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

3

12

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.

Fluoric answered 5/1, 2016 at 15:25 Comment(5)
Is the CloudFront distribution configured to whitelist the Origin request header?Swarthy
@Michael-sqlbot I'm not sure where to check that. Editing the Origin doesn't yield anything related to whitelisting origin request header.Fluoric
It's a cache behavior setting, rather than an origin setting; see docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/…Swarthy
ok, it's whitelisted now. I guess we'll see once the cache clears up and the deployment is back to status deployedFluoric
@Michael-sqlbot please add as answer. This worked.Fluoric
S
7

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.

Swarthy answered 7/1, 2016 at 2:22 Comment(1)
I understand the explanation, but it's not clear (maybe because English is not my native languag) what is the conclusion here is it 1) a conclusion that yes it is not possible with cloudfront to have several Origin , even though the S3 bucket allows it 2) it is possible but one has to do some specific manipulationRattail
K
10

Background: Your Setup

  • Let's say you have domain A (e.g. dev.mydomain.com) and domain B (e.g. www.mydomain.com).
  • Your CDN is at cdn.mydomain.com which is on CloudFront and points to a private S3 bucket.
  • Files (e.g. /fonts/myfont.woff, which needs CORS, per MDN) are accessible when you request them from www.mydomain.com via https://cdn.mydomain.com/fonts/myfont.woff. (See my answer here on how to set it up, up to this point.)

Requirements (for this question only)

  • You want the file to be accessible on cdn.mydomain.com/fonts/myfont.woff only when the page that requests it (i.e. Origin header) is either dev.mydomain.com or www.mydomain.com.
  • You do NOT want the file to be accessible when junk-cheap.com loads your font file on this page (via your CDN URL), to save on his own bandwidth/hosting cost; not to mention phishing and such risks!

The problem

By default CloudFront caches the response for any incoming request. That's the whole point of CDN.

However, the first time (after an Invalidation) that a request comes from any of the two domains for a certain file (say /fonts/myfont.woff), CloudFront caches the response for this file as { "/fonts/myfont.woff": "<this response object with headers>"}. So the cache-key is by default almost only the path.

Now, when a request from domain B comes for the same file, the "allowed domain" of the cached response of the object is for domain A, and this mismatch results in a CORS error.

Solution

One simple solution would be telling CloudFront to incorporate Origin into the cache key. So, in the above example the cache would be like { ["/fonts/myfont.woff", "Origin: www.mydomain.com"]: <response for www.mydomain.com only>, ... }.

You can accomplish this by creating a new Cache Policy that takes in the Origin header:

enter image description here

and then set it up on your Behavior.

enter image description here

Now, invalidate the distribution and try again! It should work. :)

Good luck!

Kraul answered 19/5, 2021 at 20:42 Comment(0)
S
7

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.

Swarthy answered 7/1, 2016 at 2:22 Comment(1)
I understand the explanation, but it's not clear (maybe because English is not my native languag) what is the conclusion here is it 1) a conclusion that yes it is not possible with cloudfront to have several Origin , even though the S3 bucket allows it 2) it is possible but one has to do some specific manipulationRattail
N
0

In 2024

In reference to the prior responses, I resolved the issue by setting the Origin header as a cache key in CloudFront. MDN documentation on CORS helped clarify the concept.

Here's the solution:

  1. In S3:

    • Set AllowedOrigins with multiple domains in your CORS configuration.
  2. In CloudFront:

    • Add the Origin header to your cache key policy. After setting it, you can check if the Vary header includes the Origin directive in the response headers.

This approach ensures that CloudFront caches responses separately for each origin (e.g., dev.example.com, staging.example.com, and www.example.com), allowing proper CORS behavior across multiple domains.

Names answered 10/7 at 7:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.