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

8 minute read
-2

I'm using an Amazon Simple Storage Service (Amazon S3) REST API endpoint as the origin domain name to my CloudFront distribution. But, CloudFront returns 403 Access Denied errors from Amazon S3.

Short description

To avoid Access Denied errors, use the following configurations:

  • Make the S3 objects publicly accessible.
  • Use origin access control (OAC) instead of origin access identity (OAI) for S3 buckets that contain objects that are server-side encrypted with AWS Key Management Service (AWS KMS).
  • Modify the S3 bucket policy so that it allows access to s3:GetObject.
  • Make sure that the AWS account that owns the S3 bucket also owns the object.
  • Confirm that the requested objects exist in the S3 bucket.
  • Define a default root object so that clients can request the root of your distribution.
  • For an OAI configuration, you must include the OAI in the S3 bucket policy. For an OAC configuration, you must include the CloudFront service principal in the S3 bucket policy.

If your distribution uses an S3 static website endpoint, then see I'm using an S3 website endpoint as the origin of my CloudFront distribution. Why am I getting 403 Access Denied errors?

Resolution

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.

Make the S3 objects publicly accessible

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.

To make the object publicly accessible, take one of the following actions:

Use OAC for objects that are encrypted by AWS KMS

To use OAC, add a statement to the AWS KMS key policy that grants the CloudFront service principal the permission to use the key. You can also use LambdaEdge instead of OAC. For more information, see Serving AWS KMS encrypted content from S3 using CloudFront.

To confirm whether your object is encrypted with AWS KMS, take one of the following actions:

  • Use the Amazon S3 console to view the properties of the object. Review the Encryption dialog box. If AWS KMS is selected, then the object is AWS KMS encrypted.
  • Run the head-object command in the AWS CLI. If the command returns ServerSideEncryption as aws:kms, then the object is AWS KMS encrypted.
    Note: OAI doesn't serve AWS KMS encrypted objects.

Allow access to s3:GetObject

Even if you have an explicit Allow statement for s3:GetObject in your bucket policy, confirm that there's no conflict with an explicit Deny statement. An explicit Deny statement always overrides an explicit Allow statement.

To confirm whether your bucket policy allows s3:GetObject and no explicit Deny statements, complete the following steps:

  1. Open Amazon S3 console.

  2. Choose your bucket.

  3. Choose the Permissions tab.

  4. Choose Bucket policy.

  5. Check for statements with "Action": "s3:GetObject" or "Action": "s3:*". The following example policy 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"  
            }  
          }  
        }  
      ]  
    }
  6. 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 5 minutes. After you remove a deny statement from the bucket policy, you can run an invalidation on your distribution to remove the object from the cache.

Grant ownership of S3 buckets and objects

The account of the AWS Identity and Access Management (IAM) identity that created the bucket or object owns the bucket or object.

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

To check whether the bucket and objects have the same owner, complete the following steps:

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

    aws s3api list-buckets --query Owner.ID
  2. Run the list-objects 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

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. You can find the owners on the Permissions tab of the bucket or object.

To 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:

    aws s3api get-object-acl --bucket DOC-EXAMPLE-BUCKET --key object-name
  2. If the object has bucket-owner-full-control ACL permissions, then proceed to step 3. 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 --storage-class STANDARD

    Note: Replace --storage-class with your storage class.

Move the objects to the bucket

To check whether an object exists in the bucket, run the head-object AWS CLI command.

Note: S3 object names are case-sensitive. Confirm that the object request that's sent to CloudFront matches the S3 object name. If the request doesn't have the correct object name, then Amazon S3 responds as though the object is missing. To identify the object that CloudFront requests 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. Check 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. You must resolve the issue that's related to the missing object.

Define a default root object

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

Note: It's a security best practice to deny public s3:ListBucket access. If you allow public s3:ListBucket access, then users can see and list all objects in a bucket. This exposes object metadata details, such as key and size, to all users.

Add OAI or CloudFront service principal permissions in the S3 bucket policy

To check whether your bucket policy allows the OAI, open the Amazon S3 console. Find your bucket, and then on the Permissions tab, choose Bucket policy.

The following example policy includes an Allow statement for the CloudFront service principal when you configure OAC:

{        
        "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"  
             
    }  
     }  
      }

The following example policy includes an Allow statement for an OAI:

{  
  "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 in the CloudFront console, follow these steps:

  1. Open the CloudFront console.
  2. Choose your distribution.
  3. Choose the Origins and Origin Groups tab.
  4. Select the S3 origin, and then choose Edit.
  5. For Restrict Bucket Access, choose Yes.
  6. For Origin Access Identity, choose an existing identity or create a new one.
  7. For Grant read permissions on bucket, choose Yes, update bucket policy.
  8. Choose Yes, edit.

Related information

Troubleshooting error responses from your origin

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

AWS OFFICIAL
AWS OFFICIALUpdated 4 months 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!

replied a year ago

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

profile pictureAWS
MODERATOR
replied a year ago