159

We're trying to distribute out S3 buckets via Cloudfront but for some reason the only response is an AccessDenied XML document like the following:

<Error>
    <Code>AccessDenied</Code>
    <Message>Access Denied</Message>
    <RequestId>89F25EB47DDA64D5</RequestId>
    <HostId>Z2xAduhEswbdBqTB/cgCggm/jVG24dPZjy1GScs9ak0w95rF4I0SnDnJrUKHHQC</HostId>
</Error>

Here's the setting's we're using:

Distribution Settings Origin Settings

And here's the policy for the bucket

{
    "Version": "2008-10-17",
    "Id": "PolicyForCloudFrontPrivateContent",
    "Statement": [
        {
            "Sid": "1",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity *********"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::x***-logos/*"
        }
    ]
}
11
  • Cache Behavior Settings - imgur.com/JBZqrRm Mar 11, 2014 at 12:32
  • Make sure Cloudfront can read from the S3 bucket.
    – Nathan C
    Mar 11, 2014 at 13:37
  • How would I enable or check this? Mar 11, 2014 at 14:20
  • Origin settings, last option. See your screenshot. :)
    – Nathan C
    Mar 11, 2014 at 14:39
  • I think I tried this earlier and it didn't work but I've just changed it again and it's in the process of distributing. I'll add the bucket's policy to my post :) Mar 11, 2014 at 14:50

8 Answers 8

179

If you're accessing the root of your CloudFront distribution, you need to set a default root object: http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/DefaultRootObject.html

To specify a default root object using the CloudFront console:

  • Sign in to the AWS Management Console and open the Amazon CloudFront console at https://console.aws.amazon.com/cloudfront/.

  • In the list of distributions in the top pane, select the distribution to update.

  • In the Distribution Details pane, on the General tab, click Edit.

  • In the Edit Distribution dialog box, in the Default Root Object field, enter the file name of the default root object.

    Enter only the object name, for example, index.html. Do not add a / before the object name.

  • To save your changes, click Yes, Edit.

5
  • 8
    In my case, this setting has not resolved the issue. I am still getting Access Denied error
    – KurioZ7
    Jul 2, 2019 at 4:56
  • 4
    oh god, why is this not in with any of the aws knowledge answers surrounding this topic! Thank you Feb 21, 2020 at 8:24
  • 1
    For me, the Alternative Domain configuration needed to be set to my domain name in the CloudFront configuration to resolve this issue. Mar 2, 2022 at 15:41
  • Works in my case after specifying index.html as default root object, thanks! Apr 27, 2022 at 9:20
  • In my case it was root object problem.
    – kaxi1993
    Nov 1, 2022 at 13:43
99

I've just had the same issue and while Kousha's answer does solve the problem for index.html in the root path, my problem was also with sub-directories as I used those combined with index.html to get "pretty urls" (example.com/something/ rather than "ugly" example.com/something.html)

Partially it's Amazon's fault as well, because when you set up CloudFront distribution, it will offer you S3 buckets to choose from, but if you do choose one of those it will use the bucket URL rather than static website hosting URL as a backend.

So to fix the issue:

  • Enable static website hosting for the bucket
  • Set the Index (and perhaps Error) document appropriately
  • Copy Endpoint URL - you can find it next to the above settings - It should look something like: <bucket.name>.s3-website-<aws-region>.amazonaws.com
  • Use that URL as your CloudFront Distribution origin. (This will also make the CF Default Root Object setting unnecessary, but doesn't hurt to set it anyway)

UPDATE Jan '22: you can also fix this by keeping static hosting OFF and adding a CloudFront function to append index.html. See this post on SO for more information. This allows you to use an OAI and keep the bucket private.

7
  • Perfect answer as of the date on this comment. Jun 12, 2018 at 13:12
  • That was it for me as well. I already had another website working and thought I configured the new one identically. So easy to overlook this. Sep 1, 2018 at 8:01
  • You also need to add public GetObject and ListObjects permissions to the bucket.
    – Georges
    Sep 25, 2018 at 21:55
  • @Georges how do you add public GetObject and ListObjects permissions to the bucket?
    – Ryan
    Nov 3, 2019 at 20:10
  • @Ryan you can check here docs.aws.amazon.com/AmazonS3/latest/dev/…
    – Kaka Ruto
    Jun 21, 2020 at 21:55
19

I had the same issue as @Cezz, though the solution would not work in my case.

As soon as static website hosting is enabled for the bucket, it means users can access the content either via the Cloudfront URL, or the S3 URL, which is not always desirable. For example, in my case, the Cloudfront distribution is SSL enabled, and users should not be able to access it over a non-SSL connection.

The solution I found was to:

  • keep static website hosting disabled on the S3 bucket
  • keep the Cloudfront distribution origin as an S3 ID
  • set "Restrict Bucket Access" to "Yes" (and for ease, allow CloudFront to automatically update the bucket policy)
  • on "Error Pages", create a custom response, and map error code "403: Forbidden" to the desired response page i.e. /index.html, with a response code of 200

Note though that in my case, I'm serving a single page javascript application where all paths are resolved by index.html. If you've paths that resolve to different objects in your S3 bucket, this will not work.

3
  • 1
    Thanks for your answer. This one worked for me. I had the same problem as you. I didn't want people to access my S3 bucket, so I needed to restrict access to the S3 Origin, which only works with when you fill in the origin as suggested by the auto-complete in Cloudfront. One side note though, you don't have to disable static website hosting. Simply removing the bucket policy which allows public access is enough.
    – Torsten
    Jan 17, 2017 at 3:20
  • This was really helpful, the forbidden message comes from S3 which I didn't realize at first, so you have to catch that with a custom error page so your SPA works.
    – Ivan
    Sep 29, 2017 at 22:58
  • This works for spas (eg react apps) withouts exposing the s3 bucket. Thank you.
    – AArias
    Mar 3, 2022 at 15:25
12

In my case I was using multiple origins with "Path Pattern" Behaviors along with an Origin Path in my S3 bucket:

Bad setup:

CloudFront Behavior: /images/* -> My-S3-origin

My-S3-origin: Origin Path: /images

S3 files: /images/my-image.jpg

GET Request: /images/my-image.jpg -> 403

What was happening was the entire CloudFront GET request gets sent to the origin: /image/my-image.jpg prefixed by Origin Path: /images, so the request into S3 looks like /images/images/my-image.jpg which doesn't exist.

Solution

remove Origin Path.

This allowed me to access the bucket with an origin access identity and bucket permissions and individual file permissions restricted.

1
  • On a related note, I had a CloudFront Distribution with two origins: set Cloudfront to /video/* -> My-S3- May 15, 2020 at 21:01
1

In my case I had configured Route 53 wrongly. I'd created an Alias on my domain but pointed it to the S3 Bucket instead of the CloudFront distribution.

Also I omitted the default root object. The console could really be improved if they add a bit of information to the question mark text about the potential consequences of omitting it.

1

My issue was that I had turned website hosting off and had to change the origin name from the website path to the normal non-website one. That had removed the origin access identity. I put that back and everything worked fine.

0

If block public access is On and Hosting disabled, you need to setup Error Pages with appropriate HTTP error code and HTTP response code in CF.

1
  • Hi user2242291! Can you clarify how this builds on the other accepted answers?
    – shearn89
    Jan 7, 2022 at 9:16
0

If your origin is setup with "Origin access control settings (recommended)" Check that the origin has "Signing behavior" set to "Always sign requests".

Also, check that the provided policy has been added to the bucket on the "Permissions" tab.

Origin configuration:

enter image description here

Origin access configuration:

enter image description here

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .