Working with Amazon CloudFront and S3 is a popular and powerful combo when it comes to hosting static files, configuring custom URLs, or enabling features like Apple Universal Links (via apple-app-site-association
). But it's also easy to make configuration mistakes that can cause frustrating errors like "Access Denied" or "NoSuchKey".
In this post, I’ll walk you through one of the most common mistakes, one that I recently ran into myself and how to fix it quickly.
❌ The Problem: “Access Denied” or 404 from CloudFront
Let’s say you want to serve a file like:
https://your-cloudfront-url/.well-known/apple-app-site-association
You upload the file with name apple-app-site-association, to your S3 bucket and configure a CloudFront distribution. In the process, you set:
-
Origin Domain:
your-bucket.s3.region.amazonaws.com
-
Origin Path:
/.well-known/apple-app-site-association
Everything seems perfect, but when you try to access the file through CloudFront, you get:
AccessDenied
or
The specified key does not exist.
🔍 What Went Wrong
Here’s the key misunderstanding:
The
Origin Path
in CloudFront is not the full file path, it’s a prefix that's automatically added to every request path.
So, if your CloudFront request is for:
/.well-known/apple-app-site-association
And your origin path is also set to:
/.well-known/apple-app-site-association
Then CloudFront tries to fetch:
S3: /.well-known/apple-app-site-association/.well-known/apple-app-site-association
Which obviously doesn’t exist — hence the error.
✅ The Correct Setup
Here’s how to fix and simplify things:
✅ Remove the Origin Path from your CloudFront origin settings.
✅ In your S3 bucket:
- Create a folder called
.well-known
-
Upload your file inside that folder:
.well-known/apple-app-site-association
✅ Make sure CloudFront has access (via Origin Access Control).
✅ Leave Origin path - optional as empty
✅ Secure Bucket Policy for CloudFront OAC:
Add this to your bucket policy (replace ACCOUNT_ID
and DISTRIBUTION_ID
):
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowCloudFrontAccessViaOAC",
"Effect": "Allow",
"Principal": {
"Service": "cloudfront.amazonaws.com"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::your-bucket-name/*",
"Condition": {
"StringEquals": {
"AWS:SourceArn": "arn:aws:cloudfront::ACCOUNT_ID:distribution/DISTRIBUTION_ID"
}
}
}
]
}
✅ Make sure your bucket has public access disabled
✅ Now, test the file at:
https://your-cloudfront-url/.well-known/apple-app-site-association
🎉 It should work!
🧠 Takeaway
When working with CloudFront and S3:
- Keep the Origin Path empty unless you really need it.
- Structure your S3 folders to match your desired URL path.
- CloudFront appends the request path to the origin path, so watch out for unnecessary nesting.
🔄 Bonus Tip: Content-Type for apple-app-site-association
If you’re hosting apple-app-site-association
, don’t forget to set the correct Content-Type in S3:
application/json
Even though the file doesn’t have a .json
extension, Apple expects it to have the correct Content-Type
header.
Hope this helps you avoid the same mistake and get your setup running smoothly.
If this saved you hours of debugging, you’re not alone 😄
Let me know in the comments if you’ve run into other CloudFront/S3 gotchas!
Top comments (0)