AWS CloudFront Support

CloudFront origin access control for private S3 buckets.

Serving a website or assets from S3 through CloudFront should not require a public bucket. Origin access control (OAC) lets only your distribution read the bucket. We set it up, migrate older origin access identities and fix the 403 errors that often follow.

OACReplaces legacy OAI
SigV4How CloudFront signs requests
Block Public AccessStays fully on
cloudfront.amazonaws.comBucket policy principal

When You Need This

The situations where this work pays for itself.

Signs it is time

  • Your S3 bucket is public only so CloudFront can read it
  • You still use an origin access identity and want to move to OAC
  • Objects return AccessDenied through CloudFront but open directly in S3
  • Objects are encrypted with a KMS key and CloudFront cannot read them
  • You need PUT or DELETE through CloudFront to a private bucket

What you get

  • Distribution, OAC and bucket policy in infrastructure as code
  • A tested migration from OAI to OAC with no downtime
  • Key policy changes for encrypted buckets
  • A checklist for adding new distributions to the same bucket

How we do it

A clear, safe process you can follow along with.

1. Review the current setup

We check whether the origin is an S3 REST endpoint or an S3 website endpoint. OAC works with the REST endpoint; website endpoints are public by design and cannot use OAC.

2. Create the origin access control

We create an OAC with signing behavior set to sign requests, and attach it to the S3 origin of the distribution.

3. Write the bucket policy

We allow the cloudfront.amazonaws.com service principal to s3:GetObject, with a condition on AWS:SourceArn equal to the specific distribution ARN, so no other distribution can read the bucket.

4. Handle SSE-KMS objects

If objects use a customer managed KMS key, the key policy must also allow the CloudFront service principal to use kms:Decrypt and kms:GenerateDataKey, again scoped to the distribution ARN.

5. Fix listing and missing-object behavior

A missing object returns 403 instead of 404 unless the policy also grants s3:ListBucket. We decide deliberately, and set custom error responses and a default root object.

6. Turn on Block Public Access and verify

Once the policy works, we enable all S3 Block Public Access settings, then confirm the object loads through CloudFront and returns AccessDenied when requested directly from S3.

Mistakes we help you avoid

Common ways this goes wrong, and what we do instead.

Using the S3 website endpoint with OAC

OAC needs the REST endpoint. Website endpoints need a different, weaker protection such as a secret header.

Policy scoped to the account instead of the distribution

Allowing any distribution in the account is broader than needed. Use the distribution ARN condition.

Forgetting the KMS key policy

Bucket policy alone is not enough for SSE-KMS objects. The key policy must allow CloudFront too.

Removing OAI before testing OAC

We add OAC and verify, then remove the old identity, to avoid an outage.

Frequently Asked Questions

What is the difference between OAC and OAI?

OAC is the newer mechanism and supports more S3 features, including SSE-KMS and all HTTP methods, with signed requests. OAI is the older identity-based method and AWS recommends OAC for new work.

Why does CloudFront return 403 for a private S3 bucket?

Most often the bucket policy lacks the distribution ARN, the OAC is not attached to the origin, or a KMS key policy blocks decryption. The object path also has to exist.

Can I keep the bucket private and still serve a static website?

Yes. Use the REST endpoint as the origin with OAC, a default root object and custom error responses, and keep Block Public Access on.

Want Help With CloudFront origin access control for private S3 buckets?

Schedule an appointment. Tell us about your environment and we will outline the safest, highest-value approach.

Schedule Appointment › No commitment required