AWS's CloudFront system is an extremely useful tool to ensure the speed of delivery of static and dynamic content on the web.
It is the entry point to your web applications, and delivers cached content coming from a data center close to your location, in an ideal case (the so-called edge-location).
One of the main things we have seen being forgotten in more than 75% of our observed cases is the inclusion of security headers in the CloudFront responses. You can read more on the OWASP website about these headers: https://owasp.org/www-project-secure-headers/, and also the Mozilla recommendations .
If the content would be static throughout, it would not be too much of an issue. But when a website with a login-portal is being served via CloudFront, the inclusion of these security headers becomes crucial to prevent clickjacking and iframe attacks. And that is where we have seen the issue come up.
As with many things, people are expecting the cloud provider to take care of it, but they have it written clear in the documentation that this is something in the hands of the developers (see documentation ).
So, how to include those headers? We will go through some examples for CloudFormation and Terraform The only CloudFront example of CloudFormation templates in AWS actually has security headers included through a lambda function, as you can see here.
An alternative way is to define the resource `ResponseHeadersPolicyId` in all `CacheBehavior` elements and in the `DefaultCacheBehavior` inside the distribution config, as per the documentation. Some pre-made ids for policies are to be found here.
For simplicity, we recommend in general to go the latter route and have a `ReponseHeaderPolicyId` instead of a lambda function.
Here is a full code example in TerraForm which shows the correct use by using the managed security headers policy, altered from the TerraForm documentation:
resource "aws_cloudfront_distribution" "s3_distribution" {
origin {
domain_name = aws_s3_bucket.b.bucket_regional_domain_name
origin_id = local.s3_origin_id
s3_origin_config {
origin_access_identity = "origin-access-identity/cloudfront/ABCDEFG1234567"
}
}
enabled = true
is_ipv6_enabled = true
comment = "Some comment"
default_root_object = "index.html"
logging_config {
include_cookies = false
bucket = "mylogs.s3.amazonaws.com"
prefix = "myprefix"
}
aliases = ["mysite.example.com", "yoursite.example.com"]
default_cache_behavior {
allowed_methods = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"]
cached_methods = ["GET", "HEAD"]
target_origin_id = local.s3_origin_id
forwarded_values {
query_string = false
cookies {
forward = "none"
}
}
viewer_protocol_policy = "redirect-to-https"
min_ttl = 0
default_ttl = 3600
max_ttl = 86400
response_headers_policy_id = "67f7725c-6f97-4210-82d7-5512b31e9d03"
}
ordered_cache_behavior {
path_pattern = "/content/immutable/*"
allowed_methods = ["GET", "HEAD", "OPTIONS"]
cached_methods = ["GET", "HEAD", "OPTIONS"]
target_origin_id = local.s3_origin_id
forwarded_values {
query_string = false
headers = ["Origin"]
cookies {
forward = "none"
}
}
min_ttl = 0
default_ttl = 86400
max_ttl = 31536000
compress = true
viewer_protocol_policy = "redirect-to-https"
response_headers_policy_id = "67f7725c-6f97-4210-82d7-5512b31e9d03"
}
}
We compared CoGuard’s scans, which include a check for this required security setting, with the results of other tools that focus on Terraform specifically, and found that it is not included. For a comprehensive scan of your full IT infrastructure by CoGuard, contact us today info@coguard.io. All it takes is one missing security step to put your IT infrastructure’s security and stability at risk.