DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’» is a community of 967,611 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

Create account Log in
Cover image for Apply Cloudfront Security Headers Policy With Terraform
Serhii Vasylenko for AWS Community Builders

Posted on • Originally published at devdosvid.blog on

Apply Cloudfront Security Headers Policy With Terraform

In November 2021, AWS announced Response Headers Policies β€” native support of response headers in CloudFront. You can read the full announcement here: Amazon CloudFront introduces Response Headers Policies

I said β€œnative” because previously you could set response headers either using CloudFront Functions or Lambda@Edge.

And one of the common use cases for that was to set security headers. So now you don’t need to add intermediate requests processing to modify the headers: CloudFront does that for you with no additional fee.

Manage Security Headers as Code

Starting from the 3.64.0 version of Terraform AWS provider, you can create the security headers policies and apply them for your distribution.

Let’s see how that looks!

First, you need to describe the aws_cloudfront_response_headers_policy resource:

 resource "aws_cloudfront_response_headers_policy" "security_headers_policy" {
  name = "my-security-headers-policy"
  security_headers_config {
    content_type_options {
      override = true
    }
    frame_options {
      frame_option = "DENY"
      override = true
    }
    referrer_policy {
      referrer_policy = "same-origin"
      override = true
    }
    xss_protection {
      mode_block = true
      protection = true
      override = true
    }
    strict_transport_security {
      access_control_max_age_sec = "63072000"
      include_subdomains = true
      preload = true
      override = true
    }
    content_security_policy {
      content_security_policy = "frame-ancestors 'none'; default-src 'none'; img-src 'self'; script-src 'self'; style-src 'self'; object-src 'none'"
      override = true
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

List of security headers used:

The values for the security headers can be different, of course. However, the provided ones cover the majority of cases. And you can always get the up to date info about these headers and possible values here: Mozilla web Security Guidelines

Also, you could notice that provided example uses the override argument a lot. The override argument tells CloudFront to set these values for specified headers despite the values received from the origin. This way, you can enforce your security headers configuration.

Once you have the aws_cloudfront_response_headers_policy resource, you can refer to it in the code of aws_cloudfront_distribution resource inside cache behavior block (default or ordered). For example, in your default_cache_behavior:

resource "aws_cloudfront_distribution" "test" {
  default_cache_behavior {
    target_origin_id = aws_s3_bucket.my_origin.id
    allowed_methods = ["GET", "HEAD", "OPTIONS"]
    cached_methods = ["GET", "HEAD"]
    viewer_protocol_policy = "redirect-to-https"

    # some arguments skipped from listing for the sake of simplicity

    response_headers_policy_id = aws_cloudfront_response_headers_policy.security_headers_policy.id

  }

  # some arguments skipped from listing for the sake of simplicity
}

Enter fullscreen mode Exit fullscreen mode

More to read:


Top comments (1)

Collapse
 
mxro profile image
Max Rohde

Thanks for this great article! Very useful.

For future readers, note that the suggested content_security_policy is pretty restrictive and will break many dynamic pages (e.g. when implemented using Next.js). A more conservative (if less secure) configuration would be: frame-ancestors 'none'; default-src https: 'unsafe-eval' 'unsafe-inline'; object-src 'none'.

🌚 Friends don't let friends browse without dark mode.

Sorry, it's true.