Search code examples
amazon-web-servicesamazon-s3cors

AWS: How can I allow multiple domains in an S3 CORS configuration?


I've been having an issue across many of my sites that rely on S3 as an origin for Cloudfront. However, I'm having issues with allowing multiple domains (instead of a global * allowed).

I have followed the documentation here (first config). And found a few other random SO or forum answers here and there (second config)

Any help is appreciated.

I have setup CORS Rules that look like both of the following:

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
        <AllowedOrigin>https://example.com</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <AllowedMethod>HEAD</AllowedMethod>
        <AllowedMethod>DELETE</AllowedMethod>
        <AllowedMethod>PUT</AllowedMethod>
        <AllowedMethod>POST</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
        <AllowedHeader>Authorization</AllowedHeader>
    </CORSRule>
    <CORSRule>
        <AllowedOrigin>http://example.com</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <AllowedHeader>*</AllowedHeader>
    </CORSRule>
    <CORSRule>
        <AllowedOrigin>https://staging.example.com</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <AllowedHeader>*</AllowedHeader>
    </CORSRule>
    <CORSRule>
        <AllowedOrigin>http://example.dev</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <AllowedHeader>*</AllowedHeader>
    </CORSRule>
</CORSConfiguration>

AND

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
        <AllowedOrigin>https://example.com</AllowedOrigin>
        <AllowedOrigin>http://example.com</AllowedOrigin>
        <AllowedOrigin>https://staging.example.com</AllowedOrigin>
        <AllowedOrigin>http://example.dev</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <AllowedMethod>HEAD</AllowedMethod>
        <AllowedMethod>DELETE</AllowedMethod>
        <AllowedMethod>PUT</AllowedMethod>
        <AllowedMethod>POST</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
        <AllowedHeader>Authorization</AllowedHeader>
    </CORSRule>
</CORSConfiguration>

I keep getting the font origin error on all sites except https://example.com:

Font from origin 'http://CLOUDFRONTURL' has been blocked from loading by Cross-Origin Resource Sharing policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://example.dev' is therefore not allowed access.

AND

Font from origin 'http://CLOUDFRONTURL' has been blocked from loading by Cross-Origin Resource Sharing policy: The 'Access-Control-Allow-Origin' header has a value 'https://example.com' that is not equal to the supplied origin. Origin 'http://example.dev' is therefore not allowed access.


Solution

  • CloudFront caches objects based the all of the request headers that it has forwarded from the browser to the origin server -- not just the path.

    For a response to be served from the cache, it must have been returned in response to a previous request that involved exactly the same request headers.

    This is because, in principle at least, different headers can trigger different behavior by the server, and a well-behaved cache is not at liberty to assume otherwise.

    To increase the cacheability of objects without compromising its ability to serve correct responses (that is, identical response the origin server would have returned for a given request), CloudFront strips almost of the request headers before forwarding the request to the origin, and uses the stripped version of the request when doing cache lookups.

    When the origin server is a "Custom" (i.e., not S3) origin, you can choose which headers to forward to the origin server.

    But when the origin server is S3, you still have choices, but there are only three that can be optionally forwarded... and they are all CORS related.

    [With an S3 origin,] you can configure CloudFront to forward and to cache your objects based only on three headers: Access-Control-Request-Headers, Access-Control-Request-Method, and Origin. Forwarding these headers allows CloudFront to distribute content for websites that are enabled for cross-origin resource sharing (CORS). You can't configure CloudFront to forward custom headers to Amazon S3.

    http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/header-caching.html#header-caching-web

    If the Origin: header, at least, doesn't get forwarded, then S3 will not be able to react to it. Enabling forwarding of this header means that not only will S3 see it, and potentially modify its response because of the CORS configuration on the bucket, but also that each variation of Origin: -- for the same object -- will result in a different (and correct) response being returned by S3 and cached for future matching requests by CloudFront.

    Custom headers can't be forwarded to S3 by CloudFront because this would serve no purpose -- since S3 stores static content, responses wouldn't vary on other headers, so forwarding them would be pointless and would reduce the cache hit rate, with many (supposedly) different responses being cached, but only being served in response to requests that were accompanied by identical headers.