CloudFront Origin Access Control (OAC) is the modern, more secure way to restrict direct access to your S3 bucket content, forcing all requests through your CloudFront distribution.
Let’s see it in action. Imagine we have a website hosted in S3, and we want to serve images through CloudFront for performance and security.
First, we create an S3 bucket, let’s call it my-website-assets-12345. We upload an image.jpg to it.
aws s3 mb s3://my-website-assets-12345
aws s3 cp image.jpg s3://my-website-assets-12345/image.jpg
By default, this object is private. If we try to access it directly via its S3 URL (https://my-website-assets-12345.s3.us-east-1.amazonaws.com/image.jpg), we’ll get an Access Denied error. This is good.
Now, we set up a CloudFront distribution. We’ll create an Origin, pointing to our S3 bucket. Crucially, we’ll enable Origin Access Control.
When creating the OAC, CloudFront generates a unique service principal, something like s3.amazonaws.com/v4/xxxxxxxxxxxxxx. This is the identity CloudFront will use to access S3.
Next, we need to grant this OAC identity permission to read from our S3 bucket. We update the bucket policy.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowCloudFrontServicePrincipal",
"Effect": "Allow",
"Principal": {
"Service": "s3.amazonaws.com"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-website-assets-12345/*",
"Condition": {
"StringEquals": {
"AWS:SourceArn": "arn:aws:cloudfront::111122223333:distribution/E123ABCDEF456"
}
}
}
]
}
Wait, that’s the older Origin Access Identity (OAI) policy format. For OAC, the policy looks slightly different and leverages the service principal generated for the OAC. CloudFront itself will usually suggest the correct policy when you set up OAC. The key is that the Principal is {"Service": "s3.amazonaws.com"} and the Condition AWS:SourceArn matches your CloudFront distribution ARN. This ensures only your specific CloudFront distribution can access the objects via this policy.
The actual OAC configuration within CloudFront is what tells CloudFront to use specific AWS credentials (associated with the OAC) when fetching objects from S3. This is the mechanism that replaces the need for public S3 bucket ACLs or policies. CloudFront authenticates itself to S3 using the OAC identity.
The mental model is this: Your S3 bucket is a private vault. CloudFront is a secure courier. You give the courier a special key (the OAC) that only allows them to retrieve specific items (your bucket objects). Anyone else trying to get items directly from the vault (direct S3 access) using the old public road is denied.
The s3:GetObject action in the bucket policy, when combined with the AWS:SourceArn condition, is the critical gatekeeper. It says, "I will allow s3:GetObject if the request is coming from the CloudFront distribution identified by AWS:SourceArn." The OAC provides the authenticated identity that CloudFront uses to make that s3:GetObject request to S3.
When CloudFront receives a request for image.jpg from a viewer, it checks its cache. If it’s not in the cache, CloudFront then makes a request to your S3 origin. This request is authenticated using the OAC. S3 checks its bucket policy. Because the request is coming from the CloudFront distribution specified in the AWS:SourceArn condition and CloudFront is using the OAC’s identity, S3 grants s3:GetObject permission. CloudFront then retrieves the object and serves it to the viewer, caching it for future requests.
The AWS:SourceArn condition is vital. Without it, any CloudFront distribution using the same OAC identity could potentially access your bucket, which is not what you want. It ties the permission specifically to your distribution.
This setup effectively makes your S3 bucket contents inaccessible directly via S3 URLs, ensuring all traffic flows through CloudFront, where you can apply further caching, security headers, and other optimizations.
What most people don’t realize is that the OAC doesn’t just replace the need for public S3 buckets; it actively enforces the use of authenticated requests between CloudFront and S3. When you configure OAC, CloudFront automatically signs its requests to S3 using SigV4 with the credentials associated with that OAC. This is a fundamental shift from the older OAI method, which relied on bucket policy adjustments that were more prone to misconfiguration.
The next step is usually configuring custom error responses in CloudFront to handle cases where an object might not exist in S3, providing a more user-friendly experience than a raw S3 error.