Skip to content

Instantly share code, notes, and snippets.

@josephabrahams
Created October 25, 2019 17:07
Show Gist options
  • Save josephabrahams/86c384710435ccf4758d81018c2bb3f1 to your computer and use it in GitHub Desktop.
Save josephabrahams/86c384710435ccf4758d81018c2bb3f1 to your computer and use it in GitHub Desktop.
Use λ to Fix CloudFront/S3 CORS Issues

Use Lambda to Fix CloudFront/S3 CORS Issues

If you use S3 to serve static assets, you're going to have to configure S3 to deal with CORS issues. Unfortuantly, S3 doesn't return Vary: Origin unless an Origin request header is present. This causes CORS issues for browsers like Chrome since the original cached response from the GET request will get reused for CORS evaluation due to the lack of Vary: Origin.

The solution is to use a Lambda@Edge function to add the correct response headers from S3.

Steps to set up Lambda/CloudFront/S3:

  1. Make/update and S3 bucket and set the CORS policy to s3_cors_policy.xml.
  2. Create a Lambda function with the code in index.js.
    • Create a new role using the default Lambda role.
    • Modify the trust policy on the role use trust_policy.json.
    • Publish a version of the lambda function.
    • Copy the Lambda ARN (make sure it included the version number)
  3. Create a CloudFront distro with your S3 bucket as the origin.
    • Cache GET, HEAD, & OPTIONS requests
    • Whitelist the Origin, Access-Control-Request-Headers, and Access-Control-Request-Method headers.
    • Add the Lambda ARN copied above to the CloudFront Origin Response Event.
  4. Curl an asset from the distro and confirm that Vary: Origin, Access-Control-Request-Headers, Access-Control-Request-Method is present for GET requests.

Information:

'use strict';
// If the response lacks a Vary: header, fix it in a CloudFront Origin Response trigger.
// Attribution: https://forums.aws.amazon.com/thread.jspa?messageID=796312&#796312
exports.handler = (event, context, callback) => {
const response = event.Records[0].cf.response;
const headers = response.headers;
if (!headers['vary']) {
headers['vary'] = [
{ key: 'Vary', value: 'Origin' },
{ key: 'Vary', value: 'Access-Control-Request-Headers' },
{ key: 'Vary', value: 'Access-Control-Request-Method' },
];
}
callback(null, response);
};
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>GET</AllowedMethod>
</CORSRule>
</CORSConfiguration>
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"lambda.amazonaws.com",
"edgelambda.amazonaws.com"
]
},
"Action": "sts:AssumeRole"
}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment