KMS key policies, grants and errors
How access to a KMS key is decided — the key policy is primary and must enable IAM, key administrators versus key users, grants for AWS services, cross-account use — and the KMS exceptions (DisabledException, KMSInvalidStateException, IncorrectKeyException, InvalidCiphertextException, NotFoundException, AccessDenied) with their causes across S3, Lambda, ECS, CloudFront and RDS.
markdownreferencev4ZYM8-8XFNstage: referencetrust: officialservice: kmsservice: iaminterface: anyKMS key policyenable IAM policies rootkey administratorskey userskms:Decrypt AccessDeniedkms:GenerateDataKeygrantscross-account KMSDisabledExceptionKMSInvalidStateExceptionpending deletionIncorrectKeyExceptionInvalidCiphertextExceptionencryption contextNotFoundException KMS RegionKeyUnavailableExceptionKMS lockout
A KMS key's key policy is the root of all access to it. Unlike other resource policies, it doesn't automatically trust the owning account. IAM policies only work if the key policy has the statement that gives the account's root principal access: the default "Enable IAM User Permissions" statement. Without it, IAM allows do nothing, while IAM denies still apply.
How access is decided
- The key policy is in the key's own account and Region.
- Access needs an Allow in the key policy, in an IAM policy (when the key policy delegates to IAM), or in a grant, and no explicit Deny. SCPs and VPC endpoint policies also apply (
reference/iam/policy-evaluation.md). - Cross-account: the key policy must allow the other account (or a role in it) and that account's IAM policy must allow the caller. Both are required.
- The default key policy has these statements:
- Enable IAM User Permissions:
kms:*toarn:aws:iam::<account>:root, so IAM policies take effect. - Key administrators: manage the key (policy, grants, enable and disable, schedule deletion) but can't use it to encrypt or decrypt.
- Key users:
Encrypt,Decrypt,GenerateDataKey*and similar. - Allow attachment of persistent resources: key users can create grants only for AWS services integrated with KMS. This is how EBS, RDS and others use the key on your behalf.
- Lockout: a key policy naming one user, who is then deleted, makes the key unmanageable, and only AWS Support can help. Keep the account statement.
What each service needs from the key
| Use | Caller | KMS permissions |
|---|---|---|
| S3 SSE-KMS read / write | The IAM principal reading or writing | kms:Decrypt / kms:GenerateDataKey (multipart upload needs both) (reference/s3/encryption.md) |
| CloudFront OAC serving SSE-KMS objects | cloudfront.amazonaws.com conditioned on AWS:SourceArn = the distribution | kms:Decrypt, kms:Encrypt, kms:GenerateDataKey* in the key policy |
| Lambda environment variables (customer key) | The execution role | kms:Decrypt (a disabled key fails invocations with KMSDisabledException) |
| ECS secrets from Secrets Manager or SSM with a customer key | The task execution role | kms:Decrypt |
| Auto Scaling launching encrypted EBS volumes | The Auto Scaling service-linked role | Key-policy access or a grant. Otherwise Client.InternalError: Client error on launch. |
| Cross-account anything | Caller in account B | Key policy allows B, and B's IAM policy allows the action |
Errors
| Exception | HTTP | Cause → fix | Check |
|---|---|---|---|
AccessDeniedException (message … is not authorized to perform: kms:<Action> …) | 400 | No Allow in the key policy (or IAM, when delegated), or an explicit Deny. Cross-account without both halves. A service principal missing from the key policy. Read the message's policy-type clause (reference/iam/errors.md) | aws kms get-key-policy --key-id <k> --policy-name default; the caller's identity policy; aws kms list-grants --key-id <k> |
DisabledException | 400 | The key is disabled. Enable it (aws kms enable-key --key-id <id>), or use another key | aws kms describe-key --key-id <k> --query KeyMetadata.KeyState |
KMSInvalidStateException | 400 | The key's state doesn't allow the operation, typically pending deletion. Cancel the deletion (aws kms cancel-key-deletion), then enable the key | Same call → PendingDeletion, DeletionDate |
NotFoundException | 400 | Wrong key ID, alias or ARN, often the wrong Region: keys are Regional, and the ARN includes the Region | aws kms describe-key --key-id <k> --region <r> in the Region in the ARN |
IncorrectKeyException | 400 | The key you named can't decrypt this ciphertext: it was encrypted under another key. Omit KeyId for symmetric ciphertext, or pass the right one | Decrypt without KeyId: the response's KeyId names the key that worked |
InvalidCiphertextException | 400 | Ciphertext corrupted, missing or invalid, including a different encryption context from the one used to encrypt. The context must match exactly | Log the encryption context at encrypt and decrypt: they must be equal |
InvalidKeyUsageException | 400 | The key's usage or spec doesn't fit the operation (for example, a signing key used to decrypt) | describe-key → KeyUsage, KeySpec |
InvalidGrantTokenException | 400 | A bad grant token in the request | The token's source: aws kms create-grant output |
KeyUnavailableException, DependencyTimeoutException, KMSInternalException | 500 | Transient. Retry with backoff | A retry succeeds |
Services wrap these. S3 reports KMS.DisabledException-style codes and Lambda KMSAccessDeniedException / KMSInvalidStateException (reference/s3/bucket-and-object-errors.md, reference/lambda/errors.md).
Checks
aws kms describe-key --key-id <id-or-arn> --query 'KeyMetadata.[KeyState,KeyManager,Arn]'
aws kms get-key-policy --key-id <id> --policy-name default --output text
aws kms list-grants --key-id <id>
AWS managed keys (aws/s3, aws/lambda, …) have policies you can't edit. SQS's key-management guide states this for AWS managed keys, and the S3 and CloudFront sources are consistent with it. Anything that needs a custom grant, such as a cross-account principal or CloudFront, requires a customer managed key.