AWS Key Management Service (KMS) is a managed service for creating and controlling cryptographic keys backed by FIPS 140-2 validated hardware security modules (HSMs). KMS is the encryption substrate for nearly every AWS service — S3, EBS, RDS, Lambda, Secrets Manager, and more — and exposes a small API for envelope encryption in your own applications.
GenerateDataKey for high-throughput encryption of large records (PII, PHI) without saturating the KMS API.aws/service): Free, auto-rotated, but cannot be shared cross-account or audited per-key in the same detail as CMKs.GetObject issues a KMS Decrypt call. Use S3 Bucket Keys to reduce KMS calls by ~99%.
import boto3, base64, os
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
kms = boto3.client("kms", region_name="us-west-2")
KEY_ID = "alias/app-data"
def encrypt(plaintext: bytes, context: dict) -> dict:
# 1. Ask KMS for a fresh data key (256-bit AES)
resp = kms.generate_data_key(
KeyId=KEY_ID, KeySpec="AES_256", EncryptionContext=context
)
dek_plain, dek_encrypted = resp["Plaintext"], resp["CiphertextBlob"]
# 2. Encrypt locally with the plaintext DEK, then discard it
nonce = os.urandom(12)
ct = AESGCM(dek_plain).encrypt(nonce, plaintext, None)
del dek_plain
return {
"ciphertext": base64.b64encode(nonce + ct).decode(),
"encrypted_dek": base64.b64encode(dek_encrypted).decode(),
"context": context,
}
def decrypt(blob: dict) -> bytes:
dek = kms.decrypt(
CiphertextBlob=base64.b64decode(blob["encrypted_dek"]),
EncryptionContext=blob["context"],
)["Plaintext"]
raw = base64.b64decode(blob["ciphertext"])
return AESGCM(dek).decrypt(raw[:12], raw[12:], None)
Encrypt the payload locally with a randomly generated data encryption key (DEK), then encrypt the DEK with KMS. You store the encrypted DEK alongside the ciphertext. Benefits: KMS API limits and bandwidth don't constrain payload size; you can decrypt locally in tight loops by caching the unwrapped DEK in memory.
The key policy is mandatory and authoritative. IAM policies only grant access if the key policy delegates to IAM (typical: "Principal": {"AWS": "arn:aws:iam::ACCOUNT:root"} with "Action": "kms:*"). For cross-account access, the key policy must explicitly allow the external account, and the consumer's IAM policy must also allow the operation.
A non-secret key/value map bound cryptographically to the ciphertext. KMS will refuse to decrypt unless the same context is supplied. Acts as authenticated additional data (AAD) and shows up in CloudTrail — useful for audit and to prevent confused-deputy attacks.
A bucket-level data key cached at the S3 service that decrypts most objects without per-object KMS calls. Reduces KMS request charges by ~99% on hot buckets. Always enable for new SSE-KMS buckets unless you need per-object key auditing.
KMS enforces a 7-30 day pending deletion window because deleting a key permanently destroys all data encrypted with it. The waiting period gives you time to discover and re-encrypt or roll back. You can disable a key instantly to test impact before scheduling deletion.
When the same ciphertext must be decrypted in multiple regions for DR or low-latency reads (e.g., DynamoDB Global Tables, S3 Cross-Region Replication of encrypted objects). Multi-Region keys share material across replicas so ciphertext is portable; otherwise you'd need to decrypt-and-re-encrypt at the boundary.
KMS is the trust anchor for AWS encryption — get the key policies and rotation strategy right, and almost every other security control benefits. Default to customer-managed keys for anything regulated, enable bucket keys to control cost, and treat the key policy as the most important access control document in the account.