Encryption at Rest on AWS: KMS Keys, Key Policies, and Service Integration
Almost every encryption-at-rest control on AWS resolves to AWS KMS, so this task is really a key-management exam: who can use which key, through which policy path, and what breaks when a key is misconfigured, disabled, or deleted. This lesson covers KMS at Specialty depth — the three key ownership models and when each fits, key policies as the root of trust (including cross-account access and aws:PrincipalOrgID), grants and how services like EBS use them, envelope encryption with data keys and encryption context, rotation, multi-Region keys, and the 7–30 day deletion window. It then applies those mechanics to the services the exam draws from: S3's encryption modes and bucket keys, EBS and RDS encrypt-existing patterns, DynamoDB's key choice, and WORM immutability with Object Lock and Vault Lock. It closes with the troubleshooting checklist for KMS AccessDenied, throttling, and the disabled-key outage. In-transit controls belong to Task 5.1 and secrets custody to Task 5.3.
On this page8 sections
- Three key ownership models: owned, managed, customer managed
- Key policies: the root of trust
- Grants: how AWS services borrow your keys
- Envelope encryption, data keys, and encryption context
- Key lifecycle: rotation, multi-Region keys, and deletion
- S3 at rest: SSE-S3, SSE-KMS, bucket keys, and enforcement
- EBS, RDS, DynamoDB, and WORM immutability
- Troubleshooting: AccessDenied, throttling, and the dead-key outage
- Choose between AWS owned, AWS managed, and customer managed KMS keys based on control, auditability, and cross-account requirements
- Author key policies that grant and restrict access, including cross-account patterns and aws:PrincipalOrgID conditions
- Explain envelope encryption, the GenerateDataKey flow, encryption context, and grants at the API level
- Operate the key lifecycle: automatic rotation, multi-Region replication, and the disable-first deletion discipline
- Select and enforce the right at-rest encryption mode per service across S3, EBS, RDS, and DynamoDB
- Diagnose KMS AccessDenied, throttling, and disabled or pending-deletion key failures from symptoms
Three key ownership models: owned, managed, customer managed
Every KMS-integrated service encrypts under one of three key ownership models, and choosing between them is a control-versus-effort decision the exam tests repeatedly.
| Property | AWS owned | AWS managed (aws/service) | Customer managed |
|---|---|---|---|
| Visible in your account | No | Yes, view only | Yes, full control |
| Key policy editable | No | No | Yes |
| Cross-account use | No | No | Yes |
| Rotation | Varies, AWS decides | Automatic, yearly, fixed | Optional automatic, you control |
| Usage logged in your CloudTrail | No | Yes | Yes |
| Cost | Free | No monthly fee, API charges | Monthly fee plus API charges |
AWS owned keys live in AWS-internal accounts: you cannot see, audit, or choose them — DynamoDB's default encryption is the classic example. AWS managed keys (aliases like aws/s3) exist in your account and log to your CloudTrail, but you cannot edit their key policies, control rotation, or — critically — use them across accounts. Customer managed keys are the only model where you own the key policy, opt into rotation, create grants, schedule deletion, and authorize other accounts. The exam pattern: the moment a requirement mentions cross-account sharing, key-level audit boundaries, or the ability to revoke a service's access to data, the answer is a customer managed key.
Symmetric AES-256 keys are the default and what every service integration uses. Asymmetric RSA and ECC keys exist for sign/verify and for encrypt-outside-AWS patterns — the public key is downloadable while the private key never leaves KMS — but know them at concept level.
Key policies: the root of trust
Unlike most AWS resources, a KMS key does not implicitly trust its own account. The key policy is the root of trust: no principal — not even the account root user — can use or manage a key unless the key policy allows it, directly or by delegation.
The default key policy contains one statement: it allows the account principal (arn:aws:iam::111122223333:root) the full kms:* action set. That statement is not really about the root user — it is the delegation switch that enables IAM policies to work. With it present, an IAM identity policy in the account can grant KMS permissions on the key; without it, IAM policies are inert for that key. Delete or over-restrict that statement and you can create an unmanageable key — one no principal can administer — recoverable only by contacting AWS Support. Treat edits to it like production changes.
Access to a key therefore flows through two policy paths that combine: the key policy can authorize a principal directly, or the key policy delegates to IAM and an identity policy supplies the allow. Cross-account use requires both halves: the key policy must allow the external account (or specific principals in it), and the external account must separately grant its principals IAM permission on the key's ARN. Either half alone fails — a favorite distractor. Only customer managed keys support this; aws/service keys cannot cross accounts.
At organization scale, condition the key policy on aws:PrincipalOrgID to allow any principal from your AWS Organization without enumerating accounts — a clean pattern for shared data lakes and centralized log archives.
Grants: how AWS services borrow your keys
Grants are the third access path, alongside key policies and IAM policies: a temporary, programmatic delegation attached to a key. A grant names a grantee principal, a subset of allowed operations (decrypt, encrypt, generate data key, describe, retire, and a few others — grants can only allow, never deny), and optional constraints that pin the grant to a specific encryption context.
Grants exist mainly so AWS services can use your keys on your behalf without long-lived policy entries. The canonical example is EBS: when you attach an encrypted volume, EC2 creates a grant on the volume's KMS key so the service can decrypt the volume's data key during attachment, and retires the grant when it is no longer needed. This is why service-integration key policies commonly allow kms:CreateGrant conditioned on kms:GrantIsForAWSResource — the condition restricts grant creation to AWS services acting for you, rather than letting a human principal mint delegations.
That points at the risk the exam wants you to see: kms:CreateGrant is a delegation right. Any principal holding it can create new access to the key for another principal, sidestepping your policy review. Audit it the way you audit iam:PassRole, scope it with kms:GrantIsForAWSResource where only services need it, and review existing grants with the list-grants APIs during investigations.
Operationally, grants are eventually consistent — a freshly created grant can take a short time to become usable everywhere, which is why the API returns a grant token that can be passed to requests to bridge the gap. Concept-level knowledge of that behavior is enough for the exam.
Envelope encryption, data keys, and encryption context
KMS never bulk-encrypts your data. The direct Encrypt API caps plaintext at 4 KB — enough for another key or a small secret, not for objects. Everything larger uses envelope encryption: call GenerateDataKey and KMS returns two things — a plaintext data key and the same data key encrypted under your KMS key. You encrypt the data locally with the plaintext key, discard that plaintext key from memory, and store the encrypted data key alongside the ciphertext. To read, you send the encrypted data key to Decrypt, receive the plaintext key back, and decrypt locally. Every SSE-KMS integration — S3, EBS, RDS — runs this flow under the hood, which is why revoking access to the KMS key revokes access to all data encrypted under it: without the key, the stored data keys are unrecoverable ciphertext.
Encryption context is the second mechanism you must know cold. It is a set of non-secret key-value pairs bound to a cryptographic operation as additional authenticated data (AAD): it is not encrypted, but for symmetric keys the exact same context must be supplied to decrypt. That yields two benefits. Cryptographic binding — S3, for example, uses the object's location as context, so an encrypted data key copied next to a different object will not decrypt. And audit — the context appears in every CloudTrail record for the KMS call, telling you precisely which resource a Decrypt served. You can also enforce it: the kms:EncryptionContext: condition keys in key policies restrict a principal to operations carrying specific context values, scoping one key safely across many datasets.
Key lifecycle: rotation, multi-Region keys, and deletion
Rotation. Customer managed symmetric keys support optional automatic rotation — yearly by default — while AWS managed keys always rotate yearly and you cannot change that. Rotation swaps in new backing key material but retains all previous material so old ciphertexts still decrypt; the key ID and ARN never change, and nothing is ever re-encrypted. Rotation is therefore transparent to applications — and it does not retroactively protect data already encrypted: if key material were compromised, rotation alone does not fix the past. Keys with imported key material cannot auto-rotate at all; rotating them means creating new material or a new key and re-pointing the alias.
Multi-Region keys. KMS keys are Regional, which normally forces decrypt-and-re-encrypt when data crosses Regions. Multi-Region keys solve this: a primary key replicated into other Regions shares the same key ID and key material, so ciphertext encrypted in one Region decrypts in another without re-encryption — the pattern for cross-Region DR and globally replicated data. They are replicas, not a global key: each has its own key policy and is managed independently.
Deletion. You cannot delete a key immediately. ScheduleKeyDeletion imposes a pending window of 7 to 30 days (default 30) during which the key is unusable but recoverable via CancelKeyDeletion. Once deleted, every ciphertext under it — every object, snapshot, and data key — is permanently unrecoverable; that is what unrecoverable means here: the data, not just the key. The operational discipline is disable first: disable the key, watch CloudTrail for failing calls that reveal forgotten dependencies, and only then schedule deletion.
When regulation demands single-tenant HSMs or key material held outside AWS, know that KMS supports CloudHSM-backed custom key stores and external key stores — recognition depth only.
S3 at rest: SSE-S3, SSE-KMS, bucket keys, and enforcement
S3 encrypts every new object by default with SSE-S3: AES-256 with keys S3 manages entirely. It is free and invisible — which is exactly its limitation: no key of yours to audit, no key policy to control, no cross-account key governance, and no CloudTrail evidence of key usage per object.
SSE-KMS switches the data-key source to a KMS key — aws/s3 or, for real control, a customer managed key. Now every object's data-key operation is authorized by the key policy and logged to CloudTrail, access can be revoked centrally by disabling the key, and cross-account bucket sharing can be governed at the key. The cost is literal: each object operation calls KMS, which bills per request and consumes the KMS request quota — at high request rates, workloads start seeing throttling.
S3 Bucket Keys are the classic optimization: S3 requests a short-lived bucket-level key from KMS and derives per-object keys from it locally, cutting KMS calls and cost dramatically — the stock answer to reduce KMS request costs or throttling for S3. The visible trade-off is coarser CloudTrail granularity, since far fewer per-object KMS events are emitted.
Two more modes complete the picture at mention level: DSSE-KMS applies two independent layers of encryption for the strictest compliance regimes, and client-side encryption encrypts before upload so AWS never handles plaintext, putting key custody entirely on you.
Enforcement is two-layered: set bucket default encryption to SSE-KMS with your chosen key (and bucket keys enabled), then add a bucket policy denying s3:PutObject unless the s3:x-amz-server-side-encryption header equals aws:kms — since everything is encrypted by default now, the policy's real job is enforcing which method and key, and the companion condition s3:x-amz-server-side-encryption-aws-kms-key-id can pin the exact key.
EBS, RDS, DynamoDB, and WORM immutability
EBS. Enable the per-Region account setting encryption by default and every new volume and snapshot is encrypted without asking. Existing unencrypted volumes cannot be flipped in place: snapshot the volume, copy the snapshot with encryption enabled (choosing your key), and restore a new volume — the universal encrypt-existing pattern. Sharing is where key choice bites: snapshots encrypted with the default aws/ebs key cannot be shared with another account at all. You must copy the snapshot re-encrypting under a customer managed key, share the snapshot, and grant the target account access in the key policy so it can decrypt and copy. Encrypted snapshots can never be made public.
RDS. Storage encryption is decided at instance creation and cannot be toggled later. Encrypting an existing database uses the same move: snapshot, copy the snapshot with encryption, restore a new instance. Because KMS keys are Regional, copying an encrypted snapshot cross-Region requires specifying a key in the destination Region; and an encrypted snapshot cannot be restored as an unencrypted instance.
DynamoDB is always encrypted at rest — the design decision is only which key: the AWS owned default (free, invisible), the aws/dynamodb managed key (auditable in your CloudTrail), or a customer managed key (full policy control, revocable). You can switch between them on a live table.
Integrity and WORM. When the threat is modification or deletion — ransomware, insider tampering, regulated retention — encryption is not the control; immutability is. S3 Object Lock on a versioned bucket enforces retention in governance mode (bypassable only with s3:BypassGovernanceRetention) or compliance mode (no principal, not even root, can shorten it), plus legal holds. Glacier Vault Lock locks a vault policy immutably once committed. Pair these with versioning and cross-account backup copies via AWS Backup for ransomware resilience.
Org-wide, enforce preventively with SCPs that deny creating unencrypted resources — for example denying ec2:CreateVolume when the ec2:Encrypted condition is false — and detectively with AWS Config rules like encrypted-volumes and rds-storage-encrypted feeding remediation.
Troubleshooting: AccessDenied, throttling, and the dead-key outage
Work the scenario the exam loves: a Lambda function reads objects from an SSE-KMS bucket. It worked yesterday; today every GetObject fails with AccessDenied, even though the execution role clearly allows s3:GetObject and kms:Decrypt. Run the checklist in order.
1. Key policy before IAM. If the key lives in another account — or the key policy's delegation statement was tightened — the role's IAM allow is worthless: cross-account use needs the key policy to allow the external account and the caller's IAM policy to allow the key ARN. Check the key policy first, always.
2. Grants. Was access flowing through a grant that has been retired or revoked? List the key's grants; service-created grants disappearing explains sudden service failures.
3. Encryption context. If the key policy or IAM policy carries kms:EncryptionContext: conditions, a request whose context does not match is denied even though the action is allowed. Compare the context in the failing CloudTrail event against the condition values — CloudTrail records both the error and the context.
4. The network path. A Lambda in a VPC reaching KMS through an interface endpoint is also subject to the VPC endpoint policy; an endpoint policy that omits the key or principal denies the call regardless of every other policy. Key policies conditioned on aws:sourceVpce or kms:ViaService fail the same way when requests arrive by an unexpected route.
5. Key state. A disabled or pending-deletion key fails every operation — and cascades: EBS volumes fail to attach, SSE-KMS reads fail, RDS instances using the key become inaccessible. This is the everything-broke-at-once scenario; CloudTrail shows the failing Decrypt calls naming the key ARN. Re-enable the key or CancelKeyDeletion within the pending window — the reason the window and the disable-first discipline exist.
Separately, KMS throttling from high-volume SSE-KMS traffic is a quota problem, not a permissions problem: enable S3 Bucket Keys or request a quota increase.
Tip. Trigger phrases map straight to answers: 'reduce KMS request costs for S3' or SSE-KMS throttling means enable S3 Bucket Keys, 'key scheduled for deletion' scenarios reward disable-first discipline and CancelKeyDeletion within the 7–30 day window, and 'share an encrypted snapshot' requires a customer managed key because aws/ebs can never be shared. For any cross-account KMS question, verify both halves — key policy allowing the external account and external IAM allowing the key ARN — and for AccessDenied stems, check the key policy, grants, encryption context conditions, and any VPC endpoint policy before blaming IAM.
- Customer managed keys are the only key type with editable key policies, controllable rotation, grants, deletion, and cross-account use — AWS managed (aws/service) keys can do none of that across accounts.
- The key policy is the root of trust: the default kms:* account-root statement is what enables IAM policies to work on the key, and removing it can make the key unmanageable.
- Cross-account KMS access needs both halves — the key policy allows the external account, and the external account's IAM policies allow the key ARN; aws:PrincipalOrgID scales this to an Organization.
- Envelope encryption is the universal pattern: GenerateDataKey for anything over the 4 KB Encrypt limit, with encryption context as auditable AAD that must match exactly on decrypt.
- Rotation never re-encrypts existing data and retains old key material; imported key material cannot auto-rotate; multi-Region keys decrypt across Regions without re-encryption.
- S3 Bucket Keys are the answer to KMS request costs and throttling under SSE-KMS; a bucket policy on s3:x-amz-server-side-encryption enforces the method and key.
- Encrypt-existing means snapshot-copy for both EBS and RDS, and sharing an encrypted snapshot requires a customer managed key — the default aws/ebs key cannot be shared.
- Disable a key and watch CloudTrail before scheduling deletion: the 7–30 day pending window is recoverable, but deletion makes every ciphertext under the key permanently unrecoverable.
Frequently asked questions
What is the difference between SSE-S3 and SSE-KMS?
SSE-S3 encrypts objects with AES-256 keys that S3 manages entirely — free and automatic, but with no key you can audit, control, or revoke. SSE-KMS sources data keys from a KMS key, so every object operation is authorized by the key policy and logged in CloudTrail, access can be revoked by disabling the key, and cross-account governance becomes possible with a customer managed key. SSE-KMS adds per-request KMS charges and quota consumption, which S3 Bucket Keys largely eliminate.
What happens when a KMS key is scheduled for deletion?
The key enters a pending-deletion state for a window you choose between 7 and 30 days (default 30). During the window every cryptographic operation fails, but the deletion can be reversed with CancelKeyDeletion. After the window, the key material is destroyed and every ciphertext encrypted under the key — objects, snapshots, stored data keys — becomes permanently unrecoverable. Best practice is to disable the key first and watch CloudTrail for failing calls before scheduling deletion.
Does KMS key rotation re-encrypt my existing data?
No. Automatic rotation generates new backing key material for future encryption while retaining all previous material so existing ciphertexts still decrypt. The key ID and ARN never change, so applications notice nothing, and no stored data is ever re-encrypted. That also means rotation does not retroactively protect data encrypted before a suspected compromise — that would require re-encrypting the data under a new key yourself.
Why can't I share my encrypted EBS snapshot with another account?
Most likely the snapshot is encrypted with the default aws/ebs AWS managed key, which can never be shared cross-account. Copy the snapshot while re-encrypting it under a customer managed key, share the copy with the target account, and update the key policy to grant that account use of the key so it can decrypt and copy the snapshot. Encrypted snapshots also cannot be made public under any key.
How does cross-account access to a KMS key work?
Two grants must exist at once: the key policy in the key-owning account must allow the external account (or specific principals in it), and administrators in the external account must attach IAM policies allowing their principals to use that key's ARN. Neither side alone is sufficient. Only customer managed keys support this — AWS managed keys cannot be used cross-account — and aws:PrincipalOrgID in the key policy can authorize an entire AWS Organization cleanly.
What are S3 Bucket Keys and when should I use them?
A bucket key is a short-lived, bucket-level key that S3 obtains from KMS and then uses locally to derive per-object data keys, instead of calling KMS for every object. Enable it whenever a bucket uses SSE-KMS at meaningful request volume: it cuts KMS request costs dramatically and relieves KMS quota throttling. The trade-off is coarser CloudTrail granularity, because far fewer per-object KMS events are recorded.
Sign up free to mark lessons complete, bookmark topics and track your exam readiness.