- Newest
- Most votes
- Most comments
You're on the right track and you've already narrowed this down to the correct problem area. The fact that public access works but CloudFront with Origin Access Control (OAC) fails tells us the issue is almost certainly with the CloudFront-to-S3 trust relationship or the endpoint type in use. Let’s walk through a focused checklist, identify common pitfalls, and help you get this over the finish line.
Key areas to verify
-
S3 origin must use the REST endpoint, not the website endpoint Origin Access Control only works when CloudFront connects to the S3 REST endpoint (e.g. my-bucket.s3.ap-south-1.amazonaws.com). If you’ve configured your origin as the S3 static website endpoint (e.g. my-bucket.s3-website.ap-south-1.amazonaws.com), OAC will not work and you’ll consistently get AccessDenied. AWS documentation: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html
-
Bucket policy conditions must match exactly The bucket policy should permit access to the CloudFront service only when: The request comes from the CloudFront service principal cloudfront.amazonaws.com The SourceArn matches your CloudFront distribution ARN (Optional) The SourceAccount is included for added security Note: Including an ArnEquals condition for the OAC ID is not currently required by AWS and may actually cause unexpected behavior unless you are using a very specific advanced configuration. Here’s the recommended minimal bucket policy for use with OAC: { "Version": "2012-10-17", "Statement": [ { "Sid": "AllowCloudFrontOAC", "Effect": "Allow", "Principal": { "Service": "cloudfront.amazonaws.com" }, "Action": "s3:GetObject", "Resource": "arn:aws:s3:::my-bucket/*", "Condition": { "StringEquals": { "AWS:SourceArn": "arn:aws:cloudfront::123456789012:distribution/EDFDVBD6EXAMPLE" } } } ] } AWS documentation: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/using-iam-policies.html
-
CloudFront distribution must have OAC configured and attached Make sure that your CloudFront distribution is configured to use Origin Access Control, not the legacy OAI (Origin Access Identity). You can verify this by: Going to the CloudFront console Selecting your distribution Opening the Origins tab Checking that your origin is using OAC (should say "Origin Access Control settings: Enabled" with your OAC ID) If you're using CDK or CloudFormation, ensure the OAC is being created and properly attached to the origin. AWS Blog (overview of OAC): https://aws.amazon.com/blogs/networking-and-content-delivery/amazon-cloudfront-introduces-origin-access-control-oac/ AWS documentation on creating and associating an OAC: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html#access-control-migration
-
S3 Block Public Access and Object Ownership settings Since you're intentionally restricting public access, confirm the following: Block Public Access is enabled (you said “All false” which is OK for testing, but recommended to eventually re-enable) Object Ownership is set to "Bucket owner enforced" No public ACLs are lingering on objects (especially if uploaded via console or other tools that default to public-read) AWS documentation: https://docs.aws.amazon.com/AmazonS3/latest/userguide/about-object-ownership.html https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-control-block-public-access.html
-
CDN caching behavior You already ran an invalidation, which is good. But if you previously served index.html publicly, CloudFront may have cached a 200 response or an S3 redirect. If your origin is now blocked behind OAC and you’re still getting 403 or AccessDenied errors, make sure: You’re testing with a fresh browser or curl request (no stale cookies or cache) You check response headers (x-cache, x-amz-error-code) to identify if CloudFront is serving cached content or attempting an origin fetch You inspect the S3 server access logs or enable CloudTrail Data Events to confirm whether S3 is receiving the GetObject request at all AWS documentation: https://docs.aws.amazon.com/AmazonS3/latest/userguide/server-access-logging.html https://docs.aws.amazon.com/awscloudtrail/latest/userguide/logging-data-events.html
Troubleshooting actions Double-check that your origin domain name in CloudFront is set to the REST endpoint (not website hosting endpoint) Make sure the origin is assigned your OAC under “Origin access control settings” Replace the existing bucket policy with the exact AWS-recommended policy above, modifying only your bucket name, account ID, and distribution ID Re-run your invalidation, then fetch objects via curl and inspect x-cache, x-amz-error-code, and Via headers Enable S3 server access logs or CloudTrail data events for deeper visibility
Additional tips Once this is resolved, take time to document and templatize your secure static site delivery stack. Understanding how CloudFront, OAC, S3 ownership, and public access settings interact will help you avoid misconfigurations and onboard other developers faster. Consider turning this into a reusable CDK pattern, integrating automated policy validation and CloudFront-S3 integrity checks in your CI/CD pipeline.
Additional deep dive If you're still hitting a wall, feel free to drop in your CDK stack (at least the parts defining the S3 origin, OAC config, and the bucket policy) and I can help you review and tighten it up. This is what multi-region static site deployments with CloudFront + OAC are based on and can help you bulletproof this setup if you’re aiming for production-readiness or need to audit it for security.
Relevant content
asked 3 years ago
asked 3 years ago
asked 3 years ago
