gcp-spanner-write-data
spanner.databases.write + spanner.sessions.create together constitute effective data-plane write access: the caller can open a session and execute DML (INSERT, UPDATE, DELETE) statements to modify arbitrary rows in any table in the database.
match (effective permission)
{
"action": "spanner.databases.write",
"resource_type": "google.spanner.admin.database.v1.Database"
}
where
?principal ALSO has EFFECTIVE spanner.sessions.create on the same database or instance scope
database.state == READY
emit
| source type | Identity |
|---|---|
| target type | RelationalDatabase |
| source | <principal> |
| target | <Spanner Database node> |
| permissions | spanner.databases.write spanner.sessions.create |
| conditions | iam_permission |
| state logic | ACTIVE when both spanner.databases.write and spanner.sessions.create are confirmed ACTIVE effective permissions on the database or enclosing instance/project scope AND the database state is READY AND no VPC-SC perimeter blocks the Spanner API for the caller's network context; CONDITIONAL(iam_permission) when sessions.create is uncertain or held only at a broader scope that may be capped by an IAM deny policy; BLOCKED when a VPC-SC perimeter enforces and the caller is outside the perimeter. |
Narrative
{principal.name} holds spanner.databases.write + spanner.sessions.create on database {database.name}; it can open a Spanner session and execute DML (INSERT/UPDATE/DELETE) to modify arbitrary rows in any table in the database.
Raw rule rules/derived/gcp/spanner.yaml
id: gcp-spanner-write-data
emits: CanWriteData
description: 'spanner.databases.write + spanner.sessions.create together constitute effective data-plane
write access: the caller can open a session and execute DML (INSERT, UPDATE, DELETE) statements to modify
arbitrary rows in any table in the database.'
match_effective_permission:
action: spanner.databases.write
resource_type: google.spanner.admin.database.v1.Database
where:
- ?principal ALSO has EFFECTIVE spanner.sessions.create on the same database or instance scope
- database.state == READY
emit:
source_type: Identity
target_type: RelationalDatabase
source: <principal>
target: <Spanner Database node>
permissions:
- spanner.databases.write
- spanner.sessions.create
conditions:
- iam_permission
state_logic: ACTIVE when both spanner.databases.write and spanner.sessions.create are confirmed ACTIVE
effective permissions on the database or enclosing instance/project scope AND the database state is
READY AND no VPC-SC perimeter blocks the Spanner API for the caller's network context; CONDITIONAL(iam_permission)
when sessions.create is uncertain or held only at a broader scope that may be capped by an IAM deny
policy; BLOCKED when a VPC-SC perimeter enforces and the caller is outside the perimeter.
false_positive_note: "BOTH permissions are required: spanner.databases.write alone does not allow executing\
\ DML without a session (sessions.create), and spanner.sessions.create alone does not grant data write\
\ access. The permission evaluator must resolve BOTH at the effective (post-hierarchy) level. spanner.databases.write\
\ is present in roles/spanner.admin, roles/spanner.databaseAdmin, and roles/spanner.databaseUser (and\
\ above). It enables INSERT, UPDATE, DELETE DML operations and is not available in read-only roles\
\ like roles/spanner.databaseReader. A principal with CanWriteData can corrupt database integrity,\
\ modify sensitive application data, delete audit logs, or inject malicious data for downstream consumption\
\ \u2014 this is a high-value attack path for supply-chain or data-integrity attacks. VPC-SC perimeters\
\ that include the Spanner API block callers outside the perimeter regardless of IAM \u2014 emit BLOCKED\
\ in that case."
narrative: '{principal.name} holds spanner.databases.write + spanner.sessions.create on database {database.name};
it can open a Spanner session and execute DML (INSERT/UPDATE/DELETE) to modify arbitrary rows in any
table in the database.'
derived_from:
- spanner.databases.write effective permission on Database
- spanner.sessions.create effective permission on same scope