This blog post will guide you through the process of creating a CloudFormation stack that automatically invalidates CloudFront cache when you upload updated files to an associated S3 bucket. We will achieve this by using an AWS Lambda function that gets triggered by S3 bucket notifications.
webclient-assets
.Update your existing CloudFormation template to include the necessary resources for the Lambda function, S3 Bucket Notification, and Lambda Permission.
Here is the updated CloudFormation template including the new resources:
[...]
# Add the following resources to your existing CloudFormation template
# Lambda function
InvalidateCloudFrontFunction:
Type: AWS::Lambda::Function
Properties:
FunctionName: InvalidateCloudFront
Handler: index.lambda_handler
Role: !GetAtt LambdaExecutionRole.Arn
Runtime: python3.8
Code:
S3Bucket: REPLACE_WITH_YOUR_S3_BUCKET_NAME
S3Key: lambda_function.zip
# S3 bucket notification configuration
ContentBucketNotification:
Type: AWS::S3::BucketNotificationConfiguration
Properties:
Bucket: !Ref WebsiteBucket
NotificationConfiguration:
LambdaConfigurations:
- Event: s3:ObjectCreated:*
Function: !GetAtt InvalidateCloudFrontFunction.Arn
# Lambda execution role
LambdaExecutionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- sts:AssumeRole
Policies:
- PolicyName: LambdaExecutionPolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
Resource: 'arn:aws:logs:*:*:*'
- Effect: Allow
Action:
- cloudfront:CreateInvalidation
Resource: '*'
# Lambda invoke permission
LambdaInvokePermission:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:InvokeFunction
FunctionName: !Ref InvalidateCloudFrontFunction
Principal: s3.amazonaws.com
SourceAccount: !Ref 'AWS::AccountId'
SourceArn: !Sub 'arn:aws:s3:::${WebsiteBucket}'
Create a file named ```index.py`` with the following Python code for the Lambda function:
import boto3
import uuid
def lambda_handler(event, context):
distribution_id = 'REPLACE_WITH_YOUR_CLOUDFRONT_DISTRIBUTION_ID'
cloudfront_client = boto3.client('cloudfront')
caller_reference = str(uuid.uuid4()) # Using a UUID as CallerReference
response = cloudfront_client.create_invalidation(
DistributionId=distribution_id,
InvalidationBatch={
'Paths': {
'Quantity': 1,
'Items': ['/*']
},
'CallerReference': caller_reference
}
)
return {
'statusCode': 200,
'body': json.dumps(response)
}
Create a .zip
archive containing the index.py
file. Name the archive ```lambda_function.zip``.
Use the AWS CLI to update your CloudFormation stack with the updated template:
aws cloudformation update-stack \
--stack-name webclient-assets \
--template-body file://path/to/your/updated_template.yaml \
--capabilities CAPABILITY_NAMED_IAM
Replace path/to/your/updated_template.yaml
with the path to your updated CloudFormation template file.
Now, whenever you update the content in your S3 bucket, the associated CloudFront cache will be automatically invalidated. This will ensure that your users always see the latest content on your website.
If you need to make further changes to your CloudFormation stack or Lambda function, simply update the necessary files and repeat the steps to update the stack.
Happy coding!
If you made it this far, you may as well follow me on LinkedIn: Follow Brian Porter