Skip to content

Commit a11d144

Browse files
christiangdaclaude
andcommitted
fix(template): use bucket ARN for SSE-KMS encryption context
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>
1 parent ae9775a commit a11d144

2 files changed

Lines changed: 4 additions & 4 deletions

File tree

docs/Whats-New.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,11 @@ Tightens the Lambda execution role in `template.yaml` so it can only touch the s
7878
Both now carry the AWS-recommended SSE-KMS scoping conditions:
7979

8080
* `kms:ViaService = s3.<region>.amazonaws.com` — the CMK can only be used through requests S3 forwards on the role's behalf, not via direct `kms:Decrypt` / `kms:Encrypt` calls.
81-
* `kms:EncryptionContext:aws:s3:arn = arn:${Partition}:s3:::<bucket>/<BucketKey>` — the KMS grant only applies when S3 passes that exact object ARN as encryption context. S3 always populates this context for SSE-KMS objects, so legitimate reads/writes of the state file continue to work; any other object path is rejected by KMS.
81+
* `kms:EncryptionContext:aws:s3:arn = arn:${Partition}:s3:::<bucket>` — the KMS grant only applies when S3 passes that exact **bucket** ARN as encryption context. The bucket ARN (not the object ARN) is the correct value here because the state bucket has `BucketKeyEnabled: true`: S3 generates a short-lived bucket-level data key once and derives per-object keys locally from it, so the encryption context S3 forwards to KMS is the bucket ARN. The role can still only reach the single state object through the `S3ObjectPolicy` ARN scoping. See [AWS docs — S3 Bucket Keys](https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucket-key.html).
8282

8383
These are belt-and-braces additions on top of the existing bucket policy, public-access block, `aws:SecureTransport` deny, and SSE-KMS-with-bucket-key configuration.
8484

85-
References: [AWS docs — kms:ViaService](https://docs.aws.amazon.com/kms/latest/developerguide/policy-conditions.html#conditions-kms-via-service), [AWS docs — SSE-KMS encryption context](https://docs.aws.amazon.com/AmazonS3/latest/userguide/specifying-kms-encryption.html).
85+
References: [AWS docs — kms:ViaService](https://docs.aws.amazon.com/kms/latest/developerguide/policy-conditions.html#conditions-kms-via-service), [AWS docs — SSE-KMS encryption context](https://docs.aws.amazon.com/AmazonS3/latest/userguide/specifying-kms-encryption.html), [AWS docs — S3 Bucket Keys](https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucket-key.html).
8686

8787
### OpenSSF Scorecard Hardening (Phase 4) — Fuzzing
8888

template.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ Resources:
371371
Condition:
372372
StringEquals:
373373
kms:ViaService: !Sub "s3.${AWS::Region}.amazonaws.com"
374-
kms:EncryptionContext:aws:s3:arn: !Sub "arn:${AWS::Partition}:s3:::${BucketNamePrefix}-${AWS::AccountId}-${AWS::Region}/${BucketKey}"
374+
kms:EncryptionContext:aws:s3:arn: !Sub "arn:${AWS::Partition}:s3:::${BucketNamePrefix}-${AWS::AccountId}-${AWS::Region}"
375375
- Sid: KMSDecryptPolicy
376376
Effect: Allow
377377
Action:
@@ -383,7 +383,7 @@ Resources:
383383
Condition:
384384
StringEquals:
385385
kms:ViaService: !Sub "s3.${AWS::Region}.amazonaws.com"
386-
kms:EncryptionContext:aws:s3:arn: !Sub "arn:${AWS::Partition}:s3:::${BucketNamePrefix}-${AWS::AccountId}-${AWS::Region}/${BucketKey}"
386+
kms:EncryptionContext:aws:s3:arn: !Sub "arn:${AWS::Partition}:s3:::${BucketNamePrefix}-${AWS::AccountId}-${AWS::Region}"
387387

388388
AWSGWSServiceAccountFileSecret:
389389
Type: AWS::SecretsManager::Secret

0 commit comments

Comments
 (0)