Envelope-Encrypt Data with a KMS
Generate a data key per object, encrypt data with it locally, and wrap the data key with a KMS master key so rotation does not require re-encrypting everything.
Task
Encrypt stored objects with per-object data keys protected by a KMS master key.
When to use this
Encrypting everything directly with one master key makes rotation costly and puts the master key in more places than necessary.
Prerequisites
- A KMS that supports generate-data-key and decrypt
- A storage layer for ciphertext and wrapped keys
Steps
1. Ask the KMS for a data key and its wrapped form for each object.
Expected output: The plaintext data key exists only briefly in memory.
2. Encrypt the object locally with the data key and store the ciphertext plus the wrapped key.
Expected output: Only wrapped keys are persisted.
3. On read, ask the KMS to unwrap the data key and decrypt locally.
Expected output: The KMS is used for key operations, not bulk data.
4. Rotate the master key without re-encrypting data; rewrap keys on access.
aws kms generate-data-key --key-id alias/app --key-spec AES_256Expected output: Rotation is cheap and incremental.
Troubleshooting
Problem
Plaintext data key logged
Solution
Never log or persist the plaintext data key; zero it after use.
Problem
KMS throttling
Solution
Cache unwrapped keys briefly and batch; KMS calls are limited and can become a bottleneck.
Limitations
- Envelope encryption depends on KMS availability; an outage can block decryption unless keys are cached.
- It protects data at rest and wrapped keys, not the application memory where plaintext exists during processing.
Context
Encrypt stored objects with per-object data keys protected by a KMS master key. Encrypting everything directly with one master key makes rotation costly and puts the master key in more places than necessary.
Steps
- Ask the KMS for a data key and its wrapped form for each object. Expected: The plaintext data key exists only briefly in memory.
- Encrypt the object locally with the data key and store the ciphertext plus the wrapped key. Expected: Only wrapped keys are persisted.
- On read, ask the KMS to unwrap the data key and decrypt locally. Expected: The KMS is used for key operations, not bulk data.
- Rotate the master key without re-encrypting data; rewrap keys on access. Expected: Rotation is cheap and incremental.
const { Plaintext, CiphertextBlob } = await kms.generateDataKey({ KeyId, KeySpec: 'AES_256' });
const ciphertext = encrypt(Plaintext, data);
await store.put(id, { ciphertext, wrappedKey: CiphertextBlob });
Verify
- The plaintext data key exists only briefly in memory.
- Only wrapped keys are persisted.
- The KMS is used for key operations, not bulk data.
- Rotation is cheap and incremental.
Limits
- Envelope encryption depends on KMS availability; an outage can block decryption unless keys are cached.
- It protects data at rest and wrapped keys, not the application memory where plaintext exists during processing.