Amazon Cloudfront: Response header policy (tutorial)

Published on: Sun Nov 20 2022

Series

Content

Introduction

Within Amazon Cloudfront, there is a policy for customizing response properties sent to the client.

This policy is called the response header policy.

In this tutorial, we will create a simple response header policy to adjust the Cache-Control sent to the client.

Let’s dive right in!

The Architecture

Illustration of the sandbox architecture with Cloudfront and Lambda
Illustration of the sandbox architecture with Cloudfront and Lambda

The steps

  1. The Viewer (client) request comes in

  2. Cloudfront forwards the request to the origin server (Lambda URL + Lambda)

  3. The logs from the request are added into Cloudwatch Logs

  4. The Lambda function returns a response

  5. The Viewer (client) receives the response

Before you start

Before you start going through the tutorial, make sure you are using the starter - amazon-cloudfront-create-distribution.

This streamlines some of the things like building the lambda functions and writing out all the boilerplate files.

It will be the base from which we will build from!

Cloudfront response header policy

Now onto setting up the infrastructure.

1. Create a response header policy resource

In our case, we will be using a custom header, and we will set the override to true.

Also, we will just set a arbitrary value for the max-age so we can see it on the client response headers.

Add the following changes:

// infra/main.tf

resource "aws_cloudfront_response_headers_policy" "custom" {
  name = "custom-response-header-policy"
  custom_headers_config {
    items {
      header   = "Cache-Control"
      override = true
      value    = "max-age=5"
    }
  }
}

Helpful Reference

2. Attach it to the default cache behavior

Now Lambda function supports an option to expose an URL, so we can use our function as our “origin server” for testing the request origin policy.

Add the following changes:

// infra/main.tf

resource "aws_cloudfront_distribution" "cf_distribution" {
  origin {
    # This is required because "domain_name" needs to be in a specific format
    domain_name = replace(replace(aws_lambda_function_url.origin.function_url, "https://", ""), "/", "")
    origin_id = module.lambda_origin.lambda[0].function_name

    custom_origin_config {
      https_port = 443
      http_port = 80
      origin_protocol_policy = "https-only"
      origin_ssl_protocols = ["TLSv1.2"]
    }
  }

  default_cache_behavior {
    allowed_methods  = ["GET", "HEAD"]
    cached_methods   = ["GET", "HEAD"]
    target_origin_id = module.lambda_origin.lambda[0].function_name
    forwarded_values {
      query_string = false
      cookies {
        forward = "none"
      }
    }
    viewer_protocol_policy     = "redirect-to-https"
    min_ttl                    = local.min_ttl
    default_ttl                = local.default_ttl
    max_ttl                    = local.max_ttl
    response_headers_policy_id = aws_cloudfront_response_headers_policy.custom.id
  }

  price_class = var.cf_price_class
  enabled = true
  is_ipv6_enabled     = true
  comment             = "origin request policy test"
  default_root_object = "index.html"

  restrictions {
    geo_restriction {
      restriction_type = "none"
    }
  }

  tags = {
    Environment = "production"
  }

  viewer_certificate {
    cloudfront_default_certificate = true
  }
}

Helpful Reference

3. Apply the infrastructure

Now we have all our definition in Terraform, all that is left is to generate it.

Run the following:

// This will re-generate the assets
pnpm run generate-assets --filter "@function/*"

export AWS_ACCESS_KEY_ID=<your-key>
export AWS_SECRET_ACCESS_KEY=<your-secret>
export AWS_DEFAULT_REGION=us-east-1

terraform init
terraform plan
terraform apply -auto-approve

If the infrastructure applied successfully then you should see something like this:

Illustration of the Terraform outputs
Illustration of the Terraform outputs

Testing it out

1. Make a request

Curl:

curl -vvv "<cf_distribution_domain_url>"

Postman:

Illustration of the client response using postman
Illustration of the client response using postman

Conclusion

That’s really it for the response header.

Our tutorial covers a simple example of customizing the Cache-Control using response header policies, you can do a lot more like adjusting security headers.

Be sure to to check out AWS’s documentation on adding response header - AWS adding-response-headers.

And... that’s all for now, stay tuned for more!

If you found this helpful or learned something new, please do share this article with a friend or co-worker 🙏❤️ (Thanks!)


Enjoy the content ?

Then consider signing up to get notified when new content arrives!

Jerry Chang 2023. All rights reserved.