CloudFront Functions
Published: 2021-05-31 08:35:25

---
title: CloudFront Functions
published: true
date: 2021-05-31 08:00:00 UTC
tags: 
canonical_url: https://globaldatanet.com/blog/cloudfront-functions

---

![CloudFront Functions](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7680ui4x89xk3v1gg2ak.png)


<br>

A few weeks ago Amazon announced a [new feature](https://aws.amazon.com/about-aws/whats-new/2021/05/cloudfront-functions/) for Amazon CloudFront to run code in Edge Locations. But where is the difference between Lambda@Edge and CloudFront Functions?
CloudFront Functions are running in Edge locations whereas Lambda@Edge functions are executed in a regional edge cache (eg.: the AWS region closest to the CloudFront edge location reached by the client). Therefore CloudFront Functions are even closer to the client and are at the same time approximately 1/6th the price of Lambda@Edge.

## Use Cases

- **Authorization**: Implement authorization for the content delivered through CloudFront using Basic Authentication or by creating and validating user-generated tokens. 

</br>

- **Redirects**: Redirect users to a different URL - eg.: If you change to a new website structure you can redirect the user to the new URL.

</br>

- **Header Manipulation**: Add, modify, or delete any of the request/response headers - eg.: foward the IP of the client using the Header to your origin.

## CloudFront Functions versus Lambda@Edge

### Features
Most important differences - if you need more information check this docs: [Choosing between CloudFront Functions and Lambda@Edge](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/edge-functions.html).

|  |  CloudFront Functions | Lambda@Edge|
|:-----:|:-----:|:-----:| 
| Execution location |  CloudFront Edge Locations | CloudFront Regional Edge Caches|
| Programming languages |  JavaScript ([ECMAScript 5.1](https://262.ecma-international.org/5.1/) compliant) | Python, Nodejs|
| Event sources |  Viewer request </br> Viewer response | Viewer request </br> Viewer response </br>Origin request </br> Origin response|
| Memory |  2 MB | 128 MB (viewer triggers) – 10 GB (origin triggers)|
| Max size of Function |  10 KB | 1 MB (viewer request / response) </br> 50 MB (origin request / response)|
| Max execution time |  1 ms | 5 seconds (viewer request / response) </br> 30 seconds (origin request / response)|
| Access to geolocation and device data |  ✅ | ❌ (viewer request) </br> ✅ (viewer response) </br> ✅ (origin request) </br>  ✅ (origin response) |
| Access to the request body |  ❌ | ✅ |

### Pricing example
| Service |  Price per Invocation | Price per Duration (for every GB-second)| Invocations|Duration|Allocated Memory |Total Cost|
|:-----:|:-----:|:-----:|:-----:|:-----:|:-----:|:-----:|
| CloudFront Function | $0.1|-|2 Million|1ms|-| $2.0|
| Lambda@Edge | $0.6  |$0,00005001|2 Million|10ms|128MB |$12.26|

* The prices were checked on 30.05.2021 from [Lambda@Edge pricing](https://aws.amazon.com/lambda/pricing/) and [CloudFront Function pricing](https://aws.amazon.com/cloudfront/pricing/)

</br>

## Example template for Basic Auth with CloudFront Functions
Following you will find a CloudFront Function for Basic Auth - I am using it as a second layer of security for private CloudFront origins. For example I am generating exports of Jira content to S3 using a Lambda as a Backup. In Front of CloudFront I have a WAF to restrict to spefic IPs plus these CloudFront functions. 
```yaml
AWSTemplateFormatVersion: 2010-09-09
Description: Creates a Base CloudFront Function for Authentification
Metadata:
  Author:
    Description: David Krohn

Parameters:
  CloudFrountUsername:
    Description: Username CloudFront
    Type: String
  CloudFrountPassword:
    Description: Password CloudFront
    Type: String
    NoEcho: true
Ressources:
  CloudFrontFunctionBasicAuth:
    Type: AWS::CloudFront::Function
    Properties: 
      AutoPublish: true
      FunctionCode: !Sub |
        var USERS = {
            Website: [{
                username: '${CloudFrountUsername}',
                password: '${CloudFrountPassword}',
            }],
        };

        //Response when auth is not valid.
        var response401 = { 
            statusCode: 401,
            statusDescription: 'Unauthorized',
            headers: {
                'www-authenticate': {
                    value: 'Basic'
                },
            },
        };

        var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

        function btoa(input) {
            input = String(input);
            var bitmap, a, b, c,
                result = "",
                i = 0,
                rest = input.length % 3; // To determine the final padding

            for (; i < input.length;) {
                if ((a = input.charCodeAt(i++)) > 255 ||
                    (b = input.charCodeAt(i++)) > 255 ||
                    (c = input.charCodeAt(i++)) > 255)
                    throw new TypeError("Failed to execute 'btoa' on 'Window': The string to be encoded contains characters outside of the Latin1 range.");

                bitmap = (a << 16) | (b << 8) | c;
                result += b64.charAt(bitmap >> 18 & 63) + b64.charAt(bitmap >> 12 & 63) +
                    b64.charAt(bitmap >> 6 & 63) + b64.charAt(bitmap & 63);
            }

            // If there's need of padding, replace the last 'A's with equal signs
            return rest ? result.slice(0, rest - 3) + "===".substring(rest) : result;
        }

        function handler(event) {
            var request = event.request;
            var headers = request.headers;

            var auth = request.headers.authorization && request.headers.authorization.value;


            var users = USERS['Website'];

            if (users) {
                if (!auth || !auth.startsWith('Basic ')) {
                    return response401;
                }
                if(!users.find(function(user) {

                        // Construct the Basic Auth string
                        var authString = 'Basic ' + btoa(user.username + ':' + user.password);

                        return authString === auth;
                    })) {
                    return response401;
                }
            }
            return request;
        }

      FunctionConfig:
        Comment: !Sub 'Basic Auth for S3 Bucket ${MyWebsiteBucket}'
        Runtime: cloudfront-js-1.0
```


More samples can be found here: [Amazon CloudFront Functions Samples](https://github.com/aws-samples/amazon-cloudfront-functions).