1. Secrets Manager or Parameter Store?
| Item | Store |
|---|---|
| Database credentials, API keys that should rotate | Secrets Manager (managed rotation, cross-region replication) |
| Configuration values, feature flags, non-secret settings | Parameter Store (String/StringList) |
| Low-volume secrets that don't rotate automatically | Parameter Store SecureString is acceptable; Secrets Manager if you want rotation later |
| Secrets shared across accounts | Secrets Manager with resource policy + customer managed KMS key |
Pick a naming convention (/app/env/component/name) and apply it everywhere.
2. AWS managed or customer managed KMS keys?
AWS managed (aws/s3, aws/rds…) | Customer managed key (CMK) | |
|---|---|---|
| Key policy control | No | Yes |
| Cross-account use | No | Yes |
| Rotation control | Automatic, fixed | Automatic (configurable period) or manual |
| Disable/delete as a control | No | Yes (with great care) |
| Cost | No monthly key fee | Monthly fee per key + requests |
Use CMKs where you need cross-account access, separation of duties, explicit audit of key use, or a regulatory requirement. AWS managed keys are fine for many internal workloads.
3. Key structure
| Approach | Notes |
|---|---|
| Key per workload per environment per data class | Small blast radius, clear policies (common choice) |
| Key per service type per account | Fewer keys; broader access |
| One key for everything | Avoid. Any grant or policy mistake exposes everything |
Tag keys with owner, workload, data classification. Use aliases (alias/orders-prod-data) in code, never key IDs.
4. Key policies: separate admins from users
Two statements from a key policy (excerpt; keep the account root statement your organisation's standard requires):
{
"Sid": "KeyAdministrators",
"Effect": "Allow",
"Principal": {"AWS": "arn:aws:iam::123456789012:role/kms-admins"},
"Action": ["kms:Create*", "kms:Describe*", "kms:Enable*", "kms:List*", "kms:Put*", "kms:Update*",
"kms:Revoke*", "kms:Disable*", "kms:Get*", "kms:Delete*", "kms:TagResource", "kms:UntagResource",
"kms:ScheduleKeyDeletion", "kms:CancelKeyDeletion"],
"Resource": "*"
},
{
"Sid": "KeyUsers",
"Effect": "Allow",
"Principal": {"AWS": "arn:aws:iam::123456789012:role/orders-app"},
"Action": ["kms:Encrypt", "kms:Decrypt", "kms:ReEncrypt*", "kms:GenerateDataKey*", "kms:DescribeKey"],
"Resource": "*"
}
Admins manage the key but can't decrypt; apps can use it but can't change it. Use kms:ViaService conditions to restrict use to specific services where appropriate.
5. Guardrails
- SCP denying
kms:ScheduleKeyDeletionandkms:DisableKeyexcept for a break-glass role (see the KMS Sev1 post). - Deletion waiting period at the maximum (30 days) for production keys.
- CloudWatch/EventBridge alarm on
ScheduleKeyDeletion,DisableKey, key policy changes. - Config rules for unencrypted resources.
6. Rotation
- KMS automatic rotation on CMKs (period configurable). Old key material is kept, so data stays decryptable.
- Secrets Manager rotation for databases via managed rotation or Lambda; test that apps pick up new values (cache TTL).
7. Multi-region and DR
- Multi-Region KMS keys when encrypted data is replicated and must be decrypted in the DR region without re-encrypting (e.g. client-side encryption, some replication patterns).
- Secrets Manager replica secrets in the DR region.
- Check each service's cross-region replication requirements for keys (S3 CRR, Aurora Global, DynamoDB global tables).
Caution
Deleting a KMS key is irreversible after the waiting period, and every piece of data encrypted under it becomes unreadable. Treat deletion like dropping a production database: approvals, checks, and an SCP in front of it.
Checklist
- Secrets vs configuration placement decided with naming convention
- AWS managed vs CMK decided per data class
- Key per workload/env/data class with tags and aliases
- Key policies separate admins and users
- SCPs and alarms protecting keys
- Rotation and multi-region needs covered