-
Notifications
You must be signed in to change notification settings - Fork 4.2k
feat(s3): add grantReplicationPermission
for IAM Role permissions
#34138
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(s3): add grantReplicationPermission
for IAM Role permissions
#34138
Conversation
use grantReplicationPermission method
Regarding the design of the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for your contribution! I've added a small comment.
if (props.destinations.length === 0) { | ||
throw new ValidationError('destinations must be specified', this); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please add unit test for throwing this error?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@badmintoncryer Thank you for your review, yes I have added a unit test that you noted.
Thank you @hassaku63, i checked the implementation for other grant methods in repo and we usually return the grant object back which allows user to further modify the grant if needed, i would like to follow the same pattern for this grant function as well.
also i think we can still leverage the internal
|
@shikha372 Thank you for the review. I'd like to share my thoughts in response to your feedback: (1) Whether to follow the common pattern of returning a In principle, I agree with your direction to align with the common pattern seen in other grant methods. However, the approach you suggested only reflects part of the actual permissions granted in To better reflect the full behavior of let result = iam.Grant.addToPrincipalOrResource({
grantee: identity,
actions: ['s3:GetReplicationConfiguration', 's3:ListBucket'],
resourceArns: [Lazy.string({ produce: () => this.bucketArn })],
resource: this,
});
const g2 = iam.Grant.addToPrincipalOrResource({
grantee: identity,
actions: ['s3:GetObjectVersionForReplication', 's3:GetObjectVersionAcl', 's3:GetObjectVersionTagging'],
resourceArns: [Lazy.string({ produce: () => this.arnForObjects('*') })],
resource: this,
});
result = result.combine(g2);
const destinationBuckets = props.destinations.map(destination => destination.bucket);
if (destinationBuckets.length > 0) {
const g3 = iam.Grant.addToPrincipalOrResource({
grantee: identity,
actions: ['s3:ReplicateObject', 's3:ReplicateDelete', 's3:ReplicateTags', 's3:ObjectOwnerOverrideToBucketOwner'],
resourceArns: destinationBuckets.map(bucket => Lazy.string({ produce: () => bucket.arnForObjects('*') })),
resource: this,
});
result = result.combine(g3);
}
props.destinations.forEach(destination => {
const g = destination.encryptionKey?.grantEncrypt(identity);
if (g !== undefined) {
result = result.combine(g);
}
});
// If KMS key encryption is enabled on the source bucket, configure the decrypt permissions.
const g4 = this.encryptionKey?.grantDecrypt(identity);
if (g4 !== undefined) {
result = result.combine(g4);
}
return result; (2) Using the existing private While I don't consider it strictly mandatory, I agree with the direction you suggested. I intend to update the implementation accordingly to leverage the existing private Since also includes a refactoring aspect, I think it's a good opportunity to align the implementation with the existing capabilities of the class. Also, I believe this change does not conflict with the discussion in (1). |
assumedBy: new iam.ServicePrincipal('s3.amazonaws.com'), | ||
}); | ||
|
||
(srcEncryptionKey.node.defaultChild as kms.CfnKey).overrideLogicalId('SrcEncryptionKey'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
q : why we're overriding the logical id's here ? is this only for the template match below ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if yes, then there might be a change in future that can cause logical id changes which in turn leads to resource replacements so overriding it here imo is not something i would recommend.
can we please keep them as it is, and populate the values from test logs ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@shikha372 Thanks for the suggestion — I’ll go ahead and revise the implementation in line with your recommendation.
Just to share some context, the current implementation uses overrideLogicalId()
intentionally. If you're open to it, I’d appreciate your thoughts on my intent behind using overrideLogicalId()
in this context.
The reason I chose to override the logical ID was to ensure predictability and to decouple the test from internal implementation details such as CDK's logical ID generation. From my perspective, changes in how logical IDs are assigned shouldn't affect this particular test case.
Since the focus here is on verifying that the grant for IAM Role permissions works correctly in the context of S3 replication, I considered logical ID assignments to be outside the scope of what this test is meant to validate. In that sense, I was concerned that allowing logical ID changes to affect this test might introduce noise rather than meaningful signal.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(p.s.) I’m aware that my initial implementation follows a different approach from other unit tests in CDK, so I’m totally open to changing it.
Thank you @hassaku63 for submitting the PR, this has been reviewed by our security team and received a go ahead, just had one last comment about overriding the logical id changes, good to approve it once addressed. |
* Specify the KMS key to use for encryption if a destination bucket needs to be encrypted with a customer-managed KMS key. | ||
* Required one or more destination buckets. | ||
* | ||
* @default - empty array |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The JSDoc for destinations property says default tag - empty array, but the implementation throws an error if the array is empty. I would suggest removing the default tag since there is no default value, and clarify that at least one destination is required
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ozelalisen Thanks. The points you suggested are absolutely right. How about adopting the following policy?
/**
* The destination buckets for replication.
* Specify the KMS key to use for encryption if a destination bucket needs to be encrypted with a customer-managed KMS key.
*
* One or more destination buckets are required if replication configuration is enabled (i.e., `replicationRole` is specified).
*
* @default - empty array (valid only if the `replicationRole` property is NOT specified)
*/
readonly destinations: GrantReplicationPermissionDestinationProps[];
I aimed to clearly convey the behavior of this property by distinguishing between the default value itself and the conditions under which that default is valid or invalid.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for addressing the issue, that looks good to me!
*/ | ||
public grantReplicationPermission(identity: iam.IGrantable, props: GrantReplicationPermissionProps): iam.Grant { | ||
if (props.destinations.length === 0) { | ||
throw new ValidationError('destinations must be specified', this); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error message "destinations must be specified" could be more descriptive. Maybe something like: At least one destination bucket must be specified in the destinations array
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ozelalisen Thanks for your review. I will revise the error message as you suggested.
improve error message more clearly Co-authored-by: Shikha Aggarwal <[email protected]>
AWS CodeBuild CI Report
Powered by github-codebuild-logs, available on the AWS Serverless Application Repository |
Thank you for contributing! Your pull request will be updated from main and then merged automatically (do not update manually, and be sure to allow changes to be pushed to your fork). |
Comments on closed issues and PRs are hard for our team to see. |
Issue # (if applicable)
Closes #34119
Reason for this change
This change introduces a new method, grantReplicationPermission, to the aws-cdk-lib.aws_s3.Bucket construct. The purpose of this addition is to provide a more convenient and programmatic way for AWS CDK users to grant the necessary IAM permissions to a user-provided IAM Role that will be used for S3 bucket replication.
Description of changes
This pull request includes the following code changes:
grantReplicationPermission
to the Bucket class.renderReplicationConfiguration
method by extracting the IAM permission granting functionality into a dedicatedgrantReplicationPermission
method.Describe any new or updated permissions being added
No new IAM permissions are being added at the CDK level. The permissions granted by the
grantReplicationPermission
method are the same as those already handled internally by the existing replication configuration logic. This change simply exposes that functionality through a dedicated method.Description of how you validated changes
grantReplicationPermission
method, ensuring that the correct IAM policies are attached to the provided role. Notably, the unit tests specifically cover scenarios where an explicitreplicationRole
is provided.integ.bucket-replication-use-custom-role.ts
was refactored to use the newgrantReplicationPermission
method instead of manually attaching the required permissions to the IAM role, and its behavior was verified to remain equivalent.Checklist
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license