diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-s3-deployment/test/integ.bucket-deployment.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-s3-deployment/test/integ.bucket-deployment.ts index 9f68f822097fc..a30322ba96844 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-s3-deployment/test/integ.bucket-deployment.ts +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-s3-deployment/test/integ.bucket-deployment.ts @@ -34,6 +34,23 @@ class TestBucketDeployment extends cdk.Stack { retainOnDelete: false, // default is true, which will block the integration test cleanup }); + const vpc = new ec2.Vpc(this, 'InlineVpc', { restrictDefaultSecurityGroup: false }) + const sg1 = new ec2.SecurityGroup(this, 's3deploy-sg', { + vpc, + allowAllOutbound: false, + disableInlineRules: false, + }) + sg1.addEgressRule(ec2.Peer.ipv4('10.0.0.0/8'), ec2.Port.tcp(443)) + + new s3deploy.BucketDeployment(this, 'DeployWithSecurityGroup', { + sources: [s3deploy.Source.asset(path.join(__dirname, 'my-website'))], + destinationBucket, + destinationKeyPrefix: 'data/', + vpc, + securityGroups: [sg1], + retainOnDelete: false, // default is true, which will block the integration test cleanup + }); + const bucket2 = new s3.Bucket(this, 'Destination2', { removalPolicy: cdk.RemovalPolicy.DESTROY, autoDeleteObjects: true, // needed for integration test cleanup diff --git a/packages/aws-cdk-lib/aws-s3-deployment/README.md b/packages/aws-cdk-lib/aws-s3-deployment/README.md index 7f7f841d96f2a..f015e666db4a8 100644 --- a/packages/aws-cdk-lib/aws-s3-deployment/README.md +++ b/packages/aws-cdk-lib/aws-s3-deployment/README.md @@ -374,6 +374,24 @@ resource handler. > NOTE: a new AWS Lambda handler will be created in your stack for each combination > of memory and storage size. +## Connectivity Control +To constraint the network connectivity of the underlying lambda function you can provide `vpc`, `subnets` and `securityGroup` properties + +```ts +declare const destinationBucket: s3.Bucket; +declare const vpc: ec2.Vpc; +declare const subnets: ec2.SubnetSelection +declare const securityGroups: ec2.SecurityGroup[] + +new s3deploy.BucketDeployment(this, 'DeployMeWithVpc', { + sources: [s3deploy.Source.asset(path.join(__dirname, 'content'))], + destinationBucket, + vpcSubnets, + securityGroups, + vpc, +}); +``` + ## JSON-Aware Source Processing When using `Source.jsonData` with CDK Tokens (references to construct properties), you may need to enable the escaping option. This is particularly important when the referenced properties might contain special characters that require proper JSON escaping (like double quotes, line breaks, etc.). diff --git a/packages/aws-cdk-lib/aws-s3-deployment/lib/bucket-deployment.ts b/packages/aws-cdk-lib/aws-s3-deployment/lib/bucket-deployment.ts index dbc590a32556a..e5d49dc4c3208 100644 --- a/packages/aws-cdk-lib/aws-s3-deployment/lib/bucket-deployment.ts +++ b/packages/aws-cdk-lib/aws-s3-deployment/lib/bucket-deployment.ts @@ -277,6 +277,13 @@ export interface BucketDeploymentProps { */ readonly vpcSubnets?: ec2.SubnetSelection; + /** + * Security group to use with the vpc and subnet. + * + * @default - the Vpc default strategy if not specified + */ + readonly securityGroups?: ec2.ISecurityGroup[]; + /** * If set to true, uploads will precompute the value of `x-amz-content-sha256` * and include it in the signed S3 request headers. @@ -384,6 +391,7 @@ export class BucketDeployment extends Construct { ephemeralStorageSize: props.ephemeralStorageSize, vpc: props.vpc, vpcSubnets: props.vpcSubnets, + securityGroups: props.securityGroups, filesystem: accessPoint ? lambda.FileSystem.fromEfsAccessPoint( accessPoint, mountPath, diff --git a/packages/aws-cdk-lib/aws-s3-deployment/test/bucket-deployment.test.ts b/packages/aws-cdk-lib/aws-s3-deployment/test/bucket-deployment.test.ts index a259fc0fd3b52..e25fcd5fab32a 100644 --- a/packages/aws-cdk-lib/aws-s3-deployment/test/bucket-deployment.test.ts +++ b/packages/aws-cdk-lib/aws-s3-deployment/test/bucket-deployment.test.ts @@ -1084,7 +1084,7 @@ test('deployment allows vpc to be implicitly supplied to lambda', () => { }); }); -test('deployment allows vpc and subnets to be implicitly supplied to lambda', () => { +test('deployment allows vpc, subnets and security groups to be explicitly supplied to lambda', () => { // GIVEN const stack = new cdk.Stack(); const bucket = new s3.Bucket(stack, 'Dest'); @@ -1094,6 +1094,14 @@ test('deployment allows vpc and subnets to be implicitly supplied to lambda', () availabilityZone: vpc.availabilityZones[0], cidrBlock: vpc.vpcCidrBlock, }); + const sg: ec2.SecurityGroup[] = [ + new ec2.SecurityGroup(stack, 'sg1', { + vpc, + allowAllOutbound: false, + description: 'custom security group', + securityGroupName: 'controlled egress', + }), + ]; // WHEN new s3deploy.BucketDeployment(stack, 'DeployWithVpc2', { @@ -1103,6 +1111,7 @@ test('deployment allows vpc and subnets to be implicitly supplied to lambda', () vpcSubnets: { availabilityZones: [vpc.availabilityZones[0]], }, + securityGroups: sg, }); // THEN @@ -1111,7 +1120,7 @@ test('deployment allows vpc and subnets to be implicitly supplied to lambda', () SecurityGroupIds: [ { 'Fn::GetAtt': [ - 'CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756Cc8a39596cb8641929fcf6a288bc9db5ab7b0f656adSecurityGroup11274779', + 'sg15CEFF4E3', 'GroupId', ], },