AWS | Using Lambda with Cloudfront Lambda@Edge

 

AWS | Lambda Edge with Cloudfront Caching

What is Lambda@Edge ? 

AWS Cloudfront provides a feature to execute the Lambda functions to customise the content that it delivers using Python and Nodejs. These functions run as serverless in response to the Cloudfront events. Lambda@Edge can be provisioned at request as well as response to the Cloudfront at these points:

  1. Viewer Request: After Cloudwatch receives a request from the user/viewer.
  2. Origin Request: Before Cloudwatch forwards the request to the server/origin.
  3. Origin Response: After Cloudfront receives the response from the server/origin.
  4. Viewer Response: Before Cloudfront forwards the response to the user/viewer.

Few use cases of Cloudfront Lambda@Edge are mentioned below:

  • You can generate response to viewers without ever sending the request to the origin.
  • Add, delete, and modify headers, and edit the URL path to direct users to different objects in the cache.
  • Scan cookies to edit URLs to different versions of an application for A/B testing.
  • Send different objects and response to the users based the headers received.
  • Make network calls to external resources to confirm credentials, fetch content, etc.
AWS | Using Lambda with Cloudfront Lambda@Edge
Lambda Edge can be used at these points

Today's Agenda

In this post, we will learn how to setup Lambda@Edge with Lambda function at the edge of the Cloudfront. We will try a use-cases of Lambda@Edge using Python.

Prerequisite

This post has been prepared for the audience: 
  1. You should have an AWS account with access to create a Lambda Function, Cloudfront and IAM Role.
  2. Cloudfront CDN setup already. We will assume this to be already created.
  3. Have basic hands-on on Python Scripting language.
  4. And finally, are eager to learn and try something new.

Let's get started

We have mentioned a code snippet (in Python3.8) for below use-case. 
Use case: 
Redirect Origin Request URIs for a few specific paths based on User's Country.

In this use-case we want to redirect all the requests on some particular blogs (URI paths) to be redirected to the home page for users outside India.

Step 1: Create a new Lambda Function that will do the job.

Go to AWS home page > Services > Compute > Lambda.
NOTE:
  • For CloudFront to use Lambda at its edge, Lambda Function must be created in N. Virginia Region (us-east-1).
  • After your Lambda Function is ready, Save and Publish its numbered Version.
  • To update your Lambda Function, edit the $LATEST version of your function. Publish a new numbered version and update the ARN in CloudFront.
  • AWS provides few blueprints in Lambda for Lambda@Edge, but they are available only in us-east-1 region.
  • Lambda@Edge supports only these runtimes by the time this blog is created:
      • Node.js : 14, 12, 10 (version 8 & 6 are also supported by not recommended by AWS)
      • Python  : 3.8, 3.7

Create a new Lambda Function in us-east-1 AWS region. You may use a blueprint (provided by AWS) or start from scratch. 

We have to create 2 files like this:
lambda-redirect-using-origin-request/
|
|
|-------- lambda_function.py
|
|-------- redirect_rules.json

lambda_function.py
import json

def lambda_handler(event, context):
    request = event['Records'][0]['cf']['request']
    headers = request["headers"]
    host_name = headers["host"][0]["value"]
    uri = request['uri']
    domain_name = "https://therevisedcontext.com"
    file_name = "redirect_rules.json"
    rule_key = "rules"
    redirect_key = "redirect"
    original_key = "original"
    status_code_key = "statusCode"
    domain_name_key = "domainName"
    redirect_location = ""
    find_already = False
    redirect_status_code = "200"
    file_object = open(file_name, "r")
    json_data = json.loads(file_object.read())
    print("HostName: ", host_name)
    print("URI: ", uri)
    if not find_already:
        for ruleData in json_data[rule_key]:
            if str(uri) == str(ruleData[original_key]):
                viewerCountry = headers.get('cloudfront-viewer-country')
                if viewerCountry:
                    countryCode = viewerCountry[0]['value']
                    if countryCode != 'IN':
                        redirect_url = True
                        if redirect_url:
                            print("Original DomainName: ", ruleData[domain_name_key])
                            print("Original URI: ", ruleData[original_key])
                            print("Redirect DomainName: ", domain_name)
                            print("Redirect URI: ", ruleData[redirect_key])
                            print("Status Code: ", ruleData[status_code_key])
                            redirect_location = str(domain_name)
                            redirect_status_code = ruleData[status_code_key]
                            find_already = True
                            break
               
    if find_already:
        request = {
            'status': redirect_status_code,
            'statusDescription': 'Found',
            'headers': {
                'location': [{
                    'key': 'Location',
                    'value': redirect_location
                }]
            }
        }
        return request
    else:
        return request

redirect_rules.json
{
    "rules":[
        {
            "domainName": "therevisedcontext.com",
            "statusCode": "301",
            "original": "/shell-script-to-configure-fluentd.html",
            "redirect": ""
        },
        {
            "domainName": "therevisedcontext.com",
            "statusCode": "301",
            "original": "/configure-prometheus-script.html",
            "redirect": ""
        },
        {
            "domainName": "therevisedcontext.com",
            "statusCode": "301",
            "original": "/blackbox-exporter-for-prometheus.html",
            "redirect": ""
        },
        {
            "domainName": "therevisedcontext.com",
            "statusCode": "301",
            "original": "/jenkins-job-with-dsl-plugin.html",
            "redirect": ""
        }
    ],
    "querystrings":[
     
    ]
}

Save your files and make the required configuration changes (timeout, memory, basic Lambda Execution Role, etc) if needed.

Step 2 :  Publish a new numbered Version of your Lambda Function code.

Once you are satisfied with your code, save it and publish a new version of it.
Publish new Version of Lambda 


Copy the ARN of the new Published Version of your Lambda Function. The ARN will be something similar to this:
arn:aws:lambda:us-east-1:654321123456:function:lambda-function-name:9

Step 3 :  Update CloudFront Distribution required changes. 

You need to make the following changes for Lambda@Edge to work:
  • Edit CloudFront Distribution Behavior and Whitelist Headers to fetch Host and User Location.
  • Add Edge Function Association in CloudFront Behavior with Lambda@Edge, Event Type and Function ARN.
Edit the CloudFront Distribution Behavior to add Lambda@Edge

Edit CloudFront Distribution Behaviour and Whitelist Headers to fetch Host and user Location.
To fetch the User's Location (Country as per our use-case), add CloudFront-Viewer-Country header in Whitelisted space.
Whitelist Required Headers in CloudFront Behavior

Add Edge Function Association in CloudFront Behavior with Lambda@Edge, Event Type and Function ARN.
Associate Your Lambda Function to CloudFront Behavior

Save your changes.
Finally, wait for a few minutes before testing till your CloudFront Distribution Changes are deployed.

Restrictions on Lambda@Edge

The following restriction are administered on CloudFront Lambda@Edge:
  • Ownership of AWS account
  • The Cloudfront Distribution and the Lambda Function to be associated at edge should owned by the same AWS account.
  • Valid Combinations of CloudFront functions
  • Any cache behavior that has Lambda@Edge enabled can have only single association of each type (viewer request, origin request, origin response, viewer response).
  • You cannot associate Viewer request and Viewer response events type in a behavior.
  • HTTP status codes & headers
  • If origin returns HTTP status code 4xx or 5xx, CloudFront does not invoke Viewer response event. But for Origin response, Lambda@Edge can be invoke irrespective of the HTTP status code.
  • For Viewer response event types, Lambda@Edge cannot update the HTTP response code.
  • Few HTTP headers are not exposed to Lambda@Edge. If your function adds any of these headers, CloudFront validation fails and its returns HTTP status code 502 (Bad Gateway) to viewer. These headers are:
      • Connection
      • Expect
      • Keep-Alive
      • Proxy-Authenticate
      • Proxy-Authorization
      • Proxy-Connection
      • Trailer
      • Upgrade
      • X-Accel-Buffering
      • X-Accel-Charset
      • X-Accel-Limit-Rate
      • X-Accel-Redirect
      • X-Amz-Cf-*
      • X-Amzn-*
      • X-Cache
      • X-Edge-*
      • X-Forwarded-Proto
      • X-Real-IP
  • Few headers are ready-only i.e., your functions can read them, use them as input in function logic, but cannot modify or add them. If your function adds or updates any of these headers, CloudFront validation fails and its returns HTTP status code 502 (Bad Gateway) to viewer. These headers vary for event types:
    • In Viewer Request
      • Content-Length
      • Host
      • Transfer-Encoding
      • Via
    • In Origin Request
      • Accept-Encoding
      • Content-Length
      • If-Modified-Since
      • If-None-Match
      • If-Range
      • If-Unmodified-Since
      • Transfer-Encoding
      • Via
    • In Origin Response
      • Transfer-Encoding
      • Via
    • In Viewer Response
      • Content-Encoding
      • Content-Length
      • Transfer-Encoding
      • Warning
      • Via
  • Query String & URI
  • Your Lambda@Edge function can add or modify the query string for Viewer request and Origin request events.
  • Origin request or Cache Policy must be set to All or Query strings to access the query string in Origin request and Origin response events.
  • For Origin response and Viewer response events, query string can be read by the function but add or update are not allowed.
  • If above functions add or modify the query string, then:
    • They cannot add spaces, fragment identifier (#) or control characters to it.
    • Total URI size (including query string), must be less than 8192 characters.
    • Use of percent encoding for URI and query string is recommended.
  • Changing the URI for any request does not change the cache behavior and Origin of the request.
  • Use UTF-8 encoding for URI and query string values that the function returns.
  • On Lambda Functions
  • Lambda function associated must be used with a numbered version ($LATEST will not work).
  • Lambda function region must be us-east-1 (N. Virginia).
  • IAM role associated with your Lambda must allow the service principals edgelambda.amazonaws.com and lambda.amazonaws.com to assume the role.
  • Following Lambda features are not supported when using it as a Lambda@Edge:
    • Environment variables
    • Lambda Layers
    • Function cannot be configured inside a VPC.
    • Lambda on Container Images
    • Provisioned Concurrency and Reserved Concurrency

Thats all, You did a great job !!

For more use cases and details on this topic, please read the AWS documentation and Restrictions on Lambda@Edge.

If you face any issues of need any suggestions, please comment down below and hit the like button to appreciate the efforts.





Comments

  1. Many corporations on the planet today which began as startups across the same time as Evolution Gaming can't afford $2.02 billion to acquire one other market leader. It also 퍼스트카지노 proves that the live supplier market is growing stronger and presumably be} as large as the slots markets within the nearest future. Again, not too way back, the corporate in partnership with Betway launched Bollywood Roulette, a game based on the European Roulette. The catch in Bollywood Roulette is that the live supplier speaks Hindi. Thus, Indians will ready to|be succesful of|have the power to} enjoy the popular Roulette game of their native language. Players are supposed to position their bets and the supplier will ask for some extra info.

    ReplyDelete

Post a Comment