Cheat sheet — Data Protection & KMS¶
Companion to Module 17 — Data Protection & KMS · CC BY 4.0 — print it, pin it, share it.
Last reviewed: 2026-07
Keys — create and inspect¶
aws kms create-key --description "app data key" # returns a KeyId (a CMK)
aws kms create-alias --alias-name alias/app-data \
--target-key-id <key-id> # human-friendly handle
aws kms describe-key --key-id alias/app-data # metadata, key state, origin
aws kms list-keys # key IDs in the account
aws kms get-key-policy --key-id alias/app-data \
--policy-name default # the resource policy — READ THIS
Envelope encryption (the real workflow)¶
# 1. Ask KMS for a DATA key — get plaintext + KMS-wrapped copy in one call
aws kms generate-data-key --key-id alias/app-data --key-spec AES_256
# Response: Plaintext (base64, use locally then DISCARD) + CiphertextBlob (store this)
# 2. Encrypt your file locally with the plaintext data key (openssl/libsodium/etc.)
# then zero the plaintext key from memory. Store CiphertextBlob next to the ciphertext.
# 3. To read later: send the wrapped key back, KMS unwraps it, decrypt locally
aws kms decrypt --ciphertext-blob fileb://wrapped-data-key.bin \
--key-id alias/app-data --query Plaintext --output text | base64 -d
# Data-key-without-plaintext: for store-only paths that never decrypt in place
aws kms generate-data-key-without-plaintext --key-id alias/app-data --key-spec AES_256
Direct kms encrypt/decrypt is for small blobs only (<4 KB) — tokens, another key.
For files, always envelope: KMS wraps the data key, the data key wraps the file.
aws kms encrypt --key-id alias/app-data --plaintext fileb://secret.txt \
--query CiphertextBlob --output text | base64 -d > secret.enc # small blobs only
aws kms decrypt --ciphertext-blob fileb://secret.enc \
--query Plaintext --output text | base64 -d
Key policy — the second door¶
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "KeyAdmins-manage-not-use",
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::111122223333:role/KeyAdmin" },
"Action": ["kms:Create*","kms:Describe*","kms:Put*","kms:ScheduleKeyDeletion"],
"Resource": "*"
},
{
"Sid": "App-uses-not-manages",
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::111122223333:role/AppRole" },
"Action": ["kms:Decrypt","kms:GenerateDataKey"],
"Resource": "*"
}
]
}
Separation of duties: admins manage but can't decrypt; the app decrypts but can't destroy.
"Resource": "*" here means "this key" — a key policy only ever governs its own key.
aws kms put-key-policy --key-id alias/app-data \
--policy-name default --policy file://key-policy.json
Grants — temporary, scoped delegation¶
# Grant a principal narrow, revocable use without editing the key policy
aws kms create-grant --key-id alias/app-data \
--grantee-principal arn:aws:iam::111122223333:role/BatchJob \
--operations Decrypt GenerateDataKey
aws kms list-grants --key-id alias/app-data
aws kms revoke-grant --key-id alias/app-data --grant-id <grant-id> # the off-switch
Who can actually use the key (verify the blast radius)¶
# Simulate the effective decision (both doors: IAM + key policy)
aws iam simulate-principal-policy \
--policy-source-arn arn:aws:iam::111122223333:role/AppRole \
--action-names kms:Decrypt --resource-arns <key-arn>
Gotchas worth remembering¶
- A KMS key has two doors: the principal's IAM policy AND the key policy. For most services IAM is the whole story — KMS is the exception. By default the key policy is the root of authority, and an IAM grant only takes effect if the key policy delegates to IAM. A perfect least-privilege IAM policy still leaks the key if a permissive key policy left the second door open. Audit both, for every key.
- "Encrypted at rest" is silent against anyone you let use the key. Capital One's 100M
records were encrypted and read in plaintext — the storage layer decrypted transparently for
an authorized-but-over-broad role. The control is
kms:Decrypt, not the cipher. - Never store the plaintext data key. Use it locally to encrypt, then zero it. Persist
only the
CiphertextBlob(the KMS-wrapped copy). Storing the plaintext key defeats envelope encryption entirely. - Revoking decrypt is a stronger off-switch than deleting files. Every object and every
backup is unreadable without
kms:Decrypton that one key — butScheduleKeyDeletionhas a 7–30 day waiting period and is irreversible once it fires; a lost key = lost data. Prefer disabling or revoking grants over deletion. kms:GenerateDataKey+kms:Decrypttogether = full read/write. Handing an app both is correct for envelope encryption, but it means that role is your data's blast radius. Don't also give itkms:PutKeyPolicyorkms:CreateGrant— that lets it re-open the door itself.- Grants beat policy edits for temporary access — scoped, revocable, and they don't require touching (and risking) the key policy. But grants can be forgotten; list and prune them.
Only manage keys and policies in accounts you own or are authorized to administer.
Comments
Sign in with GitHub to comment. Choose the type: Feedback (errors or suggestions on this page) · Hints (help for fellow learners — no spoilers) · General (anything else).