Why this matters
Encryption at rest is common on AWS, but the key is the control point. A role with kms:Decrypt can read the data even if every bucket policy says no. A key policy with a broad principal can do the same. Key management is therefore access management plus recovery planning.
AWS KMS keys are regional. They do not follow data across Regions unless you use multi-Region keys. Customer managed keys give you control over policy, rotation and deletion. AWS managed keys are convenient but you do not own their policy, and they can be used only in limited ways. Pick customer managed keys for data you must control.
Deletion is the other risk. Scheduling a KMS key for deletion makes data that uses it unreadable. The waiting period is a safety net, not a backup. Treat key deletion like deleting the data itself.
Before you start
Build an inventory per AWS account and Region. In the KMS console, list customer managed keys, aliases, key manager, rotation status and tags. Note which keys are pending deletion. Export the list if you need to compare accounts.
Map each data store to its key. Check S3 default encryption, EBS volumes, RDS instances and snapshots, DynamoDB tables, Secrets Manager secrets, CloudWatch Logs groups and any application data you encrypt with GenerateDataKey. Record the owner, data class and environment for each key.
Decide the boundaries before you create keys. Use separate keys for production and nonproduction, and for data with different access rules. One key per application and environment is a common start. Add tenant separation only where a customer needs its own key, because more keys mean more policy work.
Write down who administers keys and who uses them. Those are different jobs. You also need a break-glass path for recovery if an IAM role is misconfigured. Keep that path in a separate account and test it before an incident.
How to do it
Start with the key policy, because it is the root of trust. For most customer managed keys, the key policy should name a small admin role and a small user role. The account root can be included as a recovery principal, but do not give it kms:* by default. Use conditions such as kms:ViaService to limit use to S3, EBS or RDS.
Use IAM policies for day-to-day access when the caller is in the same account. Use key policies for cross-account access. Use grants for temporary access by AWS services. Keep alias names consistent, such as app-env-purpose, and tag every key with owner and data class. Then follow the steps below.
- Inventory keys and data stores. List every customer managed key by account and Region, with alias, policy, rotation status and tags. Map each S3 bucket, EBS volume, RDS instance and DynamoDB table to the key that protects it. Flag keys with no owner or no alias.
- Create keys with clear aliases. Create a customer managed key in the same Region as the data. Choose the default AWS KMS key material unless you have a specific reason to import your own. Set an alias and tags that name the application, environment and purpose.
- Write tight key policies. Name explicit IAM principals for key administration and key use. Separate the two roles, and avoid Principal wildcards. Add kms:ViaService conditions for services that support them, and require encryption context where your code sets it.
- Grant least privilege to callers. Give application roles kms:Encrypt, kms:Decrypt and kms:GenerateDataKey only on the keys they need. Do not attach kms:* to shared roles. For cross-account use, update both the key policy and the caller IAM policy.
- Turn on rotation and plan multi-Region. Enable automatic rotation for symmetric customer managed keys. It rotates the backing material each year and keeps old versions for decryption. For multi-Region keys, create replicas and set policy in each Region; imported key material does not support automatic rotation.
- Set encryption defaults. Turn on S3 default encryption with SSE-KMS, EBS encryption by default in each Region, and KMS encryption for RDS and DynamoDB at creation. Re-encrypt old objects and snapshots with a copy job when the old key is too broad. Test the restore path, not only the write path.
- Guard deletion and monitor use. Give only a small role kms:ScheduleKeyDeletion and kms:DisableKey. Disable a key before you schedule deletion, then wait through the full waiting period, which you can set from 7 to 30 days. Send CloudTrail KMS events to a locked log account and alarm on policy changes, disable and deletion.
How to check it worked
Test from the outside. Use a role that should decrypt to read one object, one database row and one secret. Use a role that should not decrypt and confirm it gets AccessDenied. Check that the deny comes from the key policy, not from a missing IAM permission that hides a wider problem.
Run AWS CLI checks. aws kms describe-key shows key state and manager. aws kms get-key-policy shows the policy. aws kms get-key-rotation-status shows rotation. aws kms list-aliases shows naming. Compare the output across accounts and Regions, because a key that looks right in one Region may be missing in another.
Use CloudTrail to confirm real use. Filter on eventSource kms.amazonaws.com and look for Decrypt, Encrypt, GenerateDataKey, PutKeyPolicy, DisableKey and ScheduleKeyDeletion. Check that the caller is the role you expect. Look for spikes or new principals.
Check the data stores, not only KMS. In S3, confirm default encryption and the key ID on new objects. In EBS, confirm new volumes are encrypted. In RDS and DynamoDB, confirm the KMS key ID. Use AWS Config rules such as encrypted-volumes and rds-storage-encrypted to catch drift.
Mistakes to avoid
One key for everything. It feels simple, but it widens the blast radius and makes policy changes risky. A single role that can decrypt that key can read every data store it protects. Split keys by environment and data class before the number of consumers grows.
Giving kms:* to administrators or applications. Key administration can change policy and schedule deletion. Key use can read data. Keep those permissions apart. Also avoid using the account root as a daily user, even if it appears in the policy for recovery.
Deleting a key to clean up. Disable first, check CloudTrail for recent use, and look for snapshots, backups and old objects that still depend on it. Rotation does not re-encrypt old data, and deleting a key does not delete the data; it makes the data unreadable.
Skipping cross-account and multi-Region checks. A replica key has its own policy in each Region, and a cross-account caller needs both the key policy and an IAM policy. Test those paths in a nonproduction account. If you want an outside review, one option is the Cloud security review at $6,500 fixed price, which checks encryption, identity and logging across up to five cloud accounts.
Frequently asked questions
What is the difference between AWS managed and customer managed keys?
AWS managed keys are created and managed by AWS for a service. You cannot change their key policy or delete them, and they are not a good fit when you need cross-account access or custom controls. Customer managed keys let you set policy, rotation and deletion, so use them for data you must control.
Does KMS key rotation re-encrypt existing data?
No. Automatic rotation creates new backing key material and keeps old versions so existing ciphertext still decrypts. The data is not rewritten. To move old data to a new key or policy, copy and re-encrypt it.
Can I recover a KMS key after scheduling deletion?
You can cancel a scheduled deletion before the waiting period ends. After the key is deleted, it cannot be recovered. Disable the key first and check CloudTrail and backups before you schedule deletion.