## TL;DR

The IAM principal calling decrypt is not allowed by the KMS key policy, the IAM policy, or both - KMS needs an allow in both places. The most common miss is a key policy that only names the account root or a different role. Check the key policy first, add the caller with the decrypt action, and retry. Also check grants and the via-service condition if the call comes through another AWS service.

```text
AWS KMS "AccessDeniedException" on decrypt: policy debugging
```

## Steps

1. Identify the exact caller ARN from the request context or CloudTrail for the failed call.
Expected: You know precisely which principal was denied.

2. Read the key policy and check whether that principal has an explicit allow for the decrypt action.
Expected: You can see the key policy's allow and deny statements for this caller.

3. Read the caller's identity-based IAM policies for the same action on this key.
Expected: You know whether the IAM side also allows it - both sides must.

4. Add the missing allow, then check for a via-service condition or grant constraints if the call flows through another AWS service, and retry.
Expected: The decrypt call succeeds.

## Use this when

- A decrypt call fails with AccessDeniedException.

- A new role, user, or service just started using the key.

- Cross-account or via-another-service decryption stopped working.

## Not for this skill when

- KMS keys in disabled, pending deletion, or pending import states (different error path).

- SDK misconfiguration, wrong region, or wrong key ARN typos.

- Encryption failures rather than authorization failures.

## Variant phrasings

### KMS AccessDenied on decrypt

### kms decrypt not authorized

### KMS key policy access denied

## Why it happens

KMS evaluates the key policy and the caller's IAM policy together, and both must allow the action. Key policies default to trusting only the account, so a role with a perfect IAM policy still gets denied if the key policy never names it.

## Edge cases

- Cross-account access needs an explicit allow in the key policy - the IAM policy alone never suffices.

- A kms:ViaService condition can silently block calls that do not come through the expected service.

- Grants are an alternative path; a missing or expired grant looks like a policy denial.

- Explicit denies anywhere in either policy win over all allows - search for deny statements first.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_y1fNuX0-GZKnYMh19oFqZg
