fix(iam): use tags for granting cross-account access of KMS & S3#38254
Open
faridnsh wants to merge 1 commit into
Open
fix(iam): use tags for granting cross-account access of KMS & S3#38254faridnsh wants to merge 1 commit into
faridnsh wants to merge 1 commit into
Conversation
aws-cdk-automation
previously requested changes
Jul 5, 2026
aws-cdk-automation
temporarily deployed
to
automation
July 5, 2026 12:07 — with
GitHub Actions
Inactive
aws-cdk-automation
temporarily deployed
to
automation
July 5, 2026 12:07 — with
GitHub Actions
Inactive
aws-cdk-automation
requested a deployment
to
test-pipeline
July 5, 2026 12:08 — with
GitHub Actions
Waiting
faridnsh
force-pushed
the
fix/kms-cross-account-grant-principal-tag
branch
from
July 6, 2026 09:17
fe17b2c to
1a166d2
Compare
aws-cdk-automation
dismissed
their stale review
July 6, 2026 09:19
✅ Updated pull request passes all PRLinter validations. Dismissing previous PRLinter review.
aws-cdk-automation
temporarily deployed
to
automation
July 6, 2026 10:09 — with
GitHub Actions
Inactive
aws-cdk-automation
temporarily deployed
to
automation
July 6, 2026 10:09 — with
GitHub Actions
Inactive
aws-cdk-automation
requested a deployment
to
test-pipeline
July 6, 2026 10:10 — with
GitHub Actions
Waiting
When a bucket or key grant targets a CDK-owned principal in another account, the resource policy referenced the role by its ARN. S3 and KMS validate that every principal in a resource policy exists at the time the policy is deployed, so unless the principal's stack happens to deploy first, the first deployment fails with "Invalid principal in policy" (S3) or "Policy contains a statement with one or more invalid principals" (KMS). The most common way to hit this is a cross-account + cross-region CodePipeline: the action role lives in a support stack with no deploy-ordering guarantee relative to the bucket/key stack, so there is no deploy order that works on the first attempt. ecr.Repository.grant() already solves this exact problem: when the grantee is a CDK-owned resource in another account and the resource's stack does not depend on the grantee's stack, tag the grantee (aws-cdk:id) and trust the grantee's account root scoped by an aws:PrincipalTag condition instead of the bare role ARN. Account-root principals and condition values are not existence-checked, so deploy order no longer matters, while the tag keeps the trust scoped to the single intended role. This change extracts the ECR implementation into a shared private helper (aws-iam/lib/private/cross-account-grants.ts) and applies it to S3 bucket grants and KMS key grants. ECR is refactored to use the helper with no behavior change. Imported principals, same-account grants, grants where the resource stack already depends on the principal stack, and the KMS trustAccountIdentities are not affected. The @aws-cdk/aws-iam:crossAccountGrantsViaPrincipalTag flag gates the S3 and KMS behavior and is off by default for existing apps. It acknowledges that tag-scoped account-root trust survives role recreation and can be spoofed in-account by principals allowed to tag roles.
faridnsh
force-pushed
the
fix/kms-cross-account-grant-principal-tag
branch
from
July 6, 2026 21:27
1a166d2 to
63c80dc
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Issues
Closes #24050
Closes #24051
I am not sure if @rix0rrr finds this fix to be good enough for those issues he created.
Reason for this change
When a bucket or key grant targets a CDK-owned principal in another account, the resource policy references the role by its ARN. S3 and KMS validate that every principal in a resource policy exists at the time the policy is deployed, so unless the principal's stack happens to deploy first, the first deployment fails with "Invalid principal in policy" (S3) or "Policy contains a statement with one or more invalid principals" (KMS). The most common way to hit this is a cross-account + cross-region CodePipeline: the action role lives in a support stack with no deploy-ordering guarantee relative to the bucket/key stack, so there is no deploy order that works on the first attempt.
ecr.Repository.grant() already solves this exact problem: when the grantee is a CDK-owned resource in another account and the resource's stack does not depend on the grantee's stack, tag the grantee (aws-cdk:id) and trust the grantee's account root scoped by an aws:PrincipalTag condition instead of the bare role ARN. Account-root principals and condition values are not existence-checked, so deploy order no longer matters, while the tag keeps the trust scoped to the single intended role.
Description of changes
This change extracts the ECR implementation into a shared private helper (aws-iam/lib/private/cross-account-grants.ts) and applies it to S3 bucket grants and KMS key grants. ECR is refactored to use the helper with no behavior change. Imported principals, same-account grants, grants where the resource stack already depends on the principal stack, and the KMS trustAccountIdentities are not affected.
The @aws-cdk/aws-iam:crossAccountGrantsViaPrincipalTag flag gates the S3 and KMS behavior and is off by default for existing apps. It acknowledges that tag-scoped account-root trust survives role recreation and can be spoofed in-account by principals allowed to tag roles.
Downsides and alternatives!
Here's some discussion points and things to consider before merging this.
aws-cdk:iddepends on the logical path of the resource. A refactor of the path results in it being different and when one stack is deployed, until the other stack is deployed the permission will not be there. For example I had implicitly given Codebuild cross stack access to an ECR repo, same account, different region via thisaws-cdk:idcondition automatically by CDK. I deployed the codebuild stack after a refactor and until the ECR stack was deployed the codebuild couldn't push. Not a big deal in my case, but some cases may not want interruptions. Another option is to use PrincipalArn as condition as mentioned in the comment in codepipeline: x-account AND x-region deployments are missing stack dependencies #24050 (comment) . If the IAM role name is not generated and doesn't depend on the path it wouldn't be affected by a refactor and no downtime. Anyway, I went withaws-cdk:idto match the ECR behaviour and be consistent. But a new better behaviour is possible with a flag.Describe any new or updated permissions being added
S3 and KMS cross-stack grants when there's no dependency with the new flag make the statement to set the root IAM account as principal and add conditions to make sure we are only giving access to the particular IAM role.
Description of how you validated changes
Unit test added, but I also tested it by deploying a cross-account CodePipeline that was failing to deploy before the fix, and now it works.
Checklist
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license