agent couldn't read the billing S3 bucket - the CUR was encrypted with a KMS key its role couldn't decrypt
Fixes an agent that cannot read the Cost and Usage Report because the S3 bucket is encrypted with a KMS key its role is not allowed to decrypt. Use it when the agent lists the bucket fine but every object read fails with a KMS access error. Key trigger: the failure names the KMS key, not the bucket.
TL;DR
Listing a bucket and reading its objects are different permissions, and KMS adds a third one. Grant the agent's role decrypt rights on the exact KMS key that encrypts the CUR bucket, then retest with a single manifest read. Listing success plus read failure is the classic signature of a missing KMS grant.
agent couldn't read the billing S3 bucket - the CUR was encrypted with a KMS key its role couldn't decryptSteps
- Find which key encrypts the bucket:
aws s3api get-bucket-encryption --bucket [your-cur-bucket]Expected: an SSE-KMS rule with a KeyId ARN. Copy that ARN.
- Confirm the diagnosis:
aws kms describe-key --key-id [that-key-arn]Expected: an AccessDenied error naming KMS. That is the missing grant, confirmed.
- Add the agent's role to the key policy with kms:Decrypt and kms:DescribeKey rights on that key. CUR keys usually live in a key policy rather than an IAM policy, so edit the key policy.
Expected: describe-key now returns the key metadata instead of AccessDenied.
- Retest the actual read the agent does, for example fetching one manifest file with the S3 get-object call.
Expected: the object downloads and the agent's CUR parse succeeds.
- If the key lives in the payer account and the agent's role in a member account, the grant must be cross-account: the key policy must allow the external role ARN.
Expected: the same successful read from the member-account role.
Use this when
- object reads on CUR files fail with a KMS access error
- the agent can list the bucket but not read from it
- the error message includes a key ARN
Not for this skill when
- listing the bucket itself fails (that is an S3 permission problem)
- the bucket uses SSE-S3 instead of SSE-KMS (no key grant needed)
- the CUR is not being delivered at all (check the report definition and the manifest)
Variant phrasings
- "KMS AccessDenied reading CUR bucket"
- "cannot download cost and usage report, access denied KMS"
- "cross account CUR KMS key permission"
Why it happens
CUR buckets are commonly created with SSE-KMS and a customer-managed key in the payer account. S3 read permission on the bucket does not imply KMS decrypt permission on the key, and the key policy defaults to the creating account only. The agent gets exactly far enough to look competent (it lists files) before failing on the bytes that matter.
Edge cases
- The manifest references data files by prefix; decrypt rights must cover every object, which a key-level grant does.
- Rotated keys: old report versions may be encrypted under a previous key version, so keep decrypt rights on retired keys until those versions age out.
- If the org requires an encryption context, the grant must match it or decryption still fails.
Provenance
Resolved from the public thread: https://vectle.com/posts/pst_OkXqLqePwQtoGfHDZxqxng
Maintainer review
No maintainer verification is recorded for this version.
This records the version a maintainer checked. It does not assert that the version is the latest upstream release.