15

If I clear my browser cache, everything loads just find from my cloudfront-enabled S3 bucket. When I turn off cache, however, I get errors in the console:

Image from origin [ORIGIN URL] has been blocked from loading by Cross-Origin Resource Sharing policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin [MY LOCALHOST ADDRESS] is therefore not allowed access.

MY CORS configuration:

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
        <AllowedHeader>*</AllowedHeader>
    </CORSRule>
</CORSConfiguration>

I also followed this advice a while back and changed the cloundfront distro settings. It seemed to have worked back then but is definitely not working with browser cache now: CORS problems with Amazon S3 on the latest Chomium and Google Canary

I also tried putting "Header add Access-Control-Allow-Origin "*"" in my websites .htaccess. No luck. Note: my website is hosted and accessed from localhost (it's a dev environment).

Community
  • 1
  • 1
Chris Scott
  • 583
  • 1
  • 7
  • 23

2 Answers2

29

I found myself with the same sort of problem: no Access-Control-Allow-Origin coming up. It was very random, sometimes it worked, other times it did not. I finally narrowed it down in this way:

  1. Turned on S3 website hosting
  2. Tested for CORS header in both S3 and CloudFront

Here is how to easily test for a CORS header:

curl -i -H "Origin: http://YOUR-SITE-URL" http://S3-or-CLOUDFRONT-URL | grep Access

In my case it would work fine in S3, but in CloudFront it will only sometimes return back the access-control headers:

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET
Access-Control-Max-Age: 3000

After more research, I discovered that our CloudFront distribution was configured to block the headers from going to S3. To fix this:

  1. Go to CloudFront distribution in the AWS dashboard
  2. Click on Distribution Settings
  3. Click on the Behaviors Tab
  4. Edit the default pattern Behavior
  5. Click on Forward Headers and select Whitelist
  6. Add the 3 suggested headers: Access-Control-Request-Headers, Access-Control-Request-Method, Origin
  7. Save changes

Once the headers made it to S3, we could always see the correct access control information with curl command above.

CharlieH
  • 1,432
  • 2
  • 12
  • 19
  • 3
    Probably this is the most complete answer regarding this topic on Stackoverflow, but it's still not working for me. It seems that Cloudfront only Forward Headers from my Subdomains (eg.: www.myapp.com), but it doesn't to my domain (myapp.com) - if anyone knows why have a look here: https://stackoverflow.com/questions/45528115/cloudfront-cors-only-works-for-subdomain – Eduardo Almeida Aug 06 '17 at 03:04
  • I had to add `Access-Control-Allow-Origin` and `Access-Control-Allow-Methods` to the headers but this approach worked. Basically, you need to include the headers that you are sending in your pre-flight requests to be passed through the cloudfront distribution. Great answer, thank you! – Matt Dodge Feb 21 '18 at 22:21
  • 14
    Also FYI, the section isn't called "Forward Headers" anymore, it's now "Cache Based on Selected Request Headers" then select "Whitelist" – Matt Dodge Feb 21 '18 at 22:22
  • This doesn't always work for me, I have been having this issue for weeks now, sometimes the images don't load and I see a CORS error on the console. It's not easy to reproduce this bug. – BrunoLM Jul 01 '19 at 17:41
4

I was stuck in the same problem and found that exposing headers as shown below solve the problem:

<CORSConfiguration>
  <CORSRule>
    <AllowedOrigin>MYIP</AllowedOrigin>
    <AllowedMethod>PUT</AllowedMethod>
    <AllowedMethod>POST</AllowedMethod>
    <AllowedMethod>DELETE</AllowedMethod>
    <AllowedMethod>PUT</AllowedMethod>
    <ExposeHeader>ETag</ExposeHeader>
    <AllowedHeader>*</AllowedHeader>
  </CORSRule>
</CORSConfiguration>
  • MYIP format: for my local development machine I used : http://localhost:3000 as it specifies origin from where request is triggering. – Anurag Pratap Nov 27 '15 at 09:59
  • Oddly the problem spontaneously stopped happening (before I implemented this solution). But I will try this if it starts acting up again. – Chris Scott Nov 28 '15 at 01:56
  • I had the problem again, implementing your solution and it seems to have worked. I marked your answer as correct. Thank you! – Chris Scott Nov 29 '15 at 17:38
  • Spoke to soon. I am getting the errors again. Are there other tags I should include, other than, ExposeHeader? – Chris Scott Nov 29 '15 at 18:10
  • I don't think any other tag is required.Please ensure following things: * Format of origin is not correct. * You specify CORS for each bucket you are using. – Anurag Pratap Nov 30 '15 at 05:14
  • Can you elaborate on what you mean by "Format of origin is not correct"? – Chris Scott Dec 01 '15 at 03:13
  • 1
    Thanks for the ETag header exposure that did the trick for me. I saw it in the documentation somewhere but was unable to locate it again. I would like to point out in your example code you have the "PUT" twice. Maybe one should be "GET"? – Todd Feb 11 '20 at 16:18