gcp-kms-setiam-self-grant

cryptoKeys/keyRings.setIamPolicy lets a key manager bind itself a crypto role.

derived gcp emits CanGrantPermission

match (effective permission)

{ "any_of": [ { "action": "cloudkms.cryptoKeys.setIamPolicy", "resource_type": "google.cloud.kms.CryptoKey" }, { "action": "cloudkms.keyRings.setIamPolicy", "resource_type": "google.cloud.kms.KeyRing" } ] }

where

principal has effective cloudkms.cryptoKeys.setIamPolicy on the key OR cloudkms.keyRings.setIamPolicy on its ring (ring binding inherited by every key in the ring — wider blast radius)

emit

source typeIdentity
target typeIdentity
source<principal>
target<principal (self)>
permissionscloudkms.cryptoKeys.setIamPolicy cloudkms.keyRings.setIamPolicy
conditionsiam_permission
state logicACTIVE if setIamPolicy resolves on the key/ring; BLOCKED if an IAM deny / org policy denies it. Chains to CanDecrypt/CanSignAs via a self-bound roles/cloudkms.cryptoKeyEncrypterDecrypter / roles/cloudkms.signer.

Narrative

{principal.name} can set the IAM policy of key {key.name} (cloudkms.cryptoKeys.setIamPolicy) and grant itself decrypt/sign - breaking KMS separation of duties.

Raw rule rules/derived/gcp/kms.yaml

id: gcp-kms-setiam-self-grant
emits: CanGrantPermission
description: cryptoKeys/keyRings.setIamPolicy lets a key manager bind itself a crypto role.
match_effective_permission:
  any_of:
  - action: cloudkms.cryptoKeys.setIamPolicy
    resource_type: google.cloud.kms.CryptoKey
  - action: cloudkms.keyRings.setIamPolicy
    resource_type: google.cloud.kms.KeyRing
where:
- "principal has effective cloudkms.cryptoKeys.setIamPolicy on the key OR cloudkms.keyRings.setIamPolicy\
  \ on its ring (ring binding inherited by every key in the ring \u2014 wider blast radius)"
emit:
  source_type: Identity
  target_type: Identity
  source: <principal>
  target: <principal (self)>
  permissions:
  - cloudkms.cryptoKeys.setIamPolicy
  - cloudkms.keyRings.setIamPolicy
  conditions:
  - iam_permission
  state_logic: ACTIVE if setIamPolicy resolves on the key/ring; BLOCKED if an IAM deny / org policy denies
    it. Chains to CanDecrypt/CanSignAs via a self-bound roles/cloudkms.cryptoKeyEncrypterDecrypter / roles/cloudkms.signer.
  confidence: min(contributing_confidences) * 0.95
  derived_from:
  - <effective cloudkms.cryptoKeys.setIamPolicy OR cloudkms.keyRings.setIamPolicy grant>
  false_positive_note: 'This is the intended separation-of-duties break: roles/cloudkms.admin holds setIamPolicy
    but NOT useTo*, so a key MANAGER is one IAM write from being a key USER. Escalation is realized only
    after the self-binding is applied and the version is ENABLED (see gcp-kms-selfgrant-to-decrypt/-to-sign,
    emitted POTENTIAL). keyRings.setIamPolicy affects every key in the ring.'
  narrative: "{principal.name} can set the IAM policy of key {key.name} (cloudkms.cryptoKeys.setIamPolicy)\
    \ and grant itself decrypt/sign \u2014 breaking KMS separation of duties."
move · open · esc close