diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-s3/test/integ.bucket-auto-delete-objects.js.snapshot/cdk-s3-bucket-auto-delete-objects.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-s3/test/integ.bucket-auto-delete-objects.js.snapshot/cdk-s3-bucket-auto-delete-objects.template.json index 5f02ca9f8d4aa..90df97687afc5 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-s3/test/integ.bucket-auto-delete-objects.js.snapshot/cdk-s3-bucket-auto-delete-objects.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-s3/test/integ.bucket-auto-delete-objects.js.snapshot/cdk-s3-bucket-auto-delete-objects.template.json @@ -142,6 +142,90 @@ "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092" ] }, + "BucketViaMethodAF1D9165": { + "Type": "AWS::S3::Bucket", + "Properties": { + "Tags": [ + { + "Key": "aws-cdk:auto-delete-objects", + "Value": "true" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "BucketViaMethodPolicyDC86AE49": { + "Type": "AWS::S3::BucketPolicy", + "Properties": { + "Bucket": { + "Ref": "BucketViaMethodAF1D9165" + }, + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "s3:DeleteObject*", + "s3:GetBucket*", + "s3:List*", + "s3:PutBucketPolicy" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::GetAtt": [ + "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092", + "Arn" + ] + } + }, + "Resource": [ + { + "Fn::GetAtt": [ + "BucketViaMethodAF1D9165", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "BucketViaMethodAF1D9165", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + } + } + }, + "BucketViaMethodAutoDeleteObjectsCustomResource9AB8AF36": { + "Type": "Custom::S3AutoDeleteObjects", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "CustomS3AutoDeleteObjectsCustomResourceProviderHandler9D90184F", + "Arn" + ] + }, + "BucketName": { + "Ref": "BucketViaMethodAF1D9165" + } + }, + "DependsOn": [ + "BucketViaMethodPolicyDC86AE49" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, "CustomS3PutObjectsCustomResourceProviderRole40D98C91": { "Type": "AWS::IAM::Role", "Properties": { @@ -171,20 +255,36 @@ { "Effect": "Allow", "Action": "s3:PutObject", - "Resource": { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "Bucket83908E77", - "Arn" - ] - }, - "/*" + "Resource": [ + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "Bucket83908E77", + "Arn" + ] + }, + "/*" + ] ] - ] - } + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "BucketViaMethodAF1D9165", + "Arn" + ] + }, + "/*" + ] + ] + } + ] } ] } @@ -232,6 +332,22 @@ "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" }, + "PutObjectsMethodCustomResource": { + "Type": "Custom::S3PutObjects", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "CustomS3PutObjectsCustomResourceProviderHandler1D33F0A9", + "Arn" + ] + }, + "BucketName": { + "Ref": "BucketViaMethodAF1D9165" + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, "RemovedBucket4FCCEBAD": { "Type": "AWS::S3::Bucket", "Properties": { diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-s3/test/integ.bucket-auto-delete-objects.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-s3/test/integ.bucket-auto-delete-objects.js.snapshot/manifest.json index 2ef39d4fc5482..0c2557de1f330 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-s3/test/integ.bucket-auto-delete-objects.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-s3/test/integ.bucket-auto-delete-objects.js.snapshot/manifest.json @@ -41,6 +41,10 @@ "removalPolicy": "destroy", "autoDeleteObjects": true } + }, + { + "type": "aws:cdk:analytics:method", + "data": {} } ], "/cdk-s3-bucket-auto-delete-objects/Bucket/Resource": [ @@ -93,6 +97,50 @@ "data": "CustomS3AutoDeleteObjectsCustomResourceProviderHandler9D90184F" } ], + "/cdk-s3-bucket-auto-delete-objects/BucketViaMethod": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "removalPolicy": "destroy" + } + }, + { + "type": "aws:cdk:analytics:method", + "data": {} + } + ], + "/cdk-s3-bucket-auto-delete-objects/BucketViaMethod/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "BucketViaMethodAF1D9165" + } + ], + "/cdk-s3-bucket-auto-delete-objects/BucketViaMethod/Policy": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "bucket": "*" + } + } + ], + "/cdk-s3-bucket-auto-delete-objects/BucketViaMethod/Policy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "BucketViaMethodPolicyDC86AE49" + } + ], + "/cdk-s3-bucket-auto-delete-objects/BucketViaMethod/AutoDeleteObjectsCustomResource": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/cdk-s3-bucket-auto-delete-objects/BucketViaMethod/AutoDeleteObjectsCustomResource/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "BucketViaMethodAutoDeleteObjectsCustomResource9AB8AF36" + } + ], "/cdk-s3-bucket-auto-delete-objects/Custom::S3PutObjectsCustomResourceProvider/Role": [ { "type": "aws:cdk:logicalId", @@ -117,6 +165,18 @@ "data": "PutObjectsCustomResource" } ], + "/cdk-s3-bucket-auto-delete-objects/PutObjectsMethodCustomResource": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/cdk-s3-bucket-auto-delete-objects/PutObjectsMethodCustomResource/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "PutObjectsMethodCustomResource" + } + ], "/cdk-s3-bucket-auto-delete-objects/RemovedBucket": [ { "type": "aws:cdk:analytics:construct", @@ -124,6 +184,10 @@ "removalPolicy": "destroy", "autoDeleteObjects": true } + }, + { + "type": "aws:cdk:analytics:method", + "data": {} } ], "/cdk-s3-bucket-auto-delete-objects/RemovedBucket/Resource": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-s3/test/integ.bucket-auto-delete-objects.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-s3/test/integ.bucket-auto-delete-objects.js.snapshot/tree.json index 402a383d83655..8e27f3142fc2b 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-s3/test/integ.bucket-auto-delete-objects.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-s3/test/integ.bucket-auto-delete-objects.js.snapshot/tree.json @@ -1 +1 @@ -{"version":"tree-0.1","tree":{"id":"App","path":"","constructInfo":{"fqn":"aws-cdk-lib.App","version":"0.0.0"},"children":{"cdk-s3-bucket-auto-delete-objects":{"id":"cdk-s3-bucket-auto-delete-objects","path":"cdk-s3-bucket-auto-delete-objects","constructInfo":{"fqn":"aws-cdk-lib.Stack","version":"0.0.0"},"children":{"Bucket":{"id":"Bucket","path":"cdk-s3-bucket-auto-delete-objects/Bucket","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.Bucket","version":"0.0.0","metadata":[{"removalPolicy":"destroy","autoDeleteObjects":true}]},"children":{"Resource":{"id":"Resource","path":"cdk-s3-bucket-auto-delete-objects/Bucket/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.CfnBucket","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::S3::Bucket","aws:cdk:cloudformation:props":{"tags":[{"key":"aws-cdk:auto-delete-objects","value":"true"}]}}},"Policy":{"id":"Policy","path":"cdk-s3-bucket-auto-delete-objects/Bucket/Policy","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.BucketPolicy","version":"0.0.0","metadata":[{"bucket":"*"}]},"children":{"Resource":{"id":"Resource","path":"cdk-s3-bucket-auto-delete-objects/Bucket/Policy/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.CfnBucketPolicy","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::S3::BucketPolicy","aws:cdk:cloudformation:props":{"bucket":{"Ref":"Bucket83908E77"},"policyDocument":{"Statement":[{"Action":["s3:DeleteObject*","s3:GetBucket*","s3:List*","s3:PutBucketPolicy"],"Effect":"Allow","Principal":{"AWS":{"Fn::GetAtt":["CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092","Arn"]}},"Resource":[{"Fn::GetAtt":["Bucket83908E77","Arn"]},{"Fn::Join":["",[{"Fn::GetAtt":["Bucket83908E77","Arn"]},"/*"]]}]}],"Version":"2012-10-17"}}}}}},"AutoDeleteObjectsCustomResource":{"id":"AutoDeleteObjectsCustomResource","path":"cdk-s3-bucket-auto-delete-objects/Bucket/AutoDeleteObjectsCustomResource","constructInfo":{"fqn":"aws-cdk-lib.CustomResource","version":"0.0.0","metadata":["*"]},"children":{"Default":{"id":"Default","path":"cdk-s3-bucket-auto-delete-objects/Bucket/AutoDeleteObjectsCustomResource/Default","constructInfo":{"fqn":"aws-cdk-lib.CfnResource","version":"0.0.0"}}}}}},"Custom::S3AutoDeleteObjectsCustomResourceProvider":{"id":"Custom::S3AutoDeleteObjectsCustomResourceProvider","path":"cdk-s3-bucket-auto-delete-objects/Custom::S3AutoDeleteObjectsCustomResourceProvider","constructInfo":{"fqn":"aws-cdk-lib.CustomResourceProviderBase","version":"0.0.0"},"children":{"Staging":{"id":"Staging","path":"cdk-s3-bucket-auto-delete-objects/Custom::S3AutoDeleteObjectsCustomResourceProvider/Staging","constructInfo":{"fqn":"aws-cdk-lib.AssetStaging","version":"0.0.0"}},"Role":{"id":"Role","path":"cdk-s3-bucket-auto-delete-objects/Custom::S3AutoDeleteObjectsCustomResourceProvider/Role","constructInfo":{"fqn":"aws-cdk-lib.CfnResource","version":"0.0.0"}},"Handler":{"id":"Handler","path":"cdk-s3-bucket-auto-delete-objects/Custom::S3AutoDeleteObjectsCustomResourceProvider/Handler","constructInfo":{"fqn":"aws-cdk-lib.CfnResource","version":"0.0.0"}}}},"Custom::S3PutObjectsCustomResourceProvider":{"id":"Custom::S3PutObjectsCustomResourceProvider","path":"cdk-s3-bucket-auto-delete-objects/Custom::S3PutObjectsCustomResourceProvider","constructInfo":{"fqn":"aws-cdk-lib.CustomResourceProvider","version":"0.0.0"},"children":{"Staging":{"id":"Staging","path":"cdk-s3-bucket-auto-delete-objects/Custom::S3PutObjectsCustomResourceProvider/Staging","constructInfo":{"fqn":"aws-cdk-lib.AssetStaging","version":"0.0.0"}},"Role":{"id":"Role","path":"cdk-s3-bucket-auto-delete-objects/Custom::S3PutObjectsCustomResourceProvider/Role","constructInfo":{"fqn":"aws-cdk-lib.CfnResource","version":"0.0.0"}},"Handler":{"id":"Handler","path":"cdk-s3-bucket-auto-delete-objects/Custom::S3PutObjectsCustomResourceProvider/Handler","constructInfo":{"fqn":"aws-cdk-lib.CfnResource","version":"0.0.0"}}}},"PutObjectsCustomResource":{"id":"PutObjectsCustomResource","path":"cdk-s3-bucket-auto-delete-objects/PutObjectsCustomResource","constructInfo":{"fqn":"aws-cdk-lib.CustomResource","version":"0.0.0","metadata":["*"]},"children":{"Default":{"id":"Default","path":"cdk-s3-bucket-auto-delete-objects/PutObjectsCustomResource/Default","constructInfo":{"fqn":"aws-cdk-lib.CfnResource","version":"0.0.0"}}}},"RemovedBucket":{"id":"RemovedBucket","path":"cdk-s3-bucket-auto-delete-objects/RemovedBucket","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.Bucket","version":"0.0.0","metadata":[{"removalPolicy":"destroy","autoDeleteObjects":true}]},"children":{"Resource":{"id":"Resource","path":"cdk-s3-bucket-auto-delete-objects/RemovedBucket/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.CfnBucket","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::S3::Bucket","aws:cdk:cloudformation:props":{"tags":[{"key":"aws-cdk:auto-delete-objects","value":"true"}]}}},"Policy":{"id":"Policy","path":"cdk-s3-bucket-auto-delete-objects/RemovedBucket/Policy","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.BucketPolicy","version":"0.0.0","metadata":[{"bucket":"*"}]},"children":{"Resource":{"id":"Resource","path":"cdk-s3-bucket-auto-delete-objects/RemovedBucket/Policy/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.CfnBucketPolicy","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::S3::BucketPolicy","aws:cdk:cloudformation:props":{"bucket":{"Ref":"RemovedBucket4FCCEBAD"},"policyDocument":{"Statement":[{"Action":["s3:DeleteObject*","s3:GetBucket*","s3:List*","s3:PutBucketPolicy"],"Effect":"Allow","Principal":{"AWS":{"Fn::GetAtt":["CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092","Arn"]}},"Resource":[{"Fn::GetAtt":["RemovedBucket4FCCEBAD","Arn"]},{"Fn::Join":["",[{"Fn::GetAtt":["RemovedBucket4FCCEBAD","Arn"]},"/*"]]}]}],"Version":"2012-10-17"}}}}}},"AutoDeleteObjectsCustomResource":{"id":"AutoDeleteObjectsCustomResource","path":"cdk-s3-bucket-auto-delete-objects/RemovedBucket/AutoDeleteObjectsCustomResource","constructInfo":{"fqn":"aws-cdk-lib.CustomResource","version":"0.0.0","metadata":["*"]},"children":{"Default":{"id":"Default","path":"cdk-s3-bucket-auto-delete-objects/RemovedBucket/AutoDeleteObjectsCustomResource/Default","constructInfo":{"fqn":"aws-cdk-lib.CfnResource","version":"0.0.0"}}}}}},"DeleteBucket":{"id":"DeleteBucket","path":"cdk-s3-bucket-auto-delete-objects/DeleteBucket","constructInfo":{"fqn":"aws-cdk-lib.custom_resources.AwsCustomResource","version":"0.0.0"},"children":{"Provider":{"id":"Provider","path":"cdk-s3-bucket-auto-delete-objects/DeleteBucket/Provider","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.SingletonFunction","version":"0.0.0","metadata":[{"uuid":"*","lambdaPurpose":"*","memorySize":"*","timeout":"*","role":"*","logGroup":"*","functionName":"*","vpc":"*","vpcSubnets":"*","code":"*","handler":"*","runtime":"*"},{"addMetadata":["*",true]},{"addMetadata":["*","*"]}]}},"Resource":{"id":"Resource","path":"cdk-s3-bucket-auto-delete-objects/DeleteBucket/Resource","constructInfo":{"fqn":"aws-cdk-lib.CustomResource","version":"0.0.0","metadata":["*"]},"children":{"Default":{"id":"Default","path":"cdk-s3-bucket-auto-delete-objects/DeleteBucket/Resource/Default","constructInfo":{"fqn":"aws-cdk-lib.CfnResource","version":"0.0.0"}}}},"CustomResourcePolicy":{"id":"CustomResourcePolicy","path":"cdk-s3-bucket-auto-delete-objects/DeleteBucket/CustomResourcePolicy","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Policy","version":"0.0.0","metadata":[{"statements":"*"},{"addStatements":[{}]},{"attachToRole":["*"]},{"attachToRole":["*"]}]},"children":{"Resource":{"id":"Resource","path":"cdk-s3-bucket-auto-delete-objects/DeleteBucket/CustomResourcePolicy/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnPolicy","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Policy","aws:cdk:cloudformation:props":{"policyDocument":{"Statement":[{"Action":"s3:DeleteBucket","Effect":"Allow","Resource":{"Fn::GetAtt":["RemovedBucket4FCCEBAD","Arn"]}}],"Version":"2012-10-17"},"policyName":"DeleteBucketCustomResourcePolicy99AB6B27","roles":[{"Ref":"AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2"}]}}}}}}},"AWS679f53fac002430cb0da5b7982bd2287":{"id":"AWS679f53fac002430cb0da5b7982bd2287","path":"cdk-s3-bucket-auto-delete-objects/AWS679f53fac002430cb0da5b7982bd2287","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.Function","version":"0.0.0","metadata":[{"memorySize":"*","timeout":"*","role":"*","logGroup":"*","functionName":"*","vpc":"*","vpcSubnets":"*","code":"*","handler":"*","runtime":"*"}]},"children":{"ServiceRole":{"id":"ServiceRole","path":"cdk-s3-bucket-auto-delete-objects/AWS679f53fac002430cb0da5b7982bd2287/ServiceRole","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Role","version":"0.0.0","metadata":[{"attachInlinePolicy":["*"]}]},"children":{"ImportServiceRole":{"id":"ImportServiceRole","path":"cdk-s3-bucket-auto-delete-objects/AWS679f53fac002430cb0da5b7982bd2287/ServiceRole/ImportServiceRole","constructInfo":{"fqn":"aws-cdk-lib.Resource","version":"0.0.0","metadata":["*"]}},"Resource":{"id":"Resource","path":"cdk-s3-bucket-auto-delete-objects/AWS679f53fac002430cb0da5b7982bd2287/ServiceRole/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnRole","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"lambda.amazonaws.com"}}],"Version":"2012-10-17"},"managedPolicyArns":[{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]]}]}}}}},"Code":{"id":"Code","path":"cdk-s3-bucket-auto-delete-objects/AWS679f53fac002430cb0da5b7982bd2287/Code","constructInfo":{"fqn":"aws-cdk-lib.aws_s3_assets.Asset","version":"0.0.0"},"children":{"Stage":{"id":"Stage","path":"cdk-s3-bucket-auto-delete-objects/AWS679f53fac002430cb0da5b7982bd2287/Code/Stage","constructInfo":{"fqn":"aws-cdk-lib.AssetStaging","version":"0.0.0"}},"AssetBucket":{"id":"AssetBucket","path":"cdk-s3-bucket-auto-delete-objects/AWS679f53fac002430cb0da5b7982bd2287/Code/AssetBucket","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.BucketBase","version":"0.0.0","metadata":[]}}}},"Resource":{"id":"Resource","path":"cdk-s3-bucket-auto-delete-objects/AWS679f53fac002430cb0da5b7982bd2287/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnFunction","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Function","aws:cdk:cloudformation:props":{"code":{"s3Bucket":{"Fn::Sub":"cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}"},"s3Key":"89f8c437feaf078124252df938abc83ca969185d1730374a4ab70530e6b34616.zip"},"handler":"index.handler","role":{"Fn::GetAtt":["AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2","Arn"]},"runtime":"nodejs22.x","timeout":120}}}}},"BootstrapVersion":{"id":"BootstrapVersion","path":"cdk-s3-bucket-auto-delete-objects/BootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnParameter","version":"0.0.0"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"cdk-s3-bucket-auto-delete-objects/CheckBootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnRule","version":"0.0.0"}}}},"cdk-integ-s3-bucket-auto-delete-objects":{"id":"cdk-integ-s3-bucket-auto-delete-objects","path":"cdk-integ-s3-bucket-auto-delete-objects","constructInfo":{"fqn":"@aws-cdk/integ-tests-alpha.IntegTest","version":"0.0.0"},"children":{"DefaultTest":{"id":"DefaultTest","path":"cdk-integ-s3-bucket-auto-delete-objects/DefaultTest","constructInfo":{"fqn":"@aws-cdk/integ-tests-alpha.IntegTestCase","version":"0.0.0"},"children":{"Default":{"id":"Default","path":"cdk-integ-s3-bucket-auto-delete-objects/DefaultTest/Default","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"DeployAssert":{"id":"DeployAssert","path":"cdk-integ-s3-bucket-auto-delete-objects/DefaultTest/DeployAssert","constructInfo":{"fqn":"aws-cdk-lib.Stack","version":"0.0.0"},"children":{"BootstrapVersion":{"id":"BootstrapVersion","path":"cdk-integ-s3-bucket-auto-delete-objects/DefaultTest/DeployAssert/BootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnParameter","version":"0.0.0"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"cdk-integ-s3-bucket-auto-delete-objects/DefaultTest/DeployAssert/CheckBootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnRule","version":"0.0.0"}}}}}}}},"Tree":{"id":"Tree","path":"Tree","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}}}} \ No newline at end of file +{"version":"tree-0.1","tree":{"id":"App","path":"","constructInfo":{"fqn":"aws-cdk-lib.App","version":"0.0.0"},"children":{"cdk-s3-bucket-auto-delete-objects":{"id":"cdk-s3-bucket-auto-delete-objects","path":"cdk-s3-bucket-auto-delete-objects","constructInfo":{"fqn":"aws-cdk-lib.Stack","version":"0.0.0"},"children":{"Bucket":{"id":"Bucket","path":"cdk-s3-bucket-auto-delete-objects/Bucket","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.Bucket","version":"0.0.0","metadata":[{"removalPolicy":"destroy","autoDeleteObjects":true}]},"children":{"Resource":{"id":"Resource","path":"cdk-s3-bucket-auto-delete-objects/Bucket/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.CfnBucket","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::S3::Bucket","aws:cdk:cloudformation:props":{"tags":[{"key":"aws-cdk:auto-delete-objects","value":"true"}]}}},"Policy":{"id":"Policy","path":"cdk-s3-bucket-auto-delete-objects/Bucket/Policy","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.BucketPolicy","version":"0.0.0","metadata":[{"bucket":"*"}]},"children":{"Resource":{"id":"Resource","path":"cdk-s3-bucket-auto-delete-objects/Bucket/Policy/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.CfnBucketPolicy","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::S3::BucketPolicy","aws:cdk:cloudformation:props":{"bucket":{"Ref":"Bucket83908E77"},"policyDocument":{"Statement":[{"Action":["s3:DeleteObject*","s3:GetBucket*","s3:List*","s3:PutBucketPolicy"],"Effect":"Allow","Principal":{"AWS":{"Fn::GetAtt":["CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092","Arn"]}},"Resource":[{"Fn::GetAtt":["Bucket83908E77","Arn"]},{"Fn::Join":["",[{"Fn::GetAtt":["Bucket83908E77","Arn"]},"/*"]]}]}],"Version":"2012-10-17"}}}}}},"AutoDeleteObjectsCustomResource":{"id":"AutoDeleteObjectsCustomResource","path":"cdk-s3-bucket-auto-delete-objects/Bucket/AutoDeleteObjectsCustomResource","constructInfo":{"fqn":"aws-cdk-lib.CustomResource","version":"0.0.0","metadata":["*"]},"children":{"Default":{"id":"Default","path":"cdk-s3-bucket-auto-delete-objects/Bucket/AutoDeleteObjectsCustomResource/Default","constructInfo":{"fqn":"aws-cdk-lib.CfnResource","version":"0.0.0"}}}}}},"Custom::S3AutoDeleteObjectsCustomResourceProvider":{"id":"Custom::S3AutoDeleteObjectsCustomResourceProvider","path":"cdk-s3-bucket-auto-delete-objects/Custom::S3AutoDeleteObjectsCustomResourceProvider","constructInfo":{"fqn":"aws-cdk-lib.CustomResourceProviderBase","version":"0.0.0"},"children":{"Staging":{"id":"Staging","path":"cdk-s3-bucket-auto-delete-objects/Custom::S3AutoDeleteObjectsCustomResourceProvider/Staging","constructInfo":{"fqn":"aws-cdk-lib.AssetStaging","version":"0.0.0"}},"Role":{"id":"Role","path":"cdk-s3-bucket-auto-delete-objects/Custom::S3AutoDeleteObjectsCustomResourceProvider/Role","constructInfo":{"fqn":"aws-cdk-lib.CfnResource","version":"0.0.0"}},"Handler":{"id":"Handler","path":"cdk-s3-bucket-auto-delete-objects/Custom::S3AutoDeleteObjectsCustomResourceProvider/Handler","constructInfo":{"fqn":"aws-cdk-lib.CfnResource","version":"0.0.0"}}}},"Custom::S3PutObjectsCustomResourceProvider":{"id":"Custom::S3PutObjectsCustomResourceProvider","path":"cdk-s3-bucket-auto-delete-objects/Custom::S3PutObjectsCustomResourceProvider","constructInfo":{"fqn":"aws-cdk-lib.CustomResourceProvider","version":"0.0.0"},"children":{"Staging":{"id":"Staging","path":"cdk-s3-bucket-auto-delete-objects/Custom::S3PutObjectsCustomResourceProvider/Staging","constructInfo":{"fqn":"aws-cdk-lib.AssetStaging","version":"0.0.0"}},"Role":{"id":"Role","path":"cdk-s3-bucket-auto-delete-objects/Custom::S3PutObjectsCustomResourceProvider/Role","constructInfo":{"fqn":"aws-cdk-lib.CfnResource","version":"0.0.0"}},"Handler":{"id":"Handler","path":"cdk-s3-bucket-auto-delete-objects/Custom::S3PutObjectsCustomResourceProvider/Handler","constructInfo":{"fqn":"aws-cdk-lib.CfnResource","version":"0.0.0"}}}},"PutObjectsCustomResource":{"id":"PutObjectsCustomResource","path":"cdk-s3-bucket-auto-delete-objects/PutObjectsCustomResource","constructInfo":{"fqn":"aws-cdk-lib.CustomResource","version":"0.0.0","metadata":["*"]},"children":{"Default":{"id":"Default","path":"cdk-s3-bucket-auto-delete-objects/PutObjectsCustomResource/Default","constructInfo":{"fqn":"aws-cdk-lib.CfnResource","version":"0.0.0"}}}},"RemovedBucket":{"id":"RemovedBucket","path":"cdk-s3-bucket-auto-delete-objects/RemovedBucket","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.Bucket","version":"0.0.0","metadata":[{"removalPolicy":"destroy","autoDeleteObjects":true}]},"children":{"Resource":{"id":"Resource","path":"cdk-s3-bucket-auto-delete-objects/RemovedBucket/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.CfnBucket","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::S3::Bucket","aws:cdk:cloudformation:props":{"tags":[{"key":"aws-cdk:auto-delete-objects","value":"true"}]}}},"Policy":{"id":"Policy","path":"cdk-s3-bucket-auto-delete-objects/RemovedBucket/Policy","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.BucketPolicy","version":"0.0.0","metadata":[{"bucket":"*"}]},"children":{"Resource":{"id":"Resource","path":"cdk-s3-bucket-auto-delete-objects/RemovedBucket/Policy/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.CfnBucketPolicy","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::S3::BucketPolicy","aws:cdk:cloudformation:props":{"bucket":{"Ref":"RemovedBucket4FCCEBAD"},"policyDocument":{"Statement":[{"Action":["s3:DeleteObject*","s3:GetBucket*","s3:List*","s3:PutBucketPolicy"],"Effect":"Allow","Principal":{"AWS":{"Fn::GetAtt":["CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092","Arn"]}},"Resource":[{"Fn::GetAtt":["RemovedBucket4FCCEBAD","Arn"]},{"Fn::Join":["",[{"Fn::GetAtt":["RemovedBucket4FCCEBAD","Arn"]},"/*"]]}]}],"Version":"2012-10-17"}}}}}},"AutoDeleteObjectsCustomResource":{"id":"AutoDeleteObjectsCustomResource","path":"cdk-s3-bucket-auto-delete-objects/RemovedBucket/AutoDeleteObjectsCustomResource","constructInfo":{"fqn":"aws-cdk-lib.CustomResource","version":"0.0.0","metadata":["*"]},"children":{"Default":{"id":"Default","path":"cdk-s3-bucket-auto-delete-objects/RemovedBucket/AutoDeleteObjectsCustomResource/Default","constructInfo":{"fqn":"aws-cdk-lib.CfnResource","version":"0.0.0"}}}}}},"DeleteBucket":{"id":"DeleteBucket","path":"cdk-s3-bucket-auto-delete-objects/DeleteBucket","constructInfo":{"fqn":"aws-cdk-lib.custom_resources.AwsCustomResource","version":"0.0.0"},"children":{"Provider":{"id":"Provider","path":"cdk-s3-bucket-auto-delete-objects/DeleteBucket/Provider","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.SingletonFunction","version":"0.0.0","metadata":[{"uuid":"*","lambdaPurpose":"*","memorySize":"*","timeout":"*","role":"*","logGroup":"*","functionName":"*","vpc":"*","vpcSubnets":"*","code":"*","handler":"*","runtime":"*"},{"addMetadata":["*",true]},{"addMetadata":["*","*"]}]}},"Resource":{"id":"Resource","path":"cdk-s3-bucket-auto-delete-objects/DeleteBucket/Resource","constructInfo":{"fqn":"aws-cdk-lib.CustomResource","version":"0.0.0","metadata":["*"]},"children":{"Default":{"id":"Default","path":"cdk-s3-bucket-auto-delete-objects/DeleteBucket/Resource/Default","constructInfo":{"fqn":"aws-cdk-lib.CfnResource","version":"0.0.0"}}}},"CustomResourcePolicy":{"id":"CustomResourcePolicy","path":"cdk-s3-bucket-auto-delete-objects/DeleteBucket/CustomResourcePolicy","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Policy","version":"0.0.0","metadata":[{"statements":"*"},{"addStatements":[{}]},{"attachToRole":["*"]},{"attachToRole":["*"]}]},"children":{"Resource":{"id":"Resource","path":"cdk-s3-bucket-auto-delete-objects/DeleteBucket/CustomResourcePolicy/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnPolicy","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Policy","aws:cdk:cloudformation:props":{"policyDocument":{"Statement":[{"Action":"s3:DeleteBucket","Effect":"Allow","Resource":{"Fn::GetAtt":["RemovedBucket4FCCEBAD","Arn"]}}],"Version":"2012-10-17"},"policyName":"DeleteBucketCustomResourcePolicy99AB6B27","roles":[{"Ref":"AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2"}]}}}}}}},"AWS679f53fac002430cb0da5b7982bd2287":{"id":"AWS679f53fac002430cb0da5b7982bd2287","path":"cdk-s3-bucket-auto-delete-objects/AWS679f53fac002430cb0da5b7982bd2287","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.Function","version":"0.0.0","metadata":[{"memorySize":"*","timeout":"*","role":"*","logGroup":"*","functionName":"*","vpc":"*","vpcSubnets":"*","code":"*","handler":"*","runtime":"*"}]},"children":{"ServiceRole":{"id":"ServiceRole","path":"cdk-s3-bucket-auto-delete-objects/AWS679f53fac002430cb0da5b7982bd2287/ServiceRole","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Role","version":"0.0.0","metadata":[{"attachInlinePolicy":["*"]}]},"children":{"ImportServiceRole":{"id":"ImportServiceRole","path":"cdk-s3-bucket-auto-delete-objects/AWS679f53fac002430cb0da5b7982bd2287/ServiceRole/ImportServiceRole","constructInfo":{"fqn":"aws-cdk-lib.Resource","version":"0.0.0","metadata":["*"]}},"Resource":{"id":"Resource","path":"cdk-s3-bucket-auto-delete-objects/AWS679f53fac002430cb0da5b7982bd2287/ServiceRole/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnRole","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"lambda.amazonaws.com"}}],"Version":"2012-10-17"},"managedPolicyArns":[{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]]}]}}}}},"Code":{"id":"Code","path":"cdk-s3-bucket-auto-delete-objects/AWS679f53fac002430cb0da5b7982bd2287/Code","constructInfo":{"fqn":"aws-cdk-lib.aws_s3_assets.Asset","version":"0.0.0"},"children":{"Stage":{"id":"Stage","path":"cdk-s3-bucket-auto-delete-objects/AWS679f53fac002430cb0da5b7982bd2287/Code/Stage","constructInfo":{"fqn":"aws-cdk-lib.AssetStaging","version":"0.0.0"}},"AssetBucket":{"id":"AssetBucket","path":"cdk-s3-bucket-auto-delete-objects/AWS679f53fac002430cb0da5b7982bd2287/Code/AssetBucket","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.BucketBase","version":"0.0.0","metadata":[]}}}},"Resource":{"id":"Resource","path":"cdk-s3-bucket-auto-delete-objects/AWS679f53fac002430cb0da5b7982bd2287/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnFunction","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Function","aws:cdk:cloudformation:props":{"code":{"s3Bucket":{"Fn::Sub":"cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}"},"s3Key":"89f8c437feaf078124252df938abc83ca969185d1730374a4ab70530e6b34616.zip"},"handler":"index.handler","role":{"Fn::GetAtt":["AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2","Arn"]},"runtime":"nodejs22.x","timeout":120}}}}},"BootstrapVersion":{"id":"BootstrapVersion","path":"cdk-s3-bucket-auto-delete-objects/BootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnParameter","version":"0.0.0"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"cdk-s3-bucket-auto-delete-objects/CheckBootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnRule","version":"0.0.0"}}}},"cdk-integ-s3-bucket-auto-delete-objects":{"id":"cdk-integ-s3-bucket-auto-delete-objects","path":"cdk-integ-s3-bucket-auto-delete-objects","constructInfo":{"fqn":"@aws-cdk/integ-tests-alpha.IntegTest","version":"0.0.0"},"children":{"DefaultTest":{"id":"DefaultTest","path":"cdk-integ-s3-bucket-auto-delete-objects/DefaultTest","constructInfo":{"fqn":"@aws-cdk/integ-tests-alpha.IntegTestCase","version":"0.0.0"},"children":{"Default":{"id":"Default","path":"cdk-integ-s3-bucket-auto-delete-objects/DefaultTest/Default","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"DeployAssert":{"id":"DeployAssert","path":"cdk-integ-s3-bucket-auto-delete-objects/DefaultTest/DeployAssert","constructInfo":{"fqn":"aws-cdk-lib.Stack","version":"0.0.0"},"children":{"BootstrapVersion":{"id":"BootstrapVersion","path":"cdk-integ-s3-bucket-auto-delete-objects/DefaultTest/DeployAssert/BootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnParameter","version":"0.0.0"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"cdk-integ-s3-bucket-auto-delete-objects/DefaultTest/DeployAssert/CheckBootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnRule","version":"0.0.0"}}}}}}}},"Tree":{"id":"Tree","path":"Tree","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}}}} diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-s3/test/integ.bucket-auto-delete-objects.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-s3/test/integ.bucket-auto-delete-objects.ts index eb13e052f3d9d..ea0bbb5264957 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-s3/test/integ.bucket-auto-delete-objects.ts +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-s3/test/integ.bucket-auto-delete-objects.ts @@ -17,6 +17,13 @@ class TestStack extends Stack { autoDeleteObjects: true, }); + const bucketViaMethod = new s3.Bucket(this, 'BucketViaMethod', { + removalPolicy: RemovalPolicy.DESTROY, + }); + + // Call the public method + bucketViaMethod.enableAutoDeleteObjects(); + // Put objects in the bucket to ensure auto delete works as expected const serviceToken = CustomResourceProvider.getOrCreate(this, PUT_OBJECTS_RESOURCE_TYPE, { codeDirectory: path.join(__dirname, 'put-objects-handler'), @@ -24,9 +31,13 @@ class TestStack extends Stack { policyStatements: [{ Effect: 'Allow', Action: 's3:PutObject', - Resource: bucket.arnForObjects('*'), + Resource: [ + bucket.arnForObjects('*'), + bucketViaMethod.arnForObjects('*'), + ], }], }); + new CustomResource(this, 'PutObjectsCustomResource', { resourceType: PUT_OBJECTS_RESOURCE_TYPE, serviceToken, @@ -35,6 +46,14 @@ class TestStack extends Stack { }, }); + new CustomResource(this, 'PutObjectsMethodCustomResource', { + resourceType: PUT_OBJECTS_RESOURCE_TYPE, + serviceToken, + properties: { + BucketName: bucketViaMethod.bucketName, + }, + }); + const bucketThatWillBeRemoved = new s3.Bucket(this, 'RemovedBucket', { removalPolicy: RemovalPolicy.DESTROY, autoDeleteObjects: true, diff --git a/packages/aws-cdk-lib/aws-s3/README.md b/packages/aws-cdk-lib/aws-s3/README.md index 2a972dd099a33..f2a908814e19b 100644 --- a/packages/aws-cdk-lib/aws-s3/README.md +++ b/packages/aws-cdk-lib/aws-s3/README.md @@ -792,6 +792,16 @@ const bucket = new s3.Bucket(this, 'MyTempFileBucket', { }); ``` +Alternatively, you can enable object auto-deletion after the bucket has been created, allowing for conditional or dynamic configuration: + +```ts +const bucket = new s3.Bucket(this, 'MyTempFileBucket', { + removalPolicy: cdk.RemovalPolicy.DESTROY, +}); + +bucket.enableAutoDeleteObjects(); +``` + **Warning** if you have deployed a bucket with `autoDeleteObjects: true`, switching this to `false` in a CDK version _before_ `1.126.0` will lead to all objects in the bucket being deleted. Be sure to update your bucket resources diff --git a/packages/aws-cdk-lib/aws-s3/lib/bucket.ts b/packages/aws-cdk-lib/aws-s3/lib/bucket.ts index 3bbf227180729..edae51ee2268c 100644 --- a/packages/aws-cdk-lib/aws-s3/lib/bucket.ts +++ b/packages/aws-cdk-lib/aws-s3/lib/bucket.ts @@ -14,6 +14,7 @@ import { GrantOnKeyResult, IEncryptedResource, IGrantable } from '../../aws-iam' import * as kms from '../../aws-kms'; import { Annotations, + CfnDeletionPolicy, CustomResource, Duration, FeatureFlags, @@ -2357,10 +2358,6 @@ export class Bucket extends BucketBase { } if (props.autoDeleteObjects) { - if (props.removalPolicy !== RemovalPolicy.DESTROY) { - throw new ValidationError('Cannot use \'autoDeleteObjects\' property on a bucket without setting removal policy to \'DESTROY\'.', this); - } - this.enableAutoDeleteObjects(); } @@ -2409,6 +2406,66 @@ export class Bucket extends BucketBase { this.inventories.push(inventory); } + /** + * Enable auto-delete objects for the bucket. + */ + @MethodMetadata() + public enableAutoDeleteObjects() { + const id = 'AutoDeleteObjectsCustomResource'; + + if (this.node.tryFindChild(id)) { + return; + } + + if (this._resource.cfnOptions.deletionPolicy !== CfnDeletionPolicy.DELETE + || this._resource.cfnOptions.updateReplacePolicy !== CfnDeletionPolicy.DELETE) { + throw new ValidationError('Cannot use auto-delete objects on a bucket without setting removal policy to \'DESTROY\'.', this); + } + const provider = AutoDeleteObjectsProvider.getOrCreateProvider(this, AUTO_DELETE_OBJECTS_RESOURCE_TYPE, { + useCfnResponseWrapper: false, + description: `Lambda function for auto-deleting objects in ${this.bucketName} S3 bucket.`, + }); + + // Use a bucket policy to allow the custom resource to delete + // objects in the bucket + this.addToResourcePolicy(new iam.PolicyStatement({ + actions: [ + // prevent further PutObject calls + ...perms.BUCKET_PUT_POLICY_ACTIONS, + // list objects + ...perms.BUCKET_READ_METADATA_ACTIONS, + ...perms.BUCKET_DELETE_ACTIONS, // and then delete them + ], + resources: [ + this.bucketArn, + this.arnForObjects('*'), + ], + principals: [new iam.ArnPrincipal(provider.roleArn)], + })); + + const customResource = new CustomResource(this, id, { + resourceType: AUTO_DELETE_OBJECTS_RESOURCE_TYPE, + serviceToken: provider.serviceToken, + properties: { + BucketName: this.bucketName, + }, + }); + + // Ensure bucket policy is deleted AFTER the custom resource otherwise + // we don't have permissions to list and delete in the bucket. + // (add a `if` to make TS happy) + if (this.policy) { + customResource.node.addDependency(this.policy); + } + + // We also tag the bucket to record the fact that we want it autodeleted. + // The custom resource will check this tag before actually doing the delete. + // Because tagging and untagging will ALWAYS happen before the CR is deleted, + // we can set `autoDeleteObjects: false` without the removal of the CR emptying + // the bucket as a side effect. + Tags.of(this._resource).add(AUTO_DELETE_OBJECTS_TAG, 'true'); + } + /** * Adds an iam statement to enforce SSL requests only. */ @@ -3047,52 +3104,6 @@ export class Bucket extends BucketBase { }); } - private enableAutoDeleteObjects() { - const provider = AutoDeleteObjectsProvider.getOrCreateProvider(this, AUTO_DELETE_OBJECTS_RESOURCE_TYPE, { - useCfnResponseWrapper: false, - description: `Lambda function for auto-deleting objects in ${this.bucketName} S3 bucket.`, - }); - - // Use a bucket policy to allow the custom resource to delete - // objects in the bucket - this.addToResourcePolicy(new iam.PolicyStatement({ - actions: [ - // prevent further PutObject calls - ...perms.BUCKET_PUT_POLICY_ACTIONS, - // list objects - ...perms.BUCKET_READ_METADATA_ACTIONS, - ...perms.BUCKET_DELETE_ACTIONS, // and then delete them - ], - resources: [ - this.bucketArn, - this.arnForObjects('*'), - ], - principals: [new iam.ArnPrincipal(provider.roleArn)], - })); - - const customResource = new CustomResource(this, 'AutoDeleteObjectsCustomResource', { - resourceType: AUTO_DELETE_OBJECTS_RESOURCE_TYPE, - serviceToken: provider.serviceToken, - properties: { - BucketName: this.bucketName, - }, - }); - - // Ensure bucket policy is deleted AFTER the custom resource otherwise - // we don't have permissions to list and delete in the bucket. - // (add a `if` to make TS happy) - if (this.policy) { - customResource.node.addDependency(this.policy); - } - - // We also tag the bucket to record the fact that we want it autodeleted. - // The custom resource will check this tag before actually doing the delete. - // Because tagging and untagging will ALWAYS happen before the CR is deleted, - // we can set `autoDeleteObjects: false` without the removal of the CR emptying - // the bucket as a side effect. - Tags.of(this._resource).add(AUTO_DELETE_OBJECTS_TAG, 'true'); - } - /** * Function to set the blockPublicAccessOptions to a true default if not defined. * If no blockPublicAccessOptions are specified at all, this is already the case as an s3 default in aws diff --git a/packages/aws-cdk-lib/aws-s3/test/bucket.test.ts b/packages/aws-cdk-lib/aws-s3/test/bucket.test.ts index c4df92a826f3f..b714edab06413 100644 --- a/packages/aws-cdk-lib/aws-s3/test/bucket.test.ts +++ b/packages/aws-cdk-lib/aws-s3/test/bucket.test.ts @@ -3627,7 +3627,53 @@ describe('bucket', () => { expect(() => new s3.Bucket(stack, 'MyBucket', { autoDeleteObjects: true, - })).toThrow(/Cannot use \'autoDeleteObjects\' property on a bucket without setting removal policy to \'DESTROY\'/); + })).toThrow(/Cannot use auto-delete objects on a bucket without setting removal policy to \'DESTROY\'./); + }); + + test('can enable auto-delete objects after creation with enableAutoDeleteObjects()', () => { + const stack = new cdk.Stack(); + const bucket = new s3.Bucket(stack, 'MyBucket', { + removalPolicy: cdk.RemovalPolicy.DESTROY, + }); + bucket.enableAutoDeleteObjects(); + Template.fromStack(stack).hasResource('Custom::S3AutoDeleteObjects', { + 'Properties': { + 'ServiceToken': { + 'Fn::GetAtt': [ + 'CustomS3AutoDeleteObjectsCustomResourceProviderHandler9D90184F', + 'Arn', + ], + }, + 'BucketName': { + 'Ref': 'MyBucketF68F3FF0', + }, + }, + 'DependsOn': [ + 'MyBucketPolicyE7FBAC7B', + ], + }); + }); + + test('enableAutoDeleteObjects() throws if RemovalPolicy is not DESTROY', () => { + const stack = new cdk.Stack(); + const bucket = new s3.Bucket(stack, 'MyBucket'); + + expect(() => bucket.enableAutoDeleteObjects()).toThrow(/Cannot use auto-delete objects on a bucket without setting removal policy to \'DESTROY\'./); + }); + + test('enableAutoDeleteObjects() is idempotent', () => { + const stack = new cdk.Stack(); + const bucket = new s3.Bucket(stack, 'MyBucket', { + removalPolicy: cdk.RemovalPolicy.DESTROY, + }); + + bucket.enableAutoDeleteObjects(); + + expect(() => { + bucket.enableAutoDeleteObjects(); + }).not.toThrow(); + + Template.fromStack(stack).resourceCountIs('Custom::S3AutoDeleteObjects', 1); }); test('bucket with transfer acceleration turned on', () => {