Skip to content

Commit c352176

Browse files
committed
feat(aws-s3-deployment): deployment permission update
1 parent fdb4ddb commit c352176

File tree

2 files changed

+52
-2
lines changed

2 files changed

+52
-2
lines changed

packages/aws-cdk-lib/aws-s3-deployment/lib/bucket-deployment.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -400,9 +400,13 @@ export class BucketDeployment extends Construct {
400400

401401
this.sources = props.sources.map((source: ISource) => source.bind(this, { handlerRole: this.handlerRole }));
402402

403-
this.destinationBucket.grantReadWrite(handler);
403+
const objectPattern = props.destinationKeyPrefix
404+
? `${this.normalizePrefix(props.destinationKeyPrefix)}*`
405+
: '*';
406+
407+
this.destinationBucket.grantReadWrite(handler, objectPattern);
404408
if (props.accessControl) {
405-
this.destinationBucket.grantPutAcl(handler);
409+
this.destinationBucket.grantPutAcl(handler, objectPattern);
406410
}
407411
if (props.distribution) {
408412
handler.addToRolePolicy(new iam.PolicyStatement({
@@ -645,6 +649,15 @@ export class BucketDeployment extends Construct {
645649
const uuid = `BucketDeploymentEFS-VPC-${fileSystemProps.vpc.node.addr}`;
646650
return stack.node.tryFindChild(uuid) as efs.FileSystem ?? new efs.FileSystem(scope, uuid, fileSystemProps);
647651
}
652+
/**
653+
* Normalize the prefix for S3 object keys.
654+
* @param prefix prefix string
655+
* @returns normalized prefix string
656+
*/
657+
normalizePrefix(prefix?: string): string {
658+
if (!prefix) return '';
659+
return prefix.replace(/^\/+/, '').replace(/\/+$/, '') + '/';
660+
}
648661
}
649662

650663
export interface DeployTimeSubstitutedFileProps {

packages/aws-cdk-lib/aws-s3-deployment/test/bucket-deployment.test.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1765,3 +1765,40 @@ test('outputObjectKeys default value is true', () => {
17651765
OutputObjectKeys: true,
17661766
});
17671767
});
1768+
1769+
test.each([
1770+
['my-prefix', '/my-prefix/*'],
1771+
['my-prefix/', '/my-prefix/*'],
1772+
['/my-prefix', '/my-prefix/*'],
1773+
['/my-prefix/', '/my-prefix/*'],
1774+
[undefined, '/*'],
1775+
])('lambda execution role gets permissions with destinationKeyPrefix "%s"', (prefix, expectedSuffix) => {
1776+
const stack = new cdk.Stack();
1777+
const bucket = new s3.Bucket(stack, 'Dest');
1778+
new s3deploy.BucketDeployment(stack, 'Deploy', {
1779+
sources: [s3deploy.Source.asset(path.join(__dirname, 'my-website.zip'))],
1780+
destinationBucket: bucket,
1781+
destinationKeyPrefix: prefix,
1782+
});
1783+
1784+
Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', {
1785+
PolicyDocument: Match.objectLike({
1786+
Statement: Match.arrayWith([
1787+
Match.objectLike({
1788+
Resource: Match.arrayWith([
1789+
{ 'Fn::GetAtt': ['DestC383B82A', 'Arn'] },
1790+
{
1791+
'Fn::Join': [
1792+
'',
1793+
[
1794+
{ 'Fn::GetAtt': ['DestC383B82A', 'Arn'] },
1795+
expectedSuffix,
1796+
],
1797+
],
1798+
},
1799+
]),
1800+
}),
1801+
]),
1802+
}),
1803+
});
1804+
});

0 commit comments

Comments
 (0)