AWS CloudFront Returns Access Denied from S3 Origin with Query String
After investigating it turns out that if a bucket is private, then S3 will return a 403 instead of a 404 if an object does not exist in the bucket which makes sense from a security point of view (prevents object enumeration etc.).
The viewer request code in the Lambda from the blog post transformed the image url when the query string was present. If this image doesn't exist, it generates it on the fly. The origin response functino from the blog post is checking for a status of 404 in order to trigger the image resizing. However when the bucket is made private, the response is 403 so instead the Lambda@Edge just forwards the response. The fix is to either handle the 403 or make the bucket public. I've gone with the former
Lambda@Edge works with s3 via special user. So, you have to add rules in your s3 bucket policy, like this:
{
"Version": "2008-10-17",
"Id": "PolicyForCloudFrontPrivateContent",
"Statement": [
{
"Sid": "1",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity XXXXX"
},
"Action": [
"s3:GetObject"
],
"Resource": "arn:aws:s3:::xxx/*"
},
{
"Sid": "2",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity XXXX"
},
"Action": [
"s3:ListBucket"
],
"Resource": "arn:aws:s3:::xxxx"
}
]
}