Skip to content

Why do I get a "403 access denied" error when I use an Amazon S3 website endpoint as the origin of my CloudFront distribution?

9 minute read
0

I use an Amazon Simple Storage Service (Amazon S3) bucket as the origin of my Amazon CloudFront distribution. I want to troubleshoot the "403 access denied" error.

Resolution

To troubleshoot CloudFront distributions with Amazon S3 website endpoints as the origin, complete the following tasks.

Note: If you receive errors when you run AWS Command Line Interface (AWS CLI) commands, then see Troubleshoot AWS CLI errors. Also, make sure that you're using the most recent AWS CLI version.

Review the encryption of objects in your bucket

AWS Key Management Service (AWS KMS) doesn't support anonymous requests. Amazon S3 buckets that allow anonymous or public access don't apply this access to objects that are encrypted with AWS KMS. Remove AWS KMS encryption from the S3 objects that you want to serve. Instead of the AWS KMS encryption, use AES-256 to encrypt your objects.

Determine if the objects are AWS KMS encrypted

To check if the objects in your bucket are AWS KMS encrypted, complete the following tasks:

View the properties of the object on the Amazon S3 console. If AWS-KMS is selected in the Encryption dialog box, then the object is AWS KMS encrypted.

Or, run the AWS CLI to run the head-object command. If the command returns ServerSideEncryption as aws:kms, then the object is AWS KMS encrypted.

Change an object's encryption settings

To use the Amazon S3 console to change the object's encryption settings, see Specifying server-side encryption with AWS KMS (SSE-KMS).

To use the AWS CLI to change the object's encryption settings, verify that the object's bucket doesn't have AWS KMS as the default encryption. If the bucket has AWS KMS as the default encryption, then change the encryption to SSE-S3.

If the bucket doesn't have default encryption, then run the following command to copy the object over itself and remove the object encryption:

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

Note: Replace DOC-EXAMPLE-BUCKET with your bucket name. When you copy the object over itself, the action removes settings for storage-class and website-redirect-location. To maintain these settings in the new object, explicitly specify these values in the copy request.

Review your bucket policy

Your bucket policy can't have a deny statement that blocks public read access to the s3:GetObject action.

If you have an explicit allow statement for s3:GetObject, then make sure that there isn't an explicit deny statement that conflicts with the statement. An explicit deny statement always overrides an explicit allow statement.

To review your bucket policy for s3:GetObject, complete the following steps:

  1. Open the Amazon S3 console, and then navigate to your S3 bucket.
  2. Choose the Permissions tab.
  3. Choose Bucket Policy.
  4. Review the bucket policy for statements with "Action": " s3:GetObject " or " Action": " s3:* ".
  5. Modify the bucket policy to remove or edit statements that block public read access to s3:GetObject.

For example, the following policy contains an explicit allow statement for public access to s3:GetObject. However, it also contains an explicit deny statement for s3:GetObject access, unless the request is from a specific Amazon Virtual Private Cloud (Amazon VPC). Modify this policy to allow the s3:GetObject action:

{
  "Version": "2012-10-17",
  "Id": "PolicyForCloudFrontPrivateContent",
  "Statement": [
    {
      "Sid": "Allow-OAI-Access-To-Bucket",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity EAF5#########"
      },
      "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"
        }
      }
    }
  ]
}

The following policy is an example of an Amazon S3 bucket policy that allows read-only public access to S3 website endpoint:

{
   "Version": "2012-10-17",
    "Statement": {
    "Sid": "AllowPublicReadOnly",
    "Effect": "Allow",
    "Principal": "*",
    "Action": "s3:GetObject",
    "Resource": "arn:aws:s3:::DOC-EXAMPLE-BUCKET/*"
  }
}

Review bucket and object ownership

For a bucket policy to allow public read access to objects, the AWS account that owns the bucket must also own the objects.

Note: The object ownership requirement applies to public read access that a bucket policy grants. It doesn't apply to public read access that the object's access control list (ACL) grants.

Confirm that the bucket and objects have the same owner

Note: You can use the Amazon S3 console to check the bucket and object owners. You can find the owners on the Permissions tab of the bucket or object.

To use the AWS CLI to check the bucket and object owners, run the following commands:

Run the list-buckets command to get the S3 canonical ID of the bucket owner:

aws s3api list-buckets --query Owner.ID

Run the list-objects command to get the S3 canonical ID of the object owner:

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

Note: The output from the preceding example command shows a single object, but you can use the list-objects command to check several objects. If the canonical IDs don't match, then the bucket and object have different owners.

Update object ownership

Bucket owners can manage ownership of objects with S3 Object Ownership. The S3 Object Ownership setting is turned on by default for all new S3 buckets. To update an existing bucket, see Setting Object Ownership on an existing bucket.

It's a best practice for bucket owners to use the S3 Object Ownership setting on all buckets. Also, it's a best practice to manage permissions through AWS Identity and Access Management (IAM) roles and bucket policies.

To remove ACLs for your bucket and take ownership of all objects in the bucket, run the put-bucket-ownership-controls command:

aws s3api put-bucket-ownership-controls --bucket example-bucket --ownership-controls 'Rules=[{ObjectOwnership=BucketOwnerEnforced}]'

If you don't want to turn off the ACLs on your S3 bucket, then change the object's owner to the bucket owner.

Complete the following steps:

  1. From the object owner's account, run the get-object-acl command to retrieve the ACL permissions that are assigned to the object:

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

    Note: If the object has bucket-owner-full-control ACL permissions, then skip to step 3.

  2. If the object doesn't have bucket-owner-full-control ACL permissions, then run the put-object-acl 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 the following command to copy the object over itself and change the owner of the object:

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

    Note: Replace DOC-EXAMPLE-BUCKET with the name of your bucket. Replace DOC-EXAMPLE-BUCKET with the name of your bucket.

Review the Block Public Access settings for the bucket

Make sure that no Amazon S3 Block Public Access settings are applied to the bucket or account. These settings can override permissions that allow public read access. Amazon S3 Block Public Access settings can apply to individual buckets or AWS accounts.

Confirm that objects in the bucket are publicly accessible

A distribution that uses a website endpoint supports only publicly accessible content. To determine if an object in your S3 bucket is publicly accessible, open the object URL of the S3 website endpoint in a web browser. Or, run a curl command on the URL.

Example:

http://DOC-EXAMPLE-BUCKET.s3-website-us-east-1.amazonaws.com/index.html

If the web browser or curl command returns an Access Denied error, then the object isn't publicly accessible.

To allow public read access, complete one of the following tasks:

Review the Requester Pays option

If Requester Pays is turned on, then turn off the option. Requester Pays buckets don't allow access through a website endpoint.

Review your custom header

If you use the referer header to restrict access from CloudFront to your S3 website endpoint origin, then check your bucket policy. Verify that the secret value or token that's set on the S3 bucket policy matches the value on the CloudFront origin custom header.

To use an explicit deny statement in the bucket policy, there must be an allow statement that grants access based on the referer header. You can't grant access with only an explicit deny statement.

For example, the following bucket policy grants access to the S3 origin when the request contains the string "aws:Referer":"MY_SECRET_TOKEN_CONFIGURED_ON_CLOUDFRONT_ORIGIN_CUSTOM_HEADER."

The CloudFront origin custom header must have the following configurations:

  • Header: referer
  • Value: MY_SECRET_TOKEN_CONFIGURED_ON_CLOUDFRONT_ORIGIN_CUSTOM_HEADER

Example bucket policy:

{
  "Version":"2012-10-17",
  "Id":"http referer policy example",
  "Statement":[
    {
      "Sid":"Allow get requests originating from my CloudFront with referer header",
      "Effect":"Allow",
      "Principal":"*",
      "Action":"s3:GetObject",
      "Resource":"arn:aws:s3:::DOC-EXAMPLE-BUCKET/*",
      "Condition":{
        "StringLike":{"aws:Referer":"MY_SECRET_TOKEN_CONFIGURED_ON_CLOUDFRONT_ORIGIN_CUSTOM_HEADER"}
      }
    }
  ]
}

Note: Because Principal is a wildcard value ("Principal":"*"), the example bucket policy grants public (anonymous) access to the bucket. Because of the condition statement, the request must include the referer header and the header value must match the value in the bucket policy. If the condition statement isn't met, then you can't access the S3 origin.

Review your organization's management account

Use your organization's management account in AWS Organizations to check for deny service control policies (SCPs). Review the deny policies for the s3:GetObject action that's attached to the organization root, the organizational unit (OU), or directly to your account.

Related information

Why do I get 403 Access Denied errors when I use an S3 REST API endpoint as the origin of my CloudFront distribution?

Troubleshooting error response status codes in CloudFront

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

How do I use CloudFront to serve a static website that's hosted on Amazon S3?

2 Comments

While you do cover it I'd recommend making "Ensure you have a root object set" as its own troubleshooting point. I didn't have a default root object defined so / would fail but /index.html would work. Configuring the default object fixed the issue.

replied a year ago

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

AWS
MODERATOR
replied a year ago