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

To use an S3 bucket as the origin of your CloudFront distribution, you can use either the S3 static website endpoint or the S3 REST API endpoint as the origin domain name. To troubleshoot HTTP 403 (Access Denied) errors, you must know which endpoint type your distribution is using.

Follow these steps to determine the endpoint type:

  1. Open the CloudFront console.
  2. Select your CloudFront distribution, then choose Distribution Settings.
  3. Choose the Origins view.
  4. Review the domain name under Origin Domain Name and Path and then determine the endpoint type based on the format of the domain name.

REST API endpoints use this format:

example-bucket.s3.amazonaws.com

Static website endpoints use this format:

example-bucket.s3-website-us-east-1.amazonaws.com

If your distribution is using an S3 static website endpoint, see I'm using an S3 website endpoint as the origin of my CloudFront distribution. Why am I getting HTTP response code 403 (Access Denied)?

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

  • The REST API endpoint must be able to access the objects.
  • Objects in the S3 bucket cannot be encrypted using AWS Key Management Service (AWS KMS).
  • The S3 bucket policy must allow access to s3:GetObject.
  • 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, you must define a default root object.
  • If you configured an origin access identity (OAI), the OAI must be included in the S3 bucket policy.

The REST API endpoint must be able to access the objects

If you don't configure an origin access identity (OAI), the S3 REST API endpoint can access only public objects, or objects requested with AWS Signature Version 4 authentication.

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:

http://example-bucket.s3-website-us-east-1.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, use one of the following methods to allow your REST API endpoint to access the object:

Objects in the bucket cannot be AWS KMS-encrypted

S3 REST API endpoints with an OAI configured cannot access KMS-encrypted objects. S3 REST API endpoints with no OAI configured can access KMS-encrypted objects only with requests that are pre-signed with AWS Signature Version 4.

Check if the objects in your bucket are KMS-encrypted in one of the following ways:

  • Use the Amazon S3 console to view the object. Then, choose the Properties view. Review the Encryption dialog box. If AWS-KMS is selected, then the object is KMS-encrypted. For more information, see How Do I View the Properties of an Object?
  • Run the following AWS Command Line Interface (AWS CLI) command to make a head-object request. If the command returns ServerSideEncryption as aws:kms, then the object is KMS-encrypted.

Note: Be sure to replace the bucket and key values with the values related to your S3 bucket and object.

aws s3api head-object --bucket example-bucket --key kms-object.html

To change the object's encryption settings using the Amazon S3 console, see How Do I Add Encryption to an S3 Object?

To change the object's encryption settings using the AWS CLI, you must first verify that the object's bucket doesn't have default encryption. If the bucket doesn't have default encryption, run the following AWS CLI command to copy the object to itself. After you copy the object over itself, the object's encryption setting defaults to none.

Warning: Copying the object over itself removes settings for storage-class and website-redirect-location. To maintain these settings in the new object, be sure to explicitly specify storage-class or website-redirect-location values in the copy request. For more information, see Request Headers.

aws s3 cp s3://example-bucket/index.html s3://example-bucket/index.html

The S3 bucket policy must allow access to s3:GetObject

To use 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, be sure that there is no explicit deny statement that conflicts with the allow 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 view.
  3. Choose Bucket Policy.
  4. Review the bucket policy for statements related to the s3:GetObject action.

In the following example policy, there is an explicit allow statement for public access to s3:GetObject. However, there is also an explicit deny statement for s3:GetObject that prevents S3 object access.

{
    "Version": "2008-10-17",
    "Id": "PolicyForCloudFrontPrivateContent",
    "Statement": [
        {
            "Sid": "Allow-OAI-Access-To-Bucket",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::cloudfront:user/CloudFront OAI EAF5XXXXXXXXX"
            },
            "Action": "s3:GetObject",
            "Resource": [
                "arn:aws:s3:::example-bucket/*"
            ]
        },
        {
            "Sid": "Allow-Public-Access-To-Bucket",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": [
                "arn:aws:s3:::example-bucket/*"
            ]
        },
        {
            "Sid": "Access-to-specific-VPCE-only",
            "Effect": "Deny",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": [
                "arn:aws:s3:::example-bucket/*"
            ],
            "Condition": {
                "StringNotEquals": {
                    "aws:sourceVpce": "vpce-1a2b3c4d"
                }
            }
        }
    ]
  }

For instructions on updating your bucket policy to allow access to s3:GetObject, see How Do I Add an S3 Bucket Policy?

Note: CloudFront caches the results of an HTTP 403 (Access Denied) error for up to 5 minutes. After you remove the deny statement from the bucket policy, you might need to run an invalidation on your distribution to remove the object from the cache.

The AWS account that owns the S3 bucket must also own the object

For a bucket policy to apply to external accounts or services (for example, public access or OAI), the AWS account that owns the bucket must also own the objects. Bucket or object ownership is based on the AWS account of the AWS Identity and Access Management (IAM) user or role that created the bucket or object.

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 for your AWS account:

aws s3api list-buckets --query Owner.ID

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

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

aws s3api list-objects --bucket 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 view 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 bucket-name --key object-name

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

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

3.    Run this command to change the owner of the object by copying the object over itself:

aws s3 cp s3://example-bucket/index.html s3://example-bucket/index.html

The requested objects must exist in the S3 bucket

If a requested object doesn't exist in the bucket and the requester doesn't have s3:ListBucket access, then the requester receives an HTTP 403 (Access Denied) error rather than the HTTP 404 (Not Found) error.

To determine if the HTTP 403 error is masking an HTTP 404 error, first check if the object exists in the bucket by opening the bucket from the Amazon S3 console, or by running the head-object AWS CLI command.

Note: References to S3 object names are case-sensitive. Be sure that the object request sent to CloudFront matches the object name exactly. To identify which object CloudFront is requesting from Amazon S3, use server access logging.

If the object is available in the bucket, then the HTTP 403 error isn't masking an HTTP 404 error, and you must verify other configuration requirements to resolve the HTTP 403 error.

If the object isn't available in the bucket, then the HTTP 403 error is masking an HTTP 404 error, and you must resolve the issue related to the missing object.

Note: We don't recommend enabling public s3:ListBucket access because it's not a security best practice.

If clients request the root of your distribution, 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, the requester receives an HTTP 403 (Access Denied) error instead of an HTTP 404 (Not Found) error when they request the root of your distribution.

To define a default root object, see Specifying a Default Root Object (Web Distributions Only).

Note: We don't recommend enabling public s3:ListBucket access because it's not a security best practice.

If you configured an OAI, the OAI must be included in the S3 bucket policy

If you added an OAI to your CloudFront distribution, you must also include an allow statement for the OAI in the 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 view and review the bucket policy. The following is an example allow statement for an OAI: 

{
    "Sid": "1",
    "Effect": "Allow",
    "Principal": {
        "AWS": "arn:aws:iam::cloudfront:user/CloudFront OAI EAF5XXXXXXXXX"
    },
    "Action": "s3:GetObject",
    "Resource": "arn:aws:s3:::example-bucket/*"
}

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

  1. Open the Amazon CloudFront console and choose your distribution.
  2. Choose the Origins view.
  3. Select the S3 origin and 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.

Did this page help you? Yes | No

Back to the AWS Support Knowledge Center

Need help? Visit the AWS Support Center

Published: 2018-05-30