KMS in depth: key policies, grants, context

Amazon Web Services · Expert · 16 min

KMS sits on the hot path of every encrypted read and write, so policy mistakes or throttling become outages.

Every KMS key has exactly one key policy, and it is authoritative. The default policy contains a statement allowing the account principal (arn:aws:iam::<account>:root) kms:*, which delegates to IAM: only then do IAM policies in that account matter. Remove it and only principals named in the key policy can use the key, which can lock you out.

Cross-account use requires the key policy to allow the other account and that account's IAM policies to allow its principals. Only customer managed keys can be shared this way.

Grants are fine-grained, revocable delegations created via the API, used heavily by services (an EBS volume attached to an instance works through a grant).

Encryption context is a set of non-secret key-value pairs bound to the ciphertext as authenticated data: decryption fails unless the same context is supplied. It appears in CloudTrail and can be required in policies with kms:EncryptionContext: conditions. kms:ViaService restricts use to calls made through a particular service.

Quotas: cryptographic requests share a per-account, per-Region rate (thousands to tens of thousands per second depending on Region). High-volume S3 SSE-KMS workloads can throttle; S3 Bucket Keys derive a bucket-level key and cut KMS calls dramatically, and the Encryption SDK can cache data keys.

Multi-Region keys share key material across Regions so ciphertext can be decrypted elsewhere without a call back. Deleting a key has a 7 to 30 day waiting period; disable it first and watch CloudTrail for usage, because data encrypted under a deleted key is unrecoverable.

Example

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "EnableIAMPolicies",
      "Effect": "Allow",
      "Principal": {"AWS": "arn:aws:iam::111122223333:root"},
      "Action": "kms:*",
      "Resource": "*"
    },
    {
      "Sid": "AnalyticsAccountDecryptViaS3Only",
      "Effect": "Allow",
      "Principal": {"AWS": "arn:aws:iam::444455556666:root"},
      "Action": ["kms:Decrypt", "kms:DescribeKey"],
      "Resource": "*",
      "Condition": {
        "StringEquals": {"kms:ViaService": "s3.eu-west-1.amazonaws.com"}
      }
    }
  ]
}

Remember

  • The key policy is authoritative; IAM only counts if it delegates to the account
  • Grants give revocable, programmatic access; services rely on them
  • Encryption context must match on decrypt and is logged in CloudTrail
  • Use S3 Bucket Keys or data-key caching to stay under KMS request quotas

Watch out for

  • Editing a key policy and dropping the account-root statement, locking out every IAM admin.

Check yourself

  1. An IAM policy grants kms:Decrypt on a key, but the key policy has no account-root statement and doesn't name the role. Can the role decrypt?
  2. A data lake with SSE-KMS gets ThrottlingException from KMS during heavy reads. What helps most?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.aws.amazon.com/kms/latest/developerguide/key-policies.html

Builds on

Unlocks

Nothing builds on this yet.