In the previous post, we have created a CDN CloudFront using the AWS CloudFormation. In this post we will configure a Lambda@Edge.
The Lambda@Edge can be run on the request or on the response, and also on the viewer side or on the origin side. In this example we will start the lambda on the origin request, which means it will e started upon cache miss on the CDN. The lambda will write to a S3 bucket the request details.
First let's configure the S3 bucket.
S3Bucket:
Type: AWS::S3::Bucket
Properties:
AccessControl: Private
BucketName: cdn-po-transactions
Tags:
- Key: Name
Value: transactions
Next add the lambda role, and add permissions to write to the S3 bucket.
LambdaRole:
Type: AWS::IAM::Role
Properties:
Tags:
- Key: Name
Value: lambda-role
Path: "/"
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
- arn:aws:iam::aws:policy/AmazonS3FullAccess
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Sid: AllowLambdaServiceToAssumeRole
Effect: Allow
Action:
- sts:AssumeRole
Principal:
Service:
- lambda.amazonaws.com
- edgelambda.amazonaws.com
Now we configure a lambda version, allowing us to deploy it.
LambdaVersion:
Type: AWS::Lambda::Version
Properties:
FunctionName:
Ref: Lambda
And configure the lambda itself, including its NodeJS based code.
Lambda:
Type: AWS::Lambda::Function
Properties:
Role: !GetAtt LambdaRole.Arn
Runtime: nodejs12.x
Timeout: 10
Tags:
- Key: Name
Value: lambda
Handler: index.handler
Code:
ZipFile: |
const https = require('https');
const aws = require('aws-sdk');
const keepAliveAgent = new https.Agent({keepAlive: true});
const s3 = new aws.S3({region: 'us-east-1', httpOptions: {agent: keepAliveAgent}});
exports.handler = function(event, context, callback) {
const path = Date.now() + '/' + (Math.random().toString(36).substr(2, 9)).toUpperCase();
const params = {
Bucket: 'cdn-po-transactions',
Key: path,
Body: JSON.stringify(event),
};
s3.upload(params, function(err, data) {
if (err) {
throw err;
}
console.log(`File uploaded successfully. ${data.Location}`);
});
const request = event.Records[0].cf.request;
callback(null, request);
}
The last thing to do is to update the CloudFront configuration (presented in the previous post), to include the lambda invocation.
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Enabled: true
HttpVersion: http2
IPV6Enabled: false
DefaultCacheBehavior:
CachePolicyId: !Ref CloudFrontCachePolicy
OriginRequestPolicyId: !Ref CloudFrontOriginRequestPolicy
TargetOriginId: !Ref ApplicationLoadBalancer
ViewerProtocolPolicy: allow-all
LambdaFunctionAssociations:
- EventType: origin-request
IncludeBody: false
LambdaFunctionARN: !Join
- ":"
-
- !GetAtt Lambda.Arn
- !GetAtt LambdaVersion.Version
Origins:
- Id: !Ref ApplicationLoadBalancer
DomainName: !GetAtt ApplicationLoadBalancer.DNSName
CustomOriginConfig:
HTTPPort: 80
OriginProtocolPolicy: match-viewer
OriginSSLProtocols:
- TLSv1
Final Note
In this post we have configured Lambda@Edge on the AWS CloudFront using AWS CloudFormation. The Lambda@Edge enables use to manipulate the requests and the response, in addition to saving various parts of the request and the response.