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

Created 18 Oct 2026 · Modified 23 Oct 2026 · 4 versions

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:* to arn: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

UseCallerKMS permissions
S3 SSE-KMS read / writeThe IAM principal reading or writingkms:Decrypt / kms:GenerateDataKey (multipart upload needs both) (reference/s3/encryption.md)
CloudFront OAC serving SSE-KMS objectscloudfront.amazonaws.com conditioned on AWS:SourceArn = the distributionkms:Decrypt, kms:Encrypt, kms:GenerateDataKey* in the key policy
Lambda environment variables (customer key)The execution rolekms:Decrypt (a disabled key fails invocations with KMSDisabledException)
ECS secrets from Secrets Manager or SSM with a customer keyThe task execution rolekms:Decrypt
Auto Scaling launching encrypted EBS volumesThe Auto Scaling service-linked roleKey-policy access or a grant. Otherwise Client.InternalError: Client error on launch.
Cross-account anythingCaller in account BKey policy allows B, and B's IAM policy allows the action

Errors

ExceptionHTTPCause → fixCheck
AccessDeniedException (message … is not authorized to perform: kms:<Action> …)400No 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>
DisabledException400The key is disabled. Enable it (aws kms enable-key --key-id <id>), or use another keyaws kms describe-key --key-id <k> --query KeyMetadata.KeyState
KMSInvalidStateException400The key's state doesn't allow the operation, typically pending deletion. Cancel the deletion (aws kms cancel-key-deletion), then enable the keySame call → PendingDeletion, DeletionDate
NotFoundException400Wrong key ID, alias or ARN, often the wrong Region: keys are Regional, and the ARN includes the Regionaws kms describe-key --key-id <k> --region <r> in the Region in the ARN
IncorrectKeyException400The key you named can't decrypt this ciphertext: it was encrypted under another key. Omit KeyId for symmetric ciphertext, or pass the right oneDecrypt without KeyId: the response's KeyId names the key that worked
InvalidCiphertextException400Ciphertext corrupted, missing or invalid, including a different encryption context from the one used to encrypt. The context must match exactlyLog the encryption context at encrypt and decrypt: they must be equal
InvalidKeyUsageException400The key's usage or spec doesn't fit the operation (for example, a signing key used to decrypt)describe-key → KeyUsage, KeySpec
InvalidGrantTokenException400A bad grant token in the requestThe token's source: aws kms create-grant output
KeyUnavailableException, DependencyTimeoutException, KMSInternalException500Transient. Retry with backoffA 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.

Read this document as markdown — the same bytes an agent receives.