gcp-kms-cross-project-enter

Decrypting another project's key that unlocks a materialized credential privileged in that project enters it.

derived gcp emits CanEnterProject

match

A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.

{'principal': None} CanDecrypt {'key': None} {'secret': None} CredentialsFor {'identity': None}

where

?principal.project != ?key.project ?key CMEK-encrypts ?secret (customerManagedEncryption.kmsKeyName on ?secret references ?key), so CanDecrypt(?key) unlocks ?secret's payload ?identity (the identity ?secret's payload authenticates as) is a principal in ?key.project AND is privileged there (has a role binding at project/folder/org scope covering ?key.project)

emit

source typeIdentity
target typeProject
source<principal>
target<key.project>
permissionscloudkms.cryptoKeyVersions.useToDecrypt
conditionsiam_permission resource_policy key_permission trust_relationship
state logicPOTENTIAL by default (the entry is realized only after the attacker actually decrypts ?secret and assumes ?identity). ACTIVE only when ALL structural facts hold: CanDecrypt(?key) is ACTIVE, ?key CMEK-encrypts ?secret, ?secret CredentialsFor ?identity, and ?identity is a confirmed privileged principal in ?key.project. If ?identity's privilege in ?key.project is unresolved, stay POTENTIAL. BLOCKED if useToDecrypt is denied by VPC-SC/IAM deny.

Narrative

{principal.name} (project {principal.project}) can decrypt {key.name} in project {key.project}, unlocking {secret.name} whose payload authenticates as {identity.name} - a privileged principal in {key.project} - entering {key.project}.

Raw rule rules/derived/gcp/kms.yaml

id: gcp-kms-cross-project-enter
emits: CanEnterProject
description: Decrypting another project's key that unlocks a materialized credential privileged in that
  project enters it.
match:
- - principal: null
  - CanDecrypt
  - key: null
- - secret: null
  - CredentialsFor
  - identity: null
where:
- ?principal.project != ?key.project
- ?key CMEK-encrypts ?secret (customerManagedEncryption.kmsKeyName on ?secret references ?key), so CanDecrypt(?key)
  unlocks ?secret's payload
- ?identity (the identity ?secret's payload authenticates as) is a principal in ?key.project AND is privileged
  there (has a role binding at project/folder/org scope covering ?key.project)
emit:
  source_type: Identity
  target_type: Project
  source: <principal>
  target: <key.project>
  permissions:
  - cloudkms.cryptoKeyVersions.useToDecrypt
  conditions:
  - iam_permission
  - resource_policy
  - key_permission
  - trust_relationship
  state_logic: 'POTENTIAL by default (the entry is realized only after the attacker actually decrypts
    ?secret and assumes ?identity). ACTIVE only when ALL structural facts hold: CanDecrypt(?key) is ACTIVE,
    ?key CMEK-encrypts ?secret, ?secret CredentialsFor ?identity, and ?identity is a confirmed privileged
    principal in ?key.project. If ?identity''s privilege in ?key.project is unresolved, stay POTENTIAL.
    BLOCKED if useToDecrypt is denied by VPC-SC/IAM deny.'
  confidence: min(contributing_confidences) * 0.8
  derived_from:
  - <CanDecrypt edge_id>
  - <key CMEK-encrypts ?secret>
  - <CredentialsFor edge_id>
  - <?identity privilege binding in key.project>
  false_positive_note: "A bare cross-project useToDecrypt on a CMEK key (the overwhelmingly common, legitimate\
    \ cross-project CMEK pattern \u2014 e.g. decrypting a CMEK-encrypted GCS object in another project)\
    \ is NOT project entry and MUST NOT emit this edge. Require a MATERIALIZED credential node: ?key ->\
    \ CMEK-encrypts -> ?secret -> CredentialsFor -> ?identity, with ?identity demonstrably privileged\
    \ in ?key.project. Absent any of those, do not emit. The ACTIVE branch must rest on these structural\
    \ matches, never on prose about \"material privileged there\"."
  narrative: "{principal.name} (project {principal.project}) can decrypt {key.name} in project {key.project},\
    \ unlocking {secret.name} whose payload authenticates as {identity.name} \u2014 a privileged principal\
    \ in {key.project} \u2014 entering {key.project}."
move · open · esc close