gcp-firestore-read-data-cmek

datastore.entities.get on a CMEK Firestore database; the Firestore Service Agent (not the caller) decrypts using its KMS grant. CanReadData state is ACTIVE if the service agent's KMS grant is confirmed, CONDITIONAL(key_permission) if the grant state is unknown, and BLOCKED if the grant is denied or the key is disabled.

derived gcp emits CanReadData

match (effective permission)

{ "action": "datastore.entities.get", "resource_type": "google.firestore.Database" }

where

database IS CMEK-encrypted (cmekConfig.kmsKeyName is set)

emit

source typeIdentity
target typeData
source<principal>
target<CMEK Firestore Database / NoSQLDatabase node>
permissionsdatastore.entities.get
conditionsiam_permission resource_policy key_permission
state logicACTIVE if the Firestore Service Agent (service-PROJECT_NUMBER@gcp-sa-firestore.iam.gserviceaccount.com) holds cloudkms.cryptoKeyVersions.useToDecrypt (roles/cloudkms.cryptoKeyEncrypterDecrypter) on the cmekConfig.kmsKeyName AND the key version is ENABLED; CONDITIONAL(key_permission) if the service-agent grant or key state is unknown; BLOCKED if the service agent lacks the grant, OR the key is DISABLED/DESTROYED, OR a KMS deny policy targets the service agent's decrypt (data operations then return KMS errors).

Narrative

{principal.name} holds datastore.entities.get on CMEK database {database.name} (cmekConfig.kmsKeyName: {key.name}); the Firestore Service Agent - not the caller - decrypts documents using cloudkms.cryptoKeyEncrypterDecrypter on {key.name}. Access is ACTIVE while the service agent retains that grant and the key is enabled.

Raw rule rules/derived/gcp/firestore.yaml

id: gcp-firestore-read-data-cmek
emits: CanReadData
description: datastore.entities.get on a CMEK Firestore database; the Firestore Service Agent (not the
  caller) decrypts using its KMS grant. CanReadData state is ACTIVE if the service agent's KMS grant is
  confirmed, CONDITIONAL(key_permission) if the grant state is unknown, and BLOCKED if the grant is denied
  or the key is disabled.
match_effective_permission:
  action: datastore.entities.get
  resource_type: google.firestore.Database
where:
- database IS CMEK-encrypted (cmekConfig.kmsKeyName is set)
emit:
  source_type: Identity
  target_type: Data
  source: <principal>
  target: <CMEK Firestore Database / NoSQLDatabase node>
  permissions:
  - datastore.entities.get
  conditions:
  - iam_permission
  - resource_policy
  - key_permission
  state_logic: ACTIVE if the Firestore Service Agent (service-PROJECT_NUMBER@gcp-sa-firestore.iam.gserviceaccount.com)
    holds cloudkms.cryptoKeyVersions.useToDecrypt (roles/cloudkms.cryptoKeyEncrypterDecrypter) on the
    cmekConfig.kmsKeyName AND the key version is ENABLED; CONDITIONAL(key_permission) if the service-agent
    grant or key state is unknown; BLOCKED if the service agent lacks the grant, OR the key is DISABLED/DESTROYED,
    OR a KMS deny policy targets the service agent's decrypt (data operations then return KMS errors).
  confidence: min(contributing_confidences) * 0.93
  derived_from:
  - datastore.entities.get effective permission on CMEK Firestore Database
  - Firestore Service Agent KMS binding on cmekConfig.kmsKeyName
  false_positive_note: "GCP-SPECIFIC: the key_permission gate is on the FIRESTORE SERVICE AGENT, not the\
    \ caller. Do NOT require the accessing principal to hold cloudkms.* \u2014 a caller with only datastore.entities.get\
    \ reads CMEK documents while the service agent keeps useToDecrypt (same pattern as GCS CMEK and Secret\
    \ Manager CMEK). Requiring caller KMS decrypt (AWS-style) produces false negatives. Downgrade to CONDITIONAL/BLOCKED\
    \ based solely on the service agent's grant state and the key's enabled/disabled status. The KMS key\
    \ is specified in cmekConfig.kmsKeyName on the Database resource; verify via firestore.projects.databases.get."
  narrative: "{principal.name} holds datastore.entities.get on CMEK database {database.name} (cmekConfig.kmsKeyName:\
    \ {key.name}); the Firestore Service Agent \u2014 not the caller \u2014 decrypts documents using cloudkms.cryptoKeyEncrypterDecrypter\
    \ on {key.name}. Access is ACTIVE while the service agent retains that grant and the key is enabled."
move · open · esc close