gcp-spanner-read-data

spanner.databases.read (or spanner.databases.select) + spanner.sessions.create together constitute effective data-plane read access: the caller can open a session and execute SQL to read arbitrary rows from any table in the database.

derived gcp emits CanReadData

match (effective permission)

{ "action": "spanner.databases.read", "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 typeIdentity
target typeRelationalDatabase
source<principal>
target<Spanner Database node>
permissionsspanner.databases.read spanner.sessions.create
conditionsiam_permission
state logicACTIVE when both spanner.databases.read (or spanner.databases.select) 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. NOTE: If a database is encrypted with Cloud KMS CMEK and the CMEK key is DISABLED or DESTROYED (not just inaccessible to the caller), the database becomes unavailable and should emit BLOCKED(key_permission) with denied_by = <KMS key resource name>. If the CMEK key is ENABLED and operational, the Spanner SERVICE AGENT (not the caller) holds the KMS decrypt rights — the caller's CanReadData is ACTIVE if their IAM permissions are satisfied. The credential-chains.yaml decrypt-gates-secret-read linchpin does NOT apply to this rule.

Narrative

{principal.name} holds spanner.databases.read + spanner.sessions.create on database {database.name}; it can open a Spanner session and execute SQL to read arbitrary rows from any table in the database.

Raw rule rules/derived/gcp/spanner.yaml

id: gcp-spanner-read-data
emits: CanReadData
description: 'spanner.databases.read (or spanner.databases.select) + spanner.sessions.create together
  constitute effective data-plane read access: the caller can open a session and execute SQL to read arbitrary
  rows from any table in the database.'
match_effective_permission:
  action: spanner.databases.read
  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.read
  - spanner.sessions.create
  conditions:
  - iam_permission
  state_logic: "ACTIVE when both spanner.databases.read (or spanner.databases.select) 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. NOTE: If a database is encrypted with Cloud KMS CMEK and the CMEK\
    \ key is DISABLED or DESTROYED (not just inaccessible to the caller), the database becomes unavailable\
    \ and should emit BLOCKED(key_permission) with denied_by = <KMS key resource name>. If the CMEK key\
    \ is ENABLED and operational, the Spanner SERVICE AGENT (not the caller) holds the KMS decrypt rights\
    \ \u2014 the caller's CanReadData is ACTIVE if their IAM permissions are satisfied. The credential-chains.yaml\
    \ decrypt-gates-secret-read linchpin does NOT apply to this rule."
  false_positive_note: "BOTH permissions are required: spanner.databases.read alone does not allow executing\
    \ queries without a session (sessions.create), and spanner.sessions.create alone does not grant data\
    \ access without read permissions. The permission evaluator must resolve BOTH at the effective (post-hierarchy)\
    \ level: a project-level binding of roles/spanner.databaseReader grants spanner.databases.select +\
    \ spanner.sessions.create (NOT spanner.databases.read). A project-level binding of roles/spanner.databaseUser\
    \ (or higher) grants spanner.databases.read + spanner.sessions.create. Do NOT conflate spanner.databases.read\
    \ (in roles/spanner.databaseUser and above) with spanner.databases.select (read-only; in roles/spanner.databaseReader).\
    \ Both grant data read; the effective evaluator should emit CanReadData for either when combined with\
    \ sessions.create. For CMEK-encrypted databases: it is the Spanner SERVICE AGENT (service-PROJECT_NUMBER@gcp-sa-spanner.iam.gserviceaccount.com)\
    \ that must hold cloudkms.cryptoKeyVersions.useToDecrypt on the CMEK key, not the caller. The caller's\
    \ IAM permissions determine their own data-plane access. If the CMEK key is disabled or destroyed,\
    \ the database becomes inaccessible \u2014 emit BLOCKED with denied_by set to the key resource. If\
    \ the CMEK key is operational, emit CanReadData as ACTIVE (the service agent's decrypt is transparent\
    \ to the caller). VPC-SC perimeters (from accesscontextmanager.yaml) 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.read + spanner.sessions.create on database {database.name};
    it can open a Spanner session and execute SQL to read arbitrary rows from any table in the database.'
  derived_from:
  - spanner.databases.read (or spanner.databases.select) effective permission on Database
  - spanner.sessions.create effective permission on same scope
move · open · esc close