Skip to main content
emnode
Compliance Medium severity

AWS Security Hub · KMS

KMS.2: Decrypt is granted on all KMS keys

Written and reviewed by Emnode · Last reviewed

What does AWS Security Hub KMS.2 check?

KMS.2 fails when an IAM principal has an inline policy allowing kms:Decrypt or kms:ReEncryptFrom on all keys (Resource: "*") rather than on specific key ARNs. The control inspects inline policies attached to users, groups, and roles.

Why does KMS.2 matter?

Decrypt on "*" means a single compromised principal can decrypt anything in the account that any key protects. In the 2019 Capital One breach the second act was exactly this: the compromised role's broad kms:Decrypt let the attacker get AWS to decrypt 100M+ records for them. Scoping the action to the handful of keys a workload actually uses stops a stolen credential from unlocking the whole estate.

How do I fix KMS.2?

  1. Inventory inline policies and flag kms:Decrypt or kms:ReEncryptFrom paired with Resource: "*".
  2. Determine which keys each principal genuinely uses from CloudTrail.
  3. Rewrite the Resource element to list those specific key ARNs.
  4. Where an exact ARN list is impractical, scope the Resource element itself (for example a Region- and account-bound key ARN pattern like arn:aws:kms:us-east-1:111122223333:key/*) rather than relying on a Condition block, because KMS.2 only evaluates the Resource element and ignores the Condition element, so condition keys such as kms:ViaService will not clear the finding.

Remediation script · bash

# Stop the irreversible clock first: cancel any scheduled deletion, then re-enable.
for k in $(aws kms list-keys --query 'Keys[].KeyId' --output text); do
  state=$(aws kms describe-key --key-id "$k" \
    --query 'KeyMetadata.KeyState' --output text)
  if [ "$state" = "PendingDeletion" ]; then
    aws kms cancel-key-deletion --key-id "$k"
    aws kms enable-key --key-id "$k"   # cancel leaves it Disabled
    echo "$k: deletion cancelled and re-enabled"
  fi
done

# Turn rotation on for eligible customer-managed symmetric keys.
for k in $(aws kms list-keys --query 'Keys[].KeyId' --output text); do
  read -r mgr spec <<<"$(aws kms describe-key --key-id "$k" \
    --query 'KeyMetadata.[KeyManager,KeySpec]' --output text)"
  if [ "$mgr" = "CUSTOMER" ] && [ "$spec" = "SYMMETRIC_DEFAULT" ]; then
    aws kms enable-key-rotation --key-id "$k"
  fi
done

Full walkthrough (console steps, edge cases and verification) in the lesson Manage KMS encryption keys.

Is KMS.2 a false positive?

KMS.2 inspects only the Resource element and disregards the Condition block, so an inline policy that pairs kms:Decrypt on Resource "*" with a tight condition (kms:ViaService limiting use to a single service like S3 or RDS, an encryption-context constraint, or aws:PrincipalOrgID) still fails despite being effectively scoped. That construction is legitimate when the workload's key ARNs aren't fixed at authoring time, such as per-tenant keys or keys other accounts create, and a wildcard Resource behind a sharp Condition is the documented way to keep the grant least-privilege. When the conditions genuinely bound the access, record a suppression citing the condition keys instead of forcing in an ARN list, but verify the conditions actually narrow the grant first, because the control will keep flagging it regardless.

Part of the learning path Lock down access
  • KMS.1 IAM policies should not allow decrypt on all KMS keys
  • KMS.3 A KMS key is scheduled for deletion and will take data with it
  • KMS.4 KMS key rotation should be enabled
  • KMS.5 A KMS key policy allows public access