Skip to content

fix(template): use bucket ARN for SSE-KMS encryption context#540

Merged
christiangda merged 1 commit into
mainfrom
fix/permissions
May 26, 2026
Merged

fix(template): use bucket ARN for SSE-KMS encryption context#540
christiangda merged 1 commit into
mainfrom
fix/permissions

Conversation

@christiangda
Copy link
Copy Markdown
Contributor

Summary

  • Fixes a runtime regression introduced by fix(template): scope Lambda role S3+KMS perms to the state object #533 (the IAM least-privilege hardening). Every sync started failing with AccessDenied … kms:Decrypt … no identity-based policy allows the kms:Decrypt action.
  • Root cause: PR fix(template): scope Lambda role S3+KMS perms to the state object #533 pinned kms:EncryptionContext:aws:s3:arn to the object ARN, but the state bucket has BucketKeyEnabled: true. With Bucket Keys enabled, S3 generates a short-lived bucket-level data key and derives per-object keys locally — the encryption context S3 forwards to KMS is the bucket ARN, never the object ARN. The condition therefore never matched, and IAM reports a condition-mismatched Allow as "not allowed".
  • Fix: both KMSGetDataPolicy and KMSDecryptPolicy now pin the bucket ARN. The role still cannot reach any other object (the S3ObjectPolicy ARN scoping handles that), and kms:ViaService still forces all KMS access through S3.
  • Also updates docs/Whats-New.md to describe the correct behavior and link to the AWS S3 Bucket Keys docs.

Observed error (before this fix)

User: arn:aws:sts::<acct>:assumed-role/serverless-idp-scim-sync-<acct>-us-east-1/idp-scim-sync
is not authorized to perform: kms:Decrypt
on resource: arn:aws:kms:us-east-1:<acct>:key/<key-id>
because no identity-based policy allows the kms:Decrypt action

Test plan

  • Redeploy the SAM stack with the patched template.yaml.
  • Trigger the Lambda manually (or wait for the scheduled rate(15 minutes) invocation) and confirm the sync completes without the kms:Decrypt AccessDenied.
  • Confirm in CloudTrail that the kms:Decrypt call from S3 carries kms:EncryptionContext:aws:s3:arn = arn:aws:s3:::<bucket> (bucket ARN, no object suffix) — i.e. the new condition matches what S3 actually sends.
  • Sanity-check that the role still cannot read any other object in the bucket (the object-scoping is enforced by S3ObjectPolicy, not the KMS condition).

Refs: #521, #533

🤖 Generated with Claude Code

PR #533 scoped kms:EncryptionContext:aws:s3:arn to the object ARN
(<bucket>/<BucketKey>). That works for plain SSE-KMS, but the state
bucket has BucketKeyEnabled: true, so S3 generates a short-lived
bucket-level data key and derives per-object keys locally — the
encryption context S3 forwards to KMS is the bucket ARN, not the
object ARN.

The condition therefore never matched at runtime and every sync
failed with:

    AccessDenied: ... is not authorized to perform: kms:Decrypt
    on resource: arn:aws:kms:...:key/... because no identity-based
    policy allows the kms:Decrypt action

(IAM reports a condition-mismatched Allow as "not allowed".)

Change both KMSGetDataPolicy and KMSDecryptPolicy to pin the bucket
ARN. The role can still only reach the single state object via the
S3ObjectPolicy ARN scoping; kms:ViaService still forces all KMS
access through S3.

Also update docs/Whats-New.md to describe the correct behavior and
link to the S3 Bucket Keys docs.

Refs: #521, #533
Ref: https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucket-key.html

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@christiangda christiangda self-assigned this May 26, 2026
@christiangda christiangda added this pull request to the merge queue May 26, 2026
Merged via the queue into main with commit 6420e21 May 26, 2026
6 checks passed
@christiangda christiangda deleted the fix/permissions branch May 26, 2026 08:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant