I’m using an S3 REST API endpoint as the origin of my CloudFront distribution. Why am I getting 403 Access Denied errors?

11 minute read
-1

I'm using an Amazon Simple Storage Service (Amazon S3) bucket as the origin of my Amazon CloudFront distribution. I'm using the S3 REST API endpoint as the origin domain name. CloudFront is returning 403 Access Denied errors from Amazon S3.

Short description

To troubleshoot Access Denied errors, determine if your distribution’s origin domain name is an S3 website endpoint or an S3 REST API endpoint. Follow these steps to find the endpoint type:

1.    Open the CloudFront console.

2.    Select your CloudFront distribution. Then, choose Distribution Settings.

3.    Choose the Origins and Origin Groups tab.

4.    Review the domain name under Origin Domain Name and Path. Then, determine the endpoint type based on the format of the domain name. REST API endpoints use these formats:

DOC-EXAMPLE-BUCKET.s3.region.amazonaws.com 
DOC-EXAMPLE-BUCKET.s3.amazonaws.com

Important: The format bucket-name.s3.amazonaws.com doesn't work for Regions launched in 2019 or later. Static website endpoints use this format:

DOC-EXAMPLE-BUCKET.s3-website-us-east-1.amazonaws.com

If your distribution is using an S3 static website endpoint, you might receive 403 Access Denied errors. For more information, see I’m using an S3 website endpoint as the origin of my CloudFront distribution. Why am I getting 403 Access Denied errors?

If your distribution is using a REST API endpoint, then verify that your configurations meet the following requirements to avoid Access Denied errors:

  • If you don't configure either origin access control (OAC) or origin access identity (OAI), then the objects must be publicly accessible. Or, you must request the objects with AWS Signature Version 4.
  • If the S3 bucket contains objects encrypted by AWS Key Management Service (AWS KMS), then OAC should be used instead of OAI.
  • The S3 bucket policy must allow access to s3:GetObject.
  • If the bucket policy grants access, then the AWS account that owns the S3 bucket must also own the object.
  • The requested objects must exist in the S3 bucket.
  • If clients request the root of your distribution, then you must define a default root object.
  • If you configured an OAI, then the OAI must be included in the S3 bucket policy.
  • If you configured an OAC, then the CloudFront service principal must be included in the S3 bucket policy. If you configured an OAI, then the OAI must be included in your S3 bucket policy.
  • If you don't configure either OAC or OAI, then Amazon S3 Block Public Access must be turned off on the bucket.

Resolution

If you don't configure either OAC or OAI, then your objects must be publicly accessible or requested with AWS Signature Version 4.

To determine if the objects in your S3 bucket are publicly accessible, open the S3 object's URL in a web browser. Or, run a curl command on the URL.

The following is an example URL of an S3 object:

https://DOC-EXAMPLE-BUCKET.s3.amazonaws.com/index.html

If either the web browser or curl command returns an Access Denied error, then the object isn't publicly accessible. If the object isn't publicly accessible, then use one of the following configurations:

Objects encrypted by AWS Key Management Service (AWS SSE-KMS)

If the s3 bucket contains objects encrypted by AWS Key Management Service (AWS SSE-KMS), then OAC should be used instead of OAI.

AWS KMS-encrypted objects can be served with CloudFront by setting up OAC. To do this, add a statement to the AWS KMS key policy that grants the CloudFront service principal the permission to use the key. To serve AWS KMS-encrypted objects without setting up OAC, serve the AWS KMS Key encrypted from an S3 bucket using Lambda@Edge.

Use one of the following ways to check if an object in your bucket is AWS KMS-encrypted:

The S3 bucket policy must allow access to s3:GetObject

To use a distribution with an S3 REST API endpoint, your bucket policy must allow s3:GetObject either to public users or to CloudFront's OAI. Even if you have an explicit allow statement for s3:GetObject in your bucket policy, confirm that there isn't a conflicting explicit deny statement. An explicit deny statement always overrides an explicit allow statement.

Follow these steps to review your bucket policy for s3:GetObject:

1.    Open your S3 bucket from the Amazon S3 console.

2.    Choose the Permissions tab.

3.    Choose Bucket Policy.

4.    Review the bucket policy for statements with "Action": "s3:GetObject" or "Action": "s3:*". The example policy below includes an allow statement that grants a CloudFront OAC access to s3:GetObject. It also includes a statement that grants CloudFront OAI access to s3:GetObject and an allow statement that grants public access to s3:GetObject. However, there's an explicit deny statement for s3:GetObject that blocks access unless the request is from a specific Amazon Virtual Private Cloud (Amazon VPC):

{
  "Version": "2012-10-17",
  "Id":
    "PolicyForCloudFrontPrivateContent",
  "Statement": [{
      "Sid": "Allow-OAC-Access-To-Bucket",
        "Effect": "Allow",
        "Principal":
    {
            "Service": "cloudfront.amazonaws.com"
        },
        "Action": "s3:GetObject",
       
    "Resource": "arn:aws:s3:::DOC-EXAMPLE-BUCKET/*",
        "Condition": {
            "StringEquals": {
               
    "AWS:SourceArn": "arn:aws:cloudfront::111122223333:distribution/EDFDVBD6EXAMPLE"
            }
        }
      },
     
    {
      "Sid": "Allow-OAI-Access-To-Bucket",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::cloudfront:user/CloudFront
    Origin Access Identity EAF5XXXXXXXXX"
      },
      "Action": "s3:GetObject",
      "Resource": [
        "arn:aws:s3:::DOC-EXAMPLE-BUCKET/*"
     
    ]
    },
    {
      "Sid": "Allow-Public-Access-To-Bucket",
      "Effect": "Allow",
      "Principal": "*",
     
    "Action": "s3:GetObject",
      "Resource": [
        "arn:aws:s3:::DOC-EXAMPLE-BUCKET/*"
      ]
    },
    {
     
    "Sid": "Access-to-specific-VPCE-only",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource":
    [
        "arn:aws:s3:::DOC-EXAMPLE-BUCKET/*"
      ],
      "Condition": {
        "StringNotEquals": {
         
    "aws:sourceVpce": "vpce-1a2b3c4d"
        }
      }
    }
  ]
}

5.    Modify the bucket policy to remove or edit statements that block CloudFront OAI access or public access to s3:GetObject

Note: CloudFront caches the results of an Access Denied error for up to five minutes. After removing a deny statement from the bucket policy, you can run an invalidation on your distribution to remove the object from the cache.

Ownership of S3 buckets and objects

For a bucket policy to apply to external accounts or services, the AWS account that owns the bucket must also own the objects. A bucket or object is owned by the account of the AWS Identity and Access Management (IAM) identity that created the bucket or object.

Note: The object-ownership requirement applies to access granted by a bucket policy. It doesn't apply to access granted by the object's access control list (ACL).

Follow these steps to check if the bucket and objects have the same owner:

1.    Run this AWS CLI command to get the S3 canonical ID of the bucket owner:

aws s3api list-buckets --query Owner.ID

2.    Run this command to get the S3 canonical ID of the object owner:

Note: This example shows a single object, but you can use the list command to check several objects.

aws s3api list-objects --bucket DOC-EXAMPLE-BUCKET --prefix index.html

3.    If the canonical IDs don't match, then the bucket and object have different owners.

Note: You can also use the Amazon S3 console to check the bucket and object owners. The owners are found in the Permissions tab of the respective bucket or object.

Follow these steps to change the object's owner to the bucket owner:

1.    From the object owner's AWS account, run this command to retrieve the access control list (ACL) permissions assigned to the object:

aws s3api get-object-acl --bucket DOC-EXAMPLE-BUCKET --key object-name

2.    If the object has bucket-owner-full-control ACL permissions, then skip to step #3. If the object doesn't have bucket-owner-full-control ACL permissions, then run this command from the object owner's account:

aws s3api put-object-acl --bucket DOC-EXAMPLE-BUCKET
    --key object-name --acl bucket-owner-full-control

3.    From the bucket owner's account, run this command to change the owner of the object by copying the object over itself:

aws s3 cp s3://DOC-EXAMPLE-BUCKET/index.html
    s3://DOC-EXAMPLE-BUCKET/index.html --storage-class STANDARD

Note: Make sure to change the --storage-class value in the example command to the storage class applicable to your use case.

The requested objects must exist in the bucket

If a user doesn't have s3:ListBucket permissions, then the user gets Access Denied errors for missing objects instead of 404 Not Found errors. Run the head-object AWS CLI command to check if an object exists in the bucket.

Note: Confirm that the object request sent to CloudFront matches the S3 object name exactly. S3 object names are case-sensitive. If the request doesn't have the correct object name, then Amazon S3 responds as though the object is missing. To identify which object CloudFront is requesting from Amazon S3, use server access logging.

If the object exists in the bucket, then the Access Denied error isn't masking a 404 Not Found error. Verify other configuration requirements to resolve the Access Denied error.

If the object isn’t in the bucket, then the Access Denied error is masking a 404 Not Found error. Resolve the issue related to the missing object.

Note: It's not a security best practice to allow public s3:ListBucket access. Allowing public s3:ListBucket access allows users to see and list all objects in a bucket. This exposes object metadata details, such as key and size, to users even if the users don't have permissions for downloading the object.

If clients request the root of your distribution, then you must define a default root object

If your distribution doesn't have a default root object defined, and a requester doesn't have s3:ListBucket access, then the requester receives an Access Denied error. The requester gets this error instead of a 404 Not Found error when they request the root of your distribution.

To define a default root object, see Specifying a default root object.

Note: It's not a security best practice to allow public s3:ListBucket access. Allowing public s3:ListBucket access allows users to see and list all objects in a bucket. This exposes object metadata details, such as key and size, to users even if the users don't have permissions for downloading the object.

Permissions for OAC or OAI

If you configured an OAC, then a CloudFront service principal must be included in the S3 bucket policy. If you configured an OAI, then the OAI must be included in your s3 bucket policy

To verify if your bucket policy allows the OAI, open your S3 bucket in the Amazon S3 console. Then, choose the Permissions tab and review the bucket policy. In the example policy below, the first statement is an allow statement for the CloudFront service principal when OAC is configured. The second statement is an allow statement for an OAI:

{
      "Sid": "Allow-OAC-Access-To-Bucket",
        "Effect": "Allow",
        "Principal": {
           
    "Service": "cloudfront.amazonaws.com"
        },
        "Action": "s3:GetObject",
        "Resource": "arn:aws:s3:::DOC-EXAMPLE-BUCKET/*",
       
    "Condition": {
            "StringEquals": {
                "AWS:SourceArn": "arn:aws:cloudfront::111122223333:distribution/EDFDVBD6EXAMPLE"
           
    }
     }
      },

{
  "Sid": "1",
  "Effect": "Allow",
  "Principal": {
    "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin
    Access Identity EAF5XXXXXXXXX"
  },
  "Action": "s3:GetObject",
  "Resource": "arn:aws:s3:::DOC-EXAMPLE-BUCKET/*"
}

To update your bucket policy using the CloudFront console, follow these steps:

1.    Open the CloudFront console and choose your distribution.

2.    Choose the Origins and Origin Groups tab.

3.    Select the S3 origin, and then choose Edit.

4.    For Restrict Bucket Access, choose Yes.

5.    For Origin Access Identity, choose the existing identity or create a new one.

6.    For Grant Read Permissions on Bucket, choose Yes, Update Bucket Policy.

7.    Choose Yes, Edit.

Allowing public access for distribution without OAC or OAI

If your distribution isn't using OAC or OAI, and objects aren't requested with AWS Signature Version 4, then you must allow public access for objects. This is because a distribution with a REST API endpoint supports only publicly readable objects. In this case, you must confirm that there aren't any Amazon S3 Block Public Access settings applied to the bucket. These settings override permissions that allow public read access. Amazon S3 Block Public Access settings can apply to individual buckets or AWS accounts.


Related information

Troubleshooting error responses from your origin

How do I troubleshoot 403 Access Denied errors from Amazon S3?

AWS OFFICIAL
AWS OFFICIALUpdated a year ago
2 Comments

If you're working with an SPA, it's very possible you don't need to solve these errors: all you need to do is handle them appropriately so your SPA's internal routing takes over.

This is kind of alluded to by the "requested objects must exist" suggestion here, but it's hard to realize this is your problem if, when you check S3, all of the SPA's resources are right there!

Paul C
replied 5 months ago

Thank you for your comment. We'll review and update the Knowledge Center article as needed.

profile pictureAWS
MODERATOR
replied 5 months ago