Customising Content Delivery with AWS CloudFront: Routing with Origin Request Policies and CloudFront Functions
Published: 2024-04-18 19:33:37

While studying for the AWS SysOps Administrator certification exam, I discovered an interesting feature in AWS CloudFront that allows serving different objects based on cookies or HTTP request headers specified through the origin request policy. This concept intrigued me, but it didn’t truly resonate until I began experimenting with it myself. In today’s blog post, I will share a step-by-step guide on how to set this up by forwarding the value of request headers. To enhance clarity, I'll conclude with a visual demonstration directly from the AWS console.


**This post is intended for readers with existing knowledge of AWS.**

## Prerequisites
- Knowledge of S3 Buckets & Policies
- Understanding of how to set up a CloudFront Distribution with S3



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ntpwlb4fikee20mh0q2g.png)

By creating a CloudFront distribution as shown above, you can access `https://d3h4a6v5efbkjq.cloud.net/index.html` directly, leads you to `index.html` without any prefix.
 


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b5k394wxikl041cri4d7.png)

We will forward the Accept-Language header, and the CloudFront function will then redirect based on this value. For example, if the `Accept-Language` value is English, the user will be redirected to `/en/index.html`.


## Create S3 Bucket and Upload Files
Navigate to S3 from the AWS console and create a new bucket.
Set up your project files as follows:
Root directory: index.html
Korean version: /kr/index.html
English version: /en/index.html
```
<!-- Root index.html -->
<!DOCTYPE html>
<html>
<head>
    <title>gritcoding</title>
    <meta charset="UTF-8">
</head>
<body>
    <h1>gritcoding</h1>
</body>
</html>

<!-- /kr/index.html -->
<!DOCTYPE html>
<html>
<head>
    <title>한국어</title>
    <meta charset="UTF-8">
</head>
<body>
    <h1>안녕</h1>
</body>
</html>

<!-- /en/index.html -->
<!DOCTYPE html>
<html>
<head>
    <title>English</title>
    <meta charset="UTF-8">
</head>
<body>
    <h1>hi</h1>
</body>
</html>

```

Once uploaded, you will be able see `index.html`, `/en/index.html`, `/kr/index.html` objects in the bucket.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g8ddjgbi26jfijp8w17c.png)


## Create CloudFront Function and Deploy
Navigate to CloudFront and crate a new function.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6jertrkynoei5o8slf5x.png)
Update the function using the code below.
```
function handler(event) {
    const request = event.request;
    const headers = request.headers;
    
    // Check for English language in Accept-Language header
    const langHeader = headers['accept-language'];
    if (langHeader && langHeader.value.indexOf('en') !== -1) {
        // Route to English version of the content
        request.uri = '/en' + request.uri;
    } else {
        // Route to Korean version of the content
        request.uri = '/kr' + request.uri;
    }

    return request;
}
```
Now, you can test this function in the test tab. Use the following steps to simulate a request.

- Scroll down to the `Add header` button and click it.
- Enter `accept-language` as the header key.
- Add `en-GB` as the header value.
- Click the `Test function` button located above.
If the test is successful, you should see that it returns `/en/index.html` as shown in the screenshot below.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/haon46sqdb5qqyv1t23x.png)


## Create CloudFront Origin Request Policy
Navigate to CloudFront/Policies/Origin request as shown in the screenshot below. 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rmdlfolhsy8nasyq3usf.png)

Name the policy, select `include the following headers` in the Headers dropdown, and choose the `Accept-Language` header.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pgzjwjn2g8srlbnwliri.png)
Once the origin request policy is created, proceed to create a distribution.

## Create CloudFront Distribution
Navigate to CloudFront and click the `create distribution` button. Select the bucket you created as the Origin domain.
Then, scroll down to the `Cache key and origin requests` section, select the origin request policy you created, and set the `viewer request function type` to CloudFront functions to select the function we created.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h3hikkvl8vbb7kapab0e.png)

## Update S3 Bucket Policy
Navigate back to your S3 bucket and update the bucket policy.
Use the following JSON code to update it, ensuring you replace `S3 bucket name`, `Your AWS Account Number`, and `CloudFront distribution ID` with the actual values specific to your setup.

```
{
    "Version": "2012-10-17",
    "Statement": {
        "Sid": "AllowCloudFrontServicePrincipalReadWrite",
        "Effect": "Allow",
        "Principal": {
            "Service": "cloudfront.amazonaws.com"
        },
        "Action": "s3:GetObject",
        "Resource": "arn:aws:s3:::<S3 bucket name>/*",
        "Condition": {
            "StringEquals": {
                "AWS:SourceArn": "arn:aws:cloudfront::<Your AWS Account Number>:distribution/<CloudFront distribution ID>"
            }
        }
    }
}
```

After updating the policy, copy the CloudFront distribution domain name and paste it into your web browser followed by `/index.html`. Depending on the Accept-Language header in your request, this setup will either direct you to `/en/index.html` if English is detected, or `/kr/index.html` for all other languages.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3ixq7fu0ghr6ygjubqzd.png)
In this setup, direct access to the `index.html` with the `gritcoding` message is not available, as the CloudFront distribution has been configured to redirect based on language settings.

Learn more:

Watch the step-by-step video guide on setting up and testing this configuration on our YouTube channel linked below.

{% youtube AF6URiECba8 %}

Thanks for reading. :)