Skip to content

Commit

Permalink
add s3-cleanup-lambda template (#18)
Browse files Browse the repository at this point in the history
  • Loading branch information
aeghbali-mw authored and GitHub Enterprise committed Sep 20, 2024
1 parent bd63d2b commit 66f9731
Show file tree
Hide file tree
Showing 10 changed files with 196 additions and 10 deletions.
2 changes: 1 addition & 1 deletion aws/log-location/v1/.version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v1.0.0
v1.0.1
1 change: 1 addition & 0 deletions aws/log-location/v1/log-location.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
---
# Copyright 2023-2024 The MathWorks, Inc.
AWSTemplateFormatVersion: '2010-09-09'

Description: >
Expand Down
1 change: 1 addition & 0 deletions aws/s3-cleanup-lambda/v1/.version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
v1.0.0
181 changes: 181 additions & 0 deletions aws/s3-cleanup-lambda/v1/s3-cleanup-lambda.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
---
# Copyright 2024 The MathWorks, Inc.
AWSTemplateFormatVersion: '2010-09-09'

Transform: AWS::LanguageExtensions

Description: 'MathWorks Reference Architectures: S3 Bucket Cleanup Template - Automates the cleanup of an S3 bucket before stack deletion.'

Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: "S3 Configuration"
Parameters:
- BucketName
- Label:
default: "Permission Configuration"
Parameters:
- EmptyBucketLambdaExecutionRoleArn
ParameterLabels:
BucketName:
default: "S3 Bucket Name"
EmptyBucketLambdaExecutionRoleArn:
default: "Lambda Execution Role ARN"

Parameters:
BucketName:
Type: String
Description: Name of the existing S3 bucket.
AllowedPattern: ^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$
MinLength: 3
MaxLength: 63
ConstraintDescription: Bucket names must be between 3 and 63 characters long, consist only of lowercase letters, numbers, dots (.), and hyphens (-), and must begin and end with a letter or number.

EmptyBucketLambdaExecutionRoleArn:
Type: String
Default: ''
Description: (Optional) ARN of an existing IAM role to be used by the lambda function. Make sure that the IAM role has the necessary permissions to manage the S3 bucket specified in the BucketName parameter. If you leave this parameter blank, a new IAM role will be created.
AllowedPattern: ^(arn:(aws|aws-cn|aws-us-gov):iam::\d{12}:role(\/[\w-]*)*)?$

Conditions:
CreateNewRole: !Equals [!Ref EmptyBucketLambdaExecutionRoleArn, '']

Resources:
EmptyBucketLambda:
Type: AWS::Lambda::Function
Properties:
Code:
ZipFile: |
import boto3
import cfnresponse
from botocore.exceptions import ClientError
def lambda_handler(event, context):
status = cfnresponse.SUCCESS
data = {'Message': '', 'Errors': '', 'Exception': ''}
try:
bucket_name = event['ResourceProperties']['BucketName']
s3 = boto3.resource('s3')
if event['RequestType'] == 'Create':
try:
s3.meta.client.head_bucket(Bucket=bucket_name)
except ClientError as e:
print(e)
if "Forbidden" in str(e):
reason = f'Unable to find a bucket with name "{bucket_name}".'
else:
reason = f'Something went wrong while checking for the bucket "{bucket_name}".'
data['Message'] += f'{reason} Make sure S3 bucket exists. See the details in CloudWatch Log Stream: {context.log_stream_name}.'
cfnresponse.send(event, context, cfnresponse.FAILED, data, None, False, reason)
return
elif event['RequestType'] == 'Delete':
bucket = s3.Bucket(bucket_name)
versioning = bucket.Versioning()
if versioning.status == 'Enabled':
data['Message'] += 'Bucket is versioned.'
print(f"bucket {bucket_name} is versioned. Suspending versioning and deleting all object versions.")
versioning.suspend()
response = bucket.object_versions.delete()
if any('Errors' in r for r in response):
status = cfnresponse.FAILED
data['Errors'] += ';'.join(str(r['Errors']) for r in response)
else:
data['Message'] += ' Versions deleted successfully.'
print(f"All object versions in bucket {bucket_name} have been deleted. Enabling the versioning again.")
versioning.enable()
else:
data['Message'] += 'Bucket is not versioned.'
response = bucket.objects.delete()
if any('Errors' in r for r in response):
status = cfnresponse.FAILED
data['Errors'] += ';'.join(str(r['Errors']) for r in response)
else:
data['Message'] += ' Objects deleted successfully.'
else:
data['Message'] += f'Lambda triggered successfully. No action was required for event type "{event["RequestType"]}".'
except Exception as e:
status = cfnresponse.FAILED
data['Exception'] = str(e)
cfnresponse.send(event, context, status, data)
Handler: index.lambda_handler
Runtime: python3.12
Timeout: 900
Role: !If
- CreateNewRole
- !GetAtt EmptyBucketRole.Arn
- !Ref EmptyBucketLambdaExecutionRoleArn

EmptyBucketRole:
Type: AWS::IAM::Role
Condition: CreateNewRole
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- sts:AssumeRole
Path: /
Policies:
- PolicyName: bucket-cleanup-lambda-policy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Sid: CloudWatchPermissions
Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
Resource:
- !Sub arn:${AWS::Partition}:logs:*:*:log-group:/aws/lambda/*EmptyBucketLambda*
- !Sub arn:${AWS::Partition}:logs:*:*:log-group:/aws/lambda/*EmptyBucketLambda*:log-stream:*
- Sid: AllowRead
Effect: Allow
Action:
- s3:ListBucket
- s3:ListBucketVersions
- s3:GetBucketVersioning
Resource:
- !Sub arn:${AWS::Partition}:s3:::${BucketName}
- Sid: AllowEdit
Effect: Allow
Action:
- s3:PutBucketVersioning
Resource:
- !Sub arn:${AWS::Partition}:s3:::${BucketName}
- Sid: AllowDelete
Effect: Allow
Action:
- s3:DeleteObject
- s3:DeleteObjectVersion
Resource:
- !Sub arn:${AWS::Partition}:s3:::${BucketName}/*

EmptyBucketTrigger:
Type: Custom::EmptyBucketLambdaTrigger
Properties:
ServiceToken: !GetAtt EmptyBucketLambda.Arn
BucketName: !Ref BucketName

Outputs:
BucketName:
Value: !Ref BucketName
BucketArn:
Value: !Sub arn:${AWS::Partition}:s3:::${BucketName}
EmptyBucketLambdaArn:
Value: !GetAtt EmptyBucketLambda.Arn
EmptyBucketLambdaRoleArn:
Value: !If
- CreateNewRole
- !GetAtt EmptyBucketRole.Arn
- !Ref EmptyBucketLambdaExecutionRoleArn

2 changes: 1 addition & 1 deletion aws/security-group/v1/.version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v1.1.0
v1.1.1
1 change: 1 addition & 0 deletions aws/security-group/v1/security-group.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
---
# Copyright 2023-2024 The MathWorks, Inc.
AWSTemplateFormatVersion: '2010-09-09'

Description: >
Expand Down
2 changes: 1 addition & 1 deletion aws/storage-location/v1/.version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v1.0.0
v1.0.1
3 changes: 2 additions & 1 deletion aws/storage-location/v1/storage-location.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
---
# Copyright 2023-2024 The MathWorks, Inc.
AWSTemplateFormatVersion: '2010-09-09'

Transform: AWS::LanguageExtensions
Expand Down Expand Up @@ -124,7 +125,7 @@ Resources:
- sts:AssumeRole
Path: /
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
- arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Policies:
- PolicyName: empty-bucket-core
PolicyDocument:
Expand Down
2 changes: 1 addition & 1 deletion aws/storage-location/v2/.version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v2.0.1
v2.0.2
11 changes: 6 additions & 5 deletions aws/storage-location/v2/storage-location.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
---
# Copyright 2023-2024 The MathWorks, Inc.
AWSTemplateFormatVersion: '2010-09-09'

Transform: AWS::LanguageExtensions
Expand Down Expand Up @@ -144,7 +145,7 @@ Resources:
- sts:AssumeRole
Path: /
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
- arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Policies:
- PolicyName: empty-bucket-core
PolicyDocument:
Expand All @@ -159,15 +160,15 @@ Resources:
Resource: !If
- CreateNewBucketCondition
- !GetAtt Bucket.Arn
- !Sub arn:aws:s3:::${BucketName}
- !Sub arn:${AWS::Partition}:s3:::${BucketName}
- Sid: AllowEdit
Effect: Allow
Action:
- s3:PutBucketVersioning
Resource: !If
- CreateNewBucketCondition
- !GetAtt Bucket.Arn
- !Sub arn:aws:s3:::${BucketName}
- !Sub arn:${AWS::Partition}:s3:::${BucketName}
- Sid: AllowDelete
Effect: Allow
Action:
Expand All @@ -176,7 +177,7 @@ Resources:
Resource: !If
- CreateNewBucketCondition
- !Sub ${Bucket.Arn}/*
- !Sub arn:aws:s3:::${BucketName}/*
- !Sub arn:${AWS::Partition}:s3:::${BucketName}/*

EmptyBucketTrigger:
Type: Custom::LambdaTrigger
Expand All @@ -199,4 +200,4 @@ Outputs:
Value: !If
- CreateNewBucketCondition
- !GetAtt Bucket.Arn
- !Sub arn:aws:s3:::${BucketName}
- !Sub arn:${AWS::Partition}:s3:::${BucketName}

0 comments on commit 66f9731

Please sign in to comment.