Force CloudFormation to delete non-empty S3 Bucket on AWS
1 min readJul 13, 2024
Here’s a CloudFormation template that accomplishes this:
- S3 Bucket Creation: The stack creates an S3 bucket.
- Lambda Function: A Lambda function that empties the S3 bucket (Only during Deletion of the Stack)
- Lambda Service Role: Role that assigns the permission to the lambda function to delete a given s3 bucket
- Custom Resource: A custom resource that triggers the Lambda function on stack deletion.
AWSTemplateFormatVersion: '2010-09-09'
Resources:
MyBucket:
Type: 'AWS::S3::Bucket'
Properties:
BucketName: !Sub 'my-s3-bucket-${AWS::StackName}-${AWS::Region}'
EmptyBucketFunctionRole:
Type: 'AWS::IAM::Role'
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: 'Allow'
Principal:
Service: 'lambda.amazonaws.com'
Action: 'sts:AssumeRole'
Policies:
- PolicyName: 'EmptyBucketPolicy'
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: 'Allow'
Action:
- 's3:ListBucket'
- 's3:DeleteObject'
Resource:
- !Sub 'arn:aws:s3:::my-s3-bucket-${AWS::StackName}-${AWS::Region}'
- !Sub 'arn:aws:s3:::my-s3-bucket-${AWS::StackName}-${AWS::Region}/*'
EmptyBucketFunction:
Type: 'AWS::Lambda::Function'
Properties:
Handler: index.handler
Role: !GetAtt EmptyBucketFunctionRole.Arn
Code:
ZipFile: |
import boto3
import cfnresponse
s3 = boto3.resource('s3')
def handler(event, context):
if event['RequestType'] == 'Delete':
bucket_name = event['ResourceProperties']['BucketName']
bucket = s3.Bucket(bucket_name)
bucket.objects.all().delete()
cfnresponse.send(event, context, cfnresponse.SUCCESS, {})
Runtime: 'python3.9'
Timeout: 300
CustomBucketResource:
Type: 'AWS::CloudFormation::CustomResource'
Properties:
ServiceToken: !GetAtt EmptyBucketFunction.Arn
BucketName: !Ref MyBucket
Outputs:
BucketName:
Description: 'Name of the S3 bucket'
Value: !Ref MyBucket
I’ve made sure to follow the principle of “Least Privilege” when creating this Stack.
Cheers.