AWS KMS
At a glance — envelope encryption: a per-secret data key encrypts the content (AES-256-GCM), and an AWS KMS CMK wraps that data key. Key custody lives in KMS, with CloudTrail visibility.
Configure
| Variable | Required | Notes |
|---|---|---|
GANTRYCD_DATA_ENCRYPTION_PROVIDER | Yes | set to aws-kms-aes-256 |
GANTRYCD_DATA_ENCRYPTION_AWS_KMS_KEY_ID | Yes | CMK ARN, key id, or alias |
GANTRYCD_DATA_ENCRYPTION_AWS_KMS_REGION | No | falls back to AWS_REGION |
Credentials come from the default AWS chain. Grant the backend principal exactly
kms:GenerateDataKey (encrypt path) and kms:Decrypt (decrypt path) on the CMK —
not kms:Encrypt.
How it behaves
- Writes scheme byte
0x02; the body carries the wrapped data key plus the AES-256-GCM ciphertext. - The row identifier is bound both as the GCM additional data and as the KMS
EncryptionContextof the wrapped key, so a row swap fails at unwrap — before content auth even runs. Because the context is a readable identifier, CloudTrail stays legible.
Operational notes
- KMS cost/latency. Every encrypt and decrypt calls KMS. Read-heavy paths (secret env vars per deploy) pay per-call latency and request cost; a data-key cache is a possible future follow-up, not implemented today.
- No rotation tool yet. Changing the CMK without re-encrypting existing rows makes them undecryptable.