Understanding CloudFront Access to S3: OAI vs OAC — My Personal Experiment

Gerlyn MGerlyn M
5 min read

Hey everyone! 👋

When I’m working with an S3 + CloudFront setup, I noticed something that made me curious there are two different ways to let CloudFront access S3: OAI (Origin Access Identity) and the newer OAC (Origin Access Control).

That got me wondering:

Why are there two options? What’s the real difference?

To answer that, I decided to run a hands-on experiment and explore both approaches in detail.

Now that I’ve done it, I’m sharing my experience below including what I built, what I learned, and how you can try it too.

If you've ever been confused about when to use which or how they actually work in practice this post is for you!


🤔 Wait, Why Are There Two Options Anyway?

At first glance, both OAI and OAC let CloudFront access private S3 content securely so naturally, I wondered:

If both are doing the same thing, why did AWS introduce a new method?

Here’s the thing: both OAI and OAC are used to let CloudFront securely access content from an S3 bucket. So, you might think: “If the end result is the same, why is AWS pushing everyone toward OAC now?”

Let me break it down for you:


🔍 The Problem with Legacy OAI

With OAI, we create a special identity, and we update our S3 bucket policy to allow that OAI to access the bucket. Then, CloudFront uses that identity to fetch content from S3.

Seems straightforward, right?

But here’s the issue:
Any CloudFront distribution using that same OAI can access the bucket.

So, imagine I use the same OAI for multiple CloudFront distributions now, all of them can read from that S3 bucket. There's no way to limit it to just one CloudFront distribution.

🎯 That’s a security gap.


🔐 Enter OAC (Origin Access Control)

To address this issue, AWS introduced OAC.

With OAC, we create an access control configuration and assign it per CloudFront distribution. Then, in the S3 bucket policy, we don’t just allow based on a shared OAI… instead, we use a condition like AWS:SourceArn to only allow that exact CloudFront distribution to access the S3 content.

So now, only one specific CloudFront distribution and no others can read from the bucket. That’s a huge win for security and best practices. 🚀


❓But wait… Why Can’t We Just Use SourceArn with OAI?

I had the same question at first!

The problem is: OAI doesn’t include the CloudFront distribution’s identity when making the request to S3.

It only signs the request using the OAI credentials, but there's no way for S3 to know which distribution is calling. That means even if you try to use AWS:SourceArn in the bucket policy, it won’t work with OAI because the request lacks that source context.

👉 OAC solves this by including the distribution’s ARN in the signature, allowing S3 to enforce precise, per-distribution policies.

So, while OAI gives S3 a kind of generic identity, OAC brings full context and secure granularity.


🛠️ What I Built

Okay now I believe you understand the difference theoretically.
But let’s be real: theory alone isn’t enough.

So how do we actually see this difference in action?

No worries I got you! 😎

I wrote a Terraform script that will let you spin up a hands-on environment in seconds.

Here’s what it does:

Scenario 1 – Using OAI (Legacy)

  • Creates one S3 bucket with a test file.

  • Creates two CloudFront distributions (A & B) using the same OAI.

  • The S3 bucket policy allows access to that OAI.

  • Result: both distributions can access the S3 content, even though we didn’t restrict them individually and that’s the core issue with OAI.

Scenario 2 – Using OAC (Modern Approach)

  • Same S3 bucket and test file.

  • Creates two new CloudFront distributions (C & D) using OAC.

  • The bucket policy uses AWS:SourceArn to allow access only from CloudFront distribution C.

  • This means:
    CloudFront C can access the S3 content
    CloudFront D cannot, because it's not explicitly allowed in the S3 bucket policy.

  • Result: Now we have tight access control only the specified distributions can access the content.


🤯 What I Learned

✅ OAI (Origin Access Identity)

  • Simple and familiar.

  • Bucket policy just checks the OAI ARN.

  • BUT: you can't restrict it to a specific distribution, so if you share the same OAI with multiple CloudFront distributions, all of them get access.

This was clear when I spun up two distributions (A and B) both could access the S3 content, even though the bucket policy didn’t mention their individual ARNs.

✅ OAC (Origin Access Control)

  • Modern approach supports sigv4 signing.

  • You must use origin_access_control_id in CloudFront.

  • The S3 policy can now restrict access to a specific CloudFront distribution using AWS:SourceArn.

When I enabled OAC, only the distributions C and D were created. The S3 bucket policy now allow the specific distribution can access its content.


🧪 Try It Yourself

I have written all the Terraform code you need, also included clear instructions in the GitHub README. so, you can spin up the full environment in just a few commands.

👉 Repository URL:
🔗 gerlynm/just-curious


📌 Final Thoughts

If you're building something new go with OAC. It’s more secure and future ready. But OAI still works.

Hope this helps someone trying to understand the differences through actual practice, just like I did. Let me know if you’d like the full Terraform code or a breakdown of the policy structures!

Happy experimenting! ✨

10
Subscribe to my newsletter

Read articles from Gerlyn M directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Gerlyn M
Gerlyn M

Gerlyn is a DevOps engineer with a strong passion for Kubernetes and automation. He is always eager to learn and continuously strives to enhance his skills, aiming to become an expert in the field. He loves to share his knowledge with the community.