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
}
}
}
List of security headers used:
- X-Content-Type-Options
- X-Frame-Options
- Referrer Policy
- X-XSS-Protection
- Strict Transport Security
- Content Security Policy
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
}
More to read:
- Terraform Resource: aws_cloudfront_response_headers_policy
- Creating response headers policies - Amazon CloudFront
- Using the managed response headers policies - Amazon CloudFront
- Understanding response headers policies - Amazon CloudFront
Top comments (1)
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'
.