How to migrate to CloudFront Origin Access Control from Origin Access Identity

What are the differences between OAI and the new OAC

Author's image
Tamás Sallai
4 mins

Protecting S3 buckets

AWS recently announced the new Origin Access Control (OAC) feature for CloudFront. This is a successor of the Origin Acccess Identity (OAI) and I was naturally interested in what doors it opens in terms of new features.

OAI and OAC both have the same purpose: make CloudFront able to fetch objects from an S3 bucket that is not open to the public. This solves a narrow case for a problem with CDNs: they fetch content just like any other visitor, which makes it possible to circumvent the CDN entirely and go to the origin. Without using OAI or OAC, you'd need to make the S3 bucket public to allow CloudFront to fetch the files. But with them, the bucket can be private.

In this article, we'll discuss how to configure them and how to move from OAI to OAC.

We'll look into the 3 parts of the configuration: the entities on CloudFront's side, the Distribution config, then the bucket config on S3.


To use either of them, you need to create an entity on CloudFront. Both are available under the Security/Origin access menu:

Security/Origin access menu entry

Here, an OAI requires only a name:

Create Origin Access Identity form

OAC has a few extra options:

Create Origin Access Control form

But apart from a longer form, I couldn't yet find a use-case where I needed anything else than the default. So we can say there are no real differences here.

In Terraform, OAC is a bit longer, but with the same information:

resource "aws_cloudfront_origin_access_control" "oac" {
	name                              = "some-name"
	description                       = ""
	origin_access_control_origin_type = "s3"
	signing_behavior                  = "always"
	signing_protocol                  = "sigv4"

resource "aws_cloudfront_origin_access_identity" "oai" {

Distribution config

Both entities are configured for an origin:

Origins list showing the configured Origin access

And changing which one to use is to select the other one:

Configuring the OAC for an origin

In Terraform:

origin {
	domain_name              = aws_s3_bucket.files.bucket_regional_domain_name
	origin_id                = "files_oac"
	origin_access_control_id =

origin {
	domain_name = aws_s3_bucket.files.bucket_regional_domain_name
	origin_id   = "files_oai"
	s3_origin_config {
		origin_access_identity = aws_cloudfront_origin_access_identity.oai.cloudfront_access_identity_path

Bucket config

Finally, the bucket needs to allow the s3:GetObject action on its objects.

For the OAI, it is done via a special Principal:

Configuring permissions for OAI

While for the OAC, the Principal is the service and the AWS:SourceArn defines the distribution:

Configuring permissions for OAC

In Terraform:

data "aws_iam_policy_document" "default" {
	statement {
		actions = ["s3:GetObject"]

		resources = ["${aws_s3_bucket.files.arn}/*"]

		principals {
			type        = "Service"
			identifiers = [""]
		condition {
			test     = "StringEquals"
			variable = "AWS:SourceArn"
			values   = [aws_cloudfront_distribution.distribution.arn]
	statement {
		actions   = ["s3:GetObject"]
		resources = ["${aws_s3_bucket.files.arn}/*"]

		principals {
			type        = "AWS"
			identifiers = [aws_cloudfront_origin_access_identity.oai.iam_arn]


Did you spot the big difference between the two? Me neither. Their configuration is exactly the same, they allow the same use-case, and nothing else. I was hoping that maybe OAC can sign requests for Lambda origins too, making it possible to configure private endpoints without adding a secret header, but no: OAC only supports S3 origins.

The documentation lists a few examples that is now possible with OAC that weren't possible with OAI:

  • All Amazon S3 buckets in all AWS Regions, including opt-in Regions launched after December 2022
  • Amazon S3 server-side encryption with AWS KMS (SSE-KMS)
  • Dynamic requests (POST, PUT, etc.) to Amazon S3

This sounds great, but there weren't any roadblocks why CloudFront couldn't support these use-cases from day 1. Overall, this change seems more like to reduce some internal technical debt rather than anything noteworthy. I'm still missing the ability to secure other kinds of origins.

One good thing about this change is that the bucket policy references the distribution itself and not the entity that can be attached to multiple distributions. This makes permissions a more direct connection between the bucket and the recipient.

September 27, 2022

Free PDF guide

Sign up to our newsletter and download the "Git Tips and Tricks" guide.

In this article