gcp-kms-can-decrypt
cloudkms.cryptoKeyVersions.useToDecrypt lets a principal decrypt with the key.
match (effective permission)
{
"action": "cloudkms.cryptoKeyVersions.useToDecrypt",
"resource_type": "google.cloud.kms.CryptoKey"
}
where
CryptoKey.purpose is a useToDecrypt purpose: ENCRYPT_DECRYPT, RAW_ENCRYPT_DECRYPT, or ASYMMETRIC_DECRYPT (AsymmetricDecrypt
API; the IAM permission is still useToDecrypt)
purpose is NOT a KEM key — key encapsulation uses the DISTINCT permission cloudkms.cryptoKeyVersions.useToDecapsulate, matched by gcp-kms-can-decapsulate, not this rule
at least one CryptoKeyVersion is ENABLED
action resolves at the key scope (per-key allow policy OR inherited keyRing/project/folder/org binding)
emit
| target type | EncryptionKey |
|---|---|
| source | <principal> |
| target | <CryptoKey (EncryptionKey subtype)> |
| permissions | cloudkms.cryptoKeyVersions.useToDecrypt |
| conditions | iam_permission resource_policy key_permission service_state |
| state logic | ACTIVE if useToDecrypt resolves AND >=1 version ENABLED; CONDITIONAL(service_state) if all versions DISABLED (re-enableable by a cryptoKeyVersions.update holder); BLOCKED if all versions DESTROYED, or a VPC-SC perimeter / IAM deny policy denies cloudkms.cryptoKeyVersions.useToDecrypt at the effective scope (denied_by=<perimeter/deny>). |
Narrative
{principal.name} can decrypt with key {key.name} (cloudkms.cryptoKeyVersions.useToDecrypt) - unlocking any data encrypted under this key.
Raw rule rules/derived/gcp/kms.yaml
id: gcp-kms-can-decrypt
emits: CanDecrypt
description: cloudkms.cryptoKeyVersions.useToDecrypt lets a principal decrypt with the key.
match_effective_permission:
action: cloudkms.cryptoKeyVersions.useToDecrypt
resource_type: google.cloud.kms.CryptoKey
where:
- 'CryptoKey.purpose is a useToDecrypt purpose: ENCRYPT_DECRYPT, RAW_ENCRYPT_DECRYPT, or ASYMMETRIC_DECRYPT
(AsymmetricDecrypt API; the IAM permission is still useToDecrypt)'
- "purpose is NOT a KEM key \u2014 key encapsulation uses the DISTINCT permission cloudkms.cryptoKeyVersions.useToDecapsulate,\
\ matched by gcp-kms-can-decapsulate, not this rule"
- at least one CryptoKeyVersion is ENABLED
- action resolves at the key scope (per-key allow policy OR inherited keyRing/project/folder/org binding)
emit:
target_type: EncryptionKey
source: <principal>
target: <CryptoKey (EncryptionKey subtype)>
permissions:
- cloudkms.cryptoKeyVersions.useToDecrypt
conditions:
- iam_permission
- resource_policy
- key_permission
- service_state
state_logic: ACTIVE if useToDecrypt resolves AND >=1 version ENABLED; CONDITIONAL(service_state) if
all versions DISABLED (re-enableable by a cryptoKeyVersions.update holder); BLOCKED if all versions
DESTROYED, or a VPC-SC perimeter / IAM deny policy denies cloudkms.cryptoKeyVersions.useToDecrypt
at the effective scope (denied_by=<perimeter/deny>).
confidence: min(contributing_confidences) * 0.97
derived_from:
- <effective cloudkms.cryptoKeyVersions.useToDecrypt grant>
false_positive_note: "Gate on CryptoKey.purpose \u2014 useToDecrypt is meaningless on an ASYMMETRIC_SIGN\
\ or MAC key; do not emit CanDecrypt there. roles/cloudkms.admin does NOT grant useToDecrypt (separation\
\ of duties) \u2014 admin reaches decrypt only via setIamPolicy self-grant (see gcp-kms-selfgrant-to-decrypt).\
\ IAM inheritance: a keyRing/project/folder/org binding covers ALL keys in scope; keep the target\
\ key precise. Requires >=1 ENABLED version \u2014 an all-disabled key is CONDITIONAL/BLOCKED even\
\ with the permission."
narrative: "{principal.name} can decrypt with key {key.name} (cloudkms.cryptoKeyVersions.useToDecrypt)\
\ \u2014 unlocking any data encrypted under this key."