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 determine the endpoint type:
- Open the CloudFront console.
- Choose your CloudFront distribution, and then choose Distribution Settings.
- Choose the Origins and Origin Groups tab.
- Choose the Origins and Origin Groups tab.
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:
DOC-EXAMPLE-BUCKET.s3.amazonaws.com
Note: Make sure to follow the rules for naming Amazon S3 buckets.
Website endpoints use this format:
DOC-EXAMPLE-BUCKET.s3-website-us-east-1.amazonaws.com
Note: Depending on the AWS Region, the endpoint format might use the dash format (s3-website-Region) or the dot format
(s3-website.Region).
If your distribution is using a REST API endpoint, see I'm using an S3
REST API endpoint as the origin of my CloudFront distribution. Why
am I getting 403 Access Denied errors?
If your distribution is using a website endpoint, verify the following
requirements to avoid Access Denied errors:
- Objects in the bucket must be publicly accessible.
- Objects in the bucket can't be encrypted by AWS Key Management Service (AWS KMS).
- The bucket policy must allow access to s3:GetObject.
- If the bucket policy grants public read access, then the AWS account that owns the bucket must also own the object.
5.The requested objects must exist in the bucket.
- Amazon S3 Block Public Access must be disabled on the bucket.
- If Requester Pays is enabled, then the request must include the request-payer parameter.
- If you're using a Referer header to restrict access from CloudFront to your S3 origin, then review the custom header.
Note: If you don't want to allow public (anonymous) access to your S3 objects, then change your configuration to use the S3 REST API
endpoint as the origin of your distribution. Then, configure your
distribution and S3 bucket to restrict access using an origin access
identity (OAI). For instructions, see Using a REST API endpoint as the
origin with access restricted by an OAI in How do I use CloudFront to
serve a static website hosted on Amazon S3?
Resolution
Objects in the bucket must be publicly accessible
A distribution using a website endpoint supports only publicly
accessible content. To determine if an object in your S3 bucket is
publicly accessible, open the object's URL in a web browser. Or, you
can run a curl command on the URL.
The following is an example URL of an S3 object:
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.
Allow public read access to the object in one of the following ways:
- Create a bucket policy that allows public read access for all objects in the bucket.
- Use the Amazon S3 console to allow public read access for the object.
- Objects in the bucket can't be AWS KMS-encrypted
- CloudFront distributions don't support AWS KMS-encrypted objects. You must remove KMS encryption from the S3 objects that you want to
serve using the distribution.
Note: Instead of using AWS KMS encryption, use AES-256 to encrypt your objects.
Use one of the following ways to check if an object in your bucket is
KMS-encrypted:
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
KMS-encrypted. Run the head-object command using the AWS Command Line
Interface (AWS CLI). If the command returns ServerSideEncryption as
aws:kms, then the object is KMS-encrypted. Note: If you receive errors
when running AWS CLI commands, make sure that you’re using the most
recent version of the AWS CLI. 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,
first verify that the object's bucket doesn't have default encryption.
If the bucket doesn't have default encryption, then run the following
command to remove the object's encryption by copying the object over
itself:
aws s3 cp s3://DOC-EXAMPLE-BUCKET/index.html s3://DOC-EXAMPLE-BUCKET/index.html
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.
The bucket policy must allow access to s3:GetObject To use a
distribution with an S3 website endpoint, your bucket policy must not
have a deny statement that blocks public read access to the
s3:GetObject action.
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:
Open your S3 bucket from the Amazon S3 console.
Choose the Permissions tab.
Choose Bucket Policy.
Review the bucket policy for statements with "Action": "s3:GetObject" or "Action": "s3:*".
The following example policy contains an explicit allow statement for
public access to s3:GetObject. However, there's also an explicit deny
statement for s3:GetObject that blocks access unless the request is
from a specific Amazon Virtual Private Cloud (Amazon VPC).
{
"Version": "2008-10-17",
"Id": "PolicyForCloudFrontPrivateContent",
"Statement": [
{
"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"
}
}
}
]
}
- Modify the bucket policy to remove or edit statements that block public read access to s3:GetObject.
Note: CloudFront caches the results of an Access Denied error for the amount of time specified in the error caching minimum TTL. The
default value is one minute. After removing a deny statement from the
bucket policy, you can run an invalidation on your distribution to
remove the object from the cache.
If the bucket policy grants public read access, then the AWS account
that owns the bucket must also own the object For a bucket policy to
allow public read access to objects, 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 public read access granted by a bucket policy. It doesn't apply to public read
access granted by the object's access control list (ACL).
Follow these steps to check if the bucket and objects have the same
owner:
- Run this AWS CLI command to get the S3 canonical ID of the bucket owner:
aws s3api list-buckets --query Owner.ID
- 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
- 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:
- From the object owner's account, run this command to retrieve the ACL permissions assigned to the object:
aws s3api get-object-acl --bucket DOC-EXAMPLE-BUCKET --key object-name
- 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
- 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
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 enable public s3:ListBucket access. Enabling public s3:ListBucket access allows
users to see and list all objects in a bucket. This exposes object
metadata details (for example, key and size) to users even if the
users don't have permissions for downloading the object.
Amazon S3 Block Public Access must be disabled on the bucket Confirm that there aren't any Amazon S3 Block Public Access settings
applied to the bucket. These settings can override permissions that
allow public read access. Amazon S3 Block Public Access settings can
apply to individual buckets or AWS accounts.
If Requester Pays is enabled, then the request must include the
request-payer parameter If Requester Pays is enabled on a bucket, then
anonymous access to the bucket is not allowed. Users from other
accounts must specify the request-payer parameter when they send
requests to the bucket. Otherwise, those users get an Access Denied
error.
If you're using a Referer header to restrict access from CloudFront to
your S3 origin, then review the custom header If you're using the
Referer header to restrict access from CloudFront to your S3 website
endpoint origin, check the secret value or token set on the S3 bucket
policy. Then, confirm that the secret value or token matches the value
on the CloudFront origin custom header.
If you're using an explicit deny statement in the bucket policy, then
confirm that there's also 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":
{
"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"}
}
}
]
}
With this example bucket policy, the CloudFront origin custom header
must be:
- Header: Referer
- Value: MY_SECRET_TOKEN_CONFIGURED_ON_CLOUDFRONT_ORIGIN_CUSTOM_HEADER
Note:
The example bucket policy grants public (anonymous) access to the
bucket because the Principal is a wildcard value ("Principal":"*").
However, because of the condition statement, access to the S3 origin
is granted only if the request includes the Referer header and the
header value matches the value in the bucket policy.