Implementing HSTS Headers on Amazon CloudFront with S3 Origin: A Technical Guide


3 views

When configuring CloudFront distributions with S3 origins, setting HTTP Strict Transport Security (HSTS) headers presents unique challenges since S3 buckets don't natively support response header modifications. The solution requires careful CloudFront configuration rather than S3 bucket settings.

Since June 2022, AWS introduced Response Headers Policies that provide the cleanest solution:


{
    "ResponseHeadersPolicyConfig": {
        "Name": "SecurityHeadersPolicy",
        "SecurityHeadersConfig": {
            "StrictTransportSecurity": {
                "Override": true,
                "AccessControlMaxAgeSec": 63072000,
                "IncludeSubdomains": true,
                "Preload": true
            }
        }
    }
}

For legacy implementations, you can use Lambda@Edge to inject headers:


exports.handler = (event, context, callback) => {
    const response = event.Records[0].cf.response;
    response.headers['strict-transport-security'] = [
        {key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubdomains; preload'}
    ];
    callback(null, response);
};

After implementation, verify with:


curl -I https://yourdistribution.cloudfront.net

Look for the Strict-Transport-Security header in the response.

Remember that HSTS headers are cached by browsers for the specified duration. Start with shorter durations during testing. Also ensure your SSL/TLS configuration meets modern security standards before enabling HSTS.


When serving content via Amazon CloudFront with an S3 origin, many developers encounter limitations when trying to enforce HTTP Strict Transport Security (HSTS) headers. Since S3 buckets don't natively support response header modifications, we need alternative approaches to implement this crucial security feature.

There are two primary methods to implement HSTS for CloudFront distributions with S3 origins:

1. Lambda@Edge Approach

The most flexible solution involves using Lambda@Edge to modify response headers:


exports.handler = (event, context, callback) => {
    const response = event.Records[0].cf.response;
    response.headers['strict-transport-security'] = [{ 
        key: 'Strict-Transport-Security', 
        value: 'max-age=63072000; includeSubDomains; preload' 
    }];
    callback(null, response);
};

2. CloudFront Function Approach

For simpler use cases, CloudFront Functions provide a lightweight alternative:


function handler(event) {
    var response = event.response;
    response.headers['strict-transport-security'] = { 
        value: 'max-age=63072000; includeSubDomains; preload' 
    };
    return response;
}

For the Lambda@Edge solution:

  1. Create a Lambda function in US-East-1 (N. Virginia) region
  2. Deploy the function with appropriate permissions
  3. Associate it with your CloudFront distribution's Viewer Response event

When implementing HSTS:

  • Test with shorter max-age values (e.g., 300 seconds) before final deployment
  • Ensure your certificate validity period exceeds the HSTS max-age
  • Remember that preload list submissions are permanent

After implementation, verify the headers using:


curl -I https://yourdomain.com

Or through browser developer tools by checking the network responses.