AWS CloudFront access denied to S3 bucket
Asked Answered
A

16

88

I am trying to setup CloudFront to serve static files hosted in my S3 bucket. I have setup distribution but I get AccessDenied when trying to browse to the CSS (/CSS/stlyle.css) file inside S3 bucket:

<Error>
    <Code>AccessDenied</Code>
    <Message>Access Denied</Message>
    <RequestId>E193C9CDF4319589</RequestId>
    <HostId>
xbU85maj87/jukYihXnADjXoa4j2AMLFx7t08vtWZ9SRVmU1Ijq6ry2RDAh4G1IGPIeZG9IbFZg=
    </HostId>
</Error>

I have set my CloudFront distribution to my S3 bucket and created new Origin Access Identity policy which was added automatically to the S3 bucket:

{
    "Version": "2008-10-17",
    "Id": "PolicyForCloudFrontPrivateContent",
    "Statement": [
        {
            "Sid": "1",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity E21XQ8NAGWMBQQ"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::myhost.com.cdn/*"
        }
    ]
}

Did I miss something?

I want all my files in this S3 bucket be served via CloudFront...

*** UPDATE ***

This cloud front guide says:

By default, your Amazon S3 bucket and all of the objects in it are private—only the AWS account that created the bucket has permission to read or write the objects in it. If you want to allow anyone to access the objects in your Amazon S3 bucket using CloudFront URLs, you must grant public read permissions to the objects. (This is one of the most common mistakes when working with CloudFront and Amazon S3. You must explicitly grant privileges to each object in an Amazon S3 bucket.)

So based on this I have added new permissions to all objects inside S3 bucket to Everyone Read/Download. Now I can access files.

But now when I access the file like https://d3u61axijg36on.cloudfront.net/css/style.css this is being redirected to S3 URI and HTTP. How do I disable this?

Absorbed answered 15/2, 2017 at 14:13 Comment(3)
The redirection might be temporary forums.aws.amazon.com/message.jspa?messageID=677452Monoclinous
I have come across that topic myself. Still waiting to see if this is the case...Absorbed
Your update is the most confusing thing ever! Not a jab at you - more at amazon. Why must my objects be public if I have declared an OAI, changed the policy for that OAI, and have my bucket as private - as I want it to not be publicly accessible?! Makes no sense to me. Will they be private if the bucket is private and the objects are public?Jubilate
C
100

To assist with your question, I recreated the situation via:

  • Created an Amazon S3 bucket with no Bucket Policy
  • Uploaded public.jpg and make it public via "Make Public"
  • Uploaded private.jpg and kept it private
  • Created an Amazon CloudFront web distribution:
    • Origin Domain Name: Selected my S3 bucket from the list
    • Restrict Bucket Access: Yes
    • Origin Access Identity: Create a New Identity
    • Grant Read Permissions on Bucket: Yes, Update Bucket Policy

I checked the bucket, and CloudFront had added a Bucket Policy similar to yours.

The distribution was marked as In Progress for a while. Once it said Enabled, I accessed the files via the xxx.cloudfront.net URL:

  • xxx.cloudfront.net/public.jpg redirected me to the S3 URL http://bucketname.s3.amazonaws.com/public.jpg. Yes, I could see the file, but it should not use a redirect.
  • xxx.cloudfront.net/private.jpg redirected me also, but I then received Access Denied because it is a private file in S3.

I then did some research and found that this is quite a common occurrence. Some people use a workaround by pointing their CloudFront distribution to the static hosted website URL, but this has the disadvantage that it will not work with the Origin Access Identity and I also suspect it won't receive the 'free S3 traffic to the edge' discount.

So, I waited overnight, tested it this morning and everything is working fine.

Bottom line: Even if it says ENABLED, things might take several hours (eg overnight) to get themselves right. It will then work as documented.

Chough answered 16/2, 2017 at 21:31 Comment(11)
What wasn't obvious to me is that the cloudfront url does NOT include the bucket name. i.e. 'xxxx.cloudfront.net/:path' and NOT 'xxxx.cloudfront.net/bucketname/:path'Callant
If I could have upvoted this twice, I would have. This stuff has cost me hours of my life.Johnie
@john-rotenstein I'm not following your answer. If I make objects in my bucket public, I can access them via my CloudFront distribution URL. That's great! But I can also then access them directly via the S3 URL. I implemented an OAI so that only my CloudFront dist can read my objects and no one else can. I don't understand the use of that if my objects are public. Have I misunderstood your answer? Can I provide any more information to clarify my question?Circumjacent
@shea -- This is an old question. If you have something to ask, please create a new question rather than asking in a comment.Chough
@Circumjacent I'm learning CloudFront and came to the same doubt.... AWS docs does mention that S3 objects have to be made public for CloudFront to work (in addition to policy/ACL permission grant to OAI), though it doesn't explain why. From my experiment, it seems that setting bucket permission to deny action "s3:GetObject" does prevent access to resources through S3 URL, without affecting CloudFront's ability to access bucket. However, I haven't figure out is GetObject the only effect of "make public", i.e. is there any other actions that need to be included in the rule to nullify "make public".Whitmer
I'm getting another behaviour different from my earlier comment. Previously, I was getting permission denied (via CloudFront) if I didn't set objects as public on S3. Now... after few hours, when testing with few more objects, it works even if I don't set them as public. I'm afraid info in the docs is outdated, hope the behaviour will be consistent.Whitmer
I had to wait 3 hr for the 403 error to clear out. Hell, I wonder if there's anything you can do to speed the process up. I can't imagine what I would have felt if my resource was critical to prod.Euphrates
If you see that cloudfront is redirecting you to the s3 asset (check your url after entering the cloudfront domain), then this (waiting a few hours) is very likely the solution.Revis
Waiting a few hours for private content to appear using Cloudfront OAI + S3 works!! This is the best answer. In my case, I waited for about 2-3 hours. It is indeed weird that there is this difference in behavior between public and private image. I think Cloudfront should not indicate the distribution as enabled before enabling the private content access too.Gynecocracy
"So, I waited overnight, tested it this morning and everything is working fine." — As sad as it is, waiting did solve the issue...Horn
index.html in Default Root Object use this and it will workPringle
L
100

I added index.html in Default Root Object under General tab of cloudFront Distribution Settings and it worked for me. As index.html was the root file for my project!

Lolitaloll answered 10/6, 2018 at 8:46 Comment(12)
bless you. I was pulling my hair out on this, and adding the root object fixed it!Brittain
This is the thing to check if the S3 bucket endpoint is using API-style. Even though it says "Access Denied", it's not truly a permissions error - it's that you're asking for a resource that doesn't technically exist.Hileman
make sure it's index.html NOT /index.htmlChoreography
This worked for me. Even though this file was specified under S3, it was needed here too.Giffin
I banged my head for a whole day until I saw your answer. Thank you!Oscillatory
These are things that keep suggesting me "leave all this stuff and go farming".Azaleeazan
Does index.html actually have the list of objects in the bucket or am I being too optimistic?Qktp
Wow, life saver. And make sure to be patient. It took about 30 seconds for things to propagate or whatever needed to happen for it to work (which is why I originally thought setting this "optional" field wasn't a fix), but yes, telling it that the index.html is the Default Root Object fixed it for me.Entertainer
Great !. Worked for meEyrie
Thanks you so much bro you are live saverValenba
after wasting 3 days on this, you saved me from more torture. God bless :)Zarate
Check out the answer below. For me, this answer was a bandaid that only worked for the root dir. The solution below (being sure your cloudfront origin type is "s3 static website") worked for all urls. https://mcmap.net/q/236645/-aws-cloudfront-access-denied-to-s3-bucketSpectacular
A
28

Instead of choosing default s3 bucket for Origin Domain Name, please enter the <bucket-name>.s3-website.<region>.amazonaws.com as origin Domain Name(You can get this URL at Static website hosting property under S3 bucket properties).

Amadoamador answered 11/6, 2018 at 14:49 Comment(0)
M
9

This can happen if you are using a bucket that has just been newly created.

According official reply here: AWS Forun link, you have to wait for a couple of hours after creating a new bucket before you can have cloud front distribution working on it correctly.

Solution is to temporarily work from one of your old buckets and switch to the new bucket a couple of hours later.

Martyrology answered 13/5, 2020 at 7:33 Comment(2)
Massively under-rated answerMeritorious
I can confirm this is still an issue. I created the CloudFront and S3 configuration as per the official guide, it didn't work. Then I left for the day, without changing anything the next morning it just works.Herrera
V
6

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.

Voroshilovgrad answered 8/11, 2017 at 1:8 Comment(1)
If anyone has this issue, consider clearing your cdn cache change bucket policy "it will be updated if you go from empty to /xy origin name...Keesee
S
4

As an AWS novice, I encountered a similar problem after following a tutorial to set up a public S3 bucket. I wanted my S3 bucket to be private and have CloudFront serve the files. I set up an OAI and turned on Block all public access, only to receive AccessDenied errors on all my CloudFront URLs.

My problem was that I had created two conflicting statements in my S3 bucket policy: one when I set up the public bucket following the tutorial, and the other that was generated automatically when I set up the OAI and selected Update bucket policy:

{
    "Version": "2012-10-17",
    "Id": "Policy1620442091089",
    "Statement": [
        {
            "Sid": "Stmt1620442087873",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::my-s3-bucket/*"
        },
        {
            "Sid": "2",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity XXXXXXXXXXXXXX"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::my-s3-bucket/*"
        }
    ]
}

Removing the top statement solved my AccessDenied errors. Hopefully this helps someone new to AWS. It wasn't immediately obvious to me to check for conflicting statements.

Stocker answered 16/6, 2022 at 0:51 Comment(0)
P
2

See 100% working solution...

It can be only solve at cloudFront panel by adding error response rule.

See Solution here - react router doesn't work in aws s3 bucket

Pregnable answered 23/3, 2022 at 17:54 Comment(0)
D
1

I also got 403 from CloudFront but my issue was a bit different so sharing it here as it might help others.

Make sure the Origin Access Id you've defined as part of the bucket policy is the right one:

{
    "Version": "2008-10-17",
    "Id": "PolicyForCloudFrontPrivateContent",
    "Statement": [
        {
            "Sid": "1",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity HERE_GOES_YOUR_ORIGIN_ACCESS_ID"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::deepen-frontend-prod/*"
        }
    ]
}

An Origin Access Identity Id roughly looks like E19F48VV5H01ZD.

You can find all of your origin access identities on https://console.aws.amazon.com/cloudfront/home#oai Look for the one you're using in your CloudFront config under Your Identities: enter image description here

Discovert answered 18/11, 2020 at 10:57 Comment(0)
I
1

It worked for me once I added index.html to the Default Root Object under the General tab of cloudFront Distribution Settings.

Indentation answered 22/4, 2022 at 9:26 Comment(1)
it's a duplicate of other answear.Oddfellow
I
1

For me using OAC and adding the policy for a bucket with disabled public access did not work. I followed all the tutorials and checked every possible problem. The only thing that helped was using a legacy OAI setting, instead of OAC as aws suggests

Interdisciplinary answered 19/3, 2023 at 12:33 Comment(0)
S
0

add this in Bucket policy

    {
        "Sid": "2",
        "Effect": "Allow",
        "Principal": {
            "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ESDK2T2CSNT57"
        },
        "Action": "s3:GetObject",
        "Resource": "arn:aws:s3:::{Bucket name }/*"
    }
Supertanker answered 15/2, 2022 at 15:29 Comment(0)
B
0

Making the objects in the S3 bucket public-read is the fastest way to achieve this. However this is not recommended. Rather create a origin_access_identity under the s3 orgin policy and grant this identity access to the S3 bucket using a bucket policy. That way you can keep all the objects private.

Biondo answered 16/2, 2022 at 10:37 Comment(1)
I did this. Still having a 403 for root objects!Jubilate
M
0

You can point cloud front to use s3 bucket or you can host your s3 bucket as a static website and point Cloud Front to a Static website URL.

  1. When you are pointing CloudFront to s3 bucket

    • I used OAI as prescribed here. It works for me.

enter image description here

enter image description here

enter image description here

  • However, please note that you cannot access the root without mentioning a root document.

  • append /existingfile.html to url and see whether you can access any document by full url. If not you need check your permissions issues mostly at s3 bucket. Follow above URL.

  • you need to provide a default root document (index.html or something like that).. Otherwise, your root will be denied access.

  1. When you want to use s3 the static website. Do not choose S3 origin from the available list. Rather copy and paste S3 static root. In this case, the Origin has to be the exact URI given in the Static website hosting of the bucket. NOTE that This is different from the list very similar bucket name given in options while creating cloud front distribution.

Before creating a cloud front distribution make sure the website is working via this URL.

enter image description here

Mcmorris answered 11/6, 2022 at 4:6 Comment(0)
G
0

When you visit http://mywebsite.com, the request hits the index.html file in S3. If you then click a button and go to http://mywebsite.com/stats, which is an internal route of your SPA app, it won't trigger any backend request. However, if you reload the page, http://mywebsite.com/stats will be sent to S3 because your browser doesn't recognize that you're using an SPA frontend.

S3 will respond with a 403 error, providing the index.html, and Cloudfront will relay the error.

The solution is to use an edge lambda function in Cloudfront. Here an example:

function handler(event){
   // Check if the request is for an internal route (doesn't have a file extension)
  if (!event.request.uri.includes('.')) {
      event.request.uri = '/index.html'; 
  }

  return event.request;
}
Geniculate answered 6/10, 2023 at 13:42 Comment(0)
H
0

I was getting AccessedDenied because my bucket policy wasn't granting the CloudFront service proper permissions required when you use OAC over OAI with a private bucket. This was due to me adding the permissions to an existing bucket which is a known bug in CDK.

I was defining the policy on the existing bucket like so:

bucket.addToResourcePolicy(new PolicyStatement({
  effect: Effect.ALLOW,
  actions: ["s3:GetObject", "s3:ListBucket"],
  resources: [bucket.arnForObjects("*")],
  principals: [new ServicePrincipal("cloudfront.amazonaws.com")],
  conditions: {
    StringEquals: {
      "aws:SourceArn": `arn:aws:cloudfront::<accouunt>:distribution/${distribution.distributionId}`,
    },
  },
}));

Because the bucket already existed the policy was simply ignored. I didn't realize this until reviewing everything in the console where I saw the bucket policy was missing the statement above.

I followed these instructions to work around this issue:

const cloudfrontPolicy = new PolicyStatement({
  effect: Effect.ALLOW,
  actions: ["s3:GetObject", "s3:ListBucket"],
  // resources: [bucket.arnForObjects("*")],
  resources: [`arn:aws:s3:::${bucketName}`, `arn:aws:s3:::${bucketName}/*`],
  principals: [new ServicePrincipal("cloudfront.amazonaws.com")],
  conditions: {
    StringEquals: {
      "aws:SourceArn": `arn:aws:cloudfront::<account>:distribution/${distribution.distributionId}`,
    },
  },
});
const denyUnsecureConnectionPolicy = new PolicyStatement({
  effect: Effect.DENY,
  actions: ["s3:*"],
  resources: [`arn:aws:s3:::${bucketName}`, `arn:aws:s3:::${bucketName}/*`],
  principals: [new AnyPrincipal()],
  conditions: {
    Bool: {
      "aws:SecureTransport": "false"
    },
  },
});
const bucketPolicy = new BucketPolicy(
  this,
  "cloudfrontAccessBucketPolicy",
  {
    bucket: bucket,
  }
);
bucketPolicy.document.addStatements(cloudfrontPolicy, denyUnsecureConnectionPolicy);

Note that this approach will delete any existing policy you have on the bucket. This required me to replicate the existing policy (DENY defined above) for it to stick.

I also had to be explicit about the resources I was targeting. This wouldn't work:

resources: [bucket.arnForObjects("*")],

But this did:

resources: [`arn:aws:s3:::${bucketName}`, `arn:aws:s3:::${bucketName}/*`],
Hyphen answered 7/6 at 10:34 Comment(0)
I
0

In case someone ends up here in the future, OAC (Origin Access Control) is now the recommended way to set up a CloudFront Distribution in front of static content in an S3 bucket.

In my situation, I just wanted to serve all the images for my website from S3 through CloudFront so that they'd be cached.

These AWS instructions are a good place to start if you want to start from scratch.

However, after going through these instructions, I was still get AccessDenied errors (even after waiting several hours).

Turns out, I clicked the wrong option when creating my OAC policy. When you get to this step, you click this button...

enter image description here

And it will pop up a new window to create an OAC. Make sure the "Sign requests" option is checked!

enter image description here

That will let S3 know for sure that the request is coming from CloudFront so that the bucket policy they give you in the next step will apply correctly.

If you have already created this OAC without checking the right option, you can modify it by going to

Main CloudFront left-hand menu --> Security --> Origin access

Then you can click the box next to your OAC and click the Edit button.

Hope this answer helps someone else!

Imparisyllabic answered 24/6 at 22:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.