Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AWS CloudFront Returns Access Denied from S3 Origin with Query String

I have setup a CloudFront distribution and a Lambda@Edge function as described in this article:

https://aws.amazon.com/blogs/networking-and-content-delivery/resizing-images-with-amazon-cloudfront-lambdaedge-aws-cdn-blog/

I now want to limit the S3 bucket to be private and only allow the CloudFront distribution access to the bucket. I've added an Origin Access Identity to the S3 Origin configuration, and updated the bucket policy to allow this OAI GetObject access to the bucket. I have removed the statement from the bucket policy that made it publicly readable, and changed the ACL to be private. If I do not include any query string parameters on the request to CloudFront, the image is returned as expected and the S3 link is not directly accessible.

However, the solution relies on passing in query parameters to resize the images on the fly (via 2 Lambda@Edge functions) and after making the bucket private I get an Access Denied 403 response from CloudFront.

I tried disabling forwarding of query strings which had no effect. I also tried only updating the bucket policy to remove public read access, and leave the ACL as PublicRead and it worked. So it makes me think something is up with the ACL being set to private

I was wondering if perhaps S3 is returning a 403 instead of a 404 when the bucket is made private? But then I don’t understand why adding the whitelisted query string param yields a different result to the request for the same image with no query string

Update

Example of working URL: http://<my_distro>.cloudfront.net/images/house.jpeg

Example of broken URL: http://<my_distro>.cloudfront.net/images/house.jpeg?size=1200

like image 253
ExoticChimp Avatar asked Apr 24 '18 18:04

ExoticChimp


People also ask

Why is CloudFront Access Denied?

If your distribution doesn't have a default root object defined, and a requester doesn't have s3:ListBucket access, then the requester receives an Access Denied error. The requester gets this error instead of a 404 Not Found error when they request the root of your distribution.

How do I fix an AWS S3 bucket policy and Public permissions access denied error?

If you're denied permissions, then use another IAM identity that has bucket access, and edit the bucket policy. Or, delete and recreate the bucket policy if no one has access to it. If you're trying to add a public read policy, then disable the bucket's S3 Block Public Access.

Why is my S3 Access Denied?

If you're getting Access Denied errors on public read requests that are allowed, check the bucket's Amazon S3 block public access settings. Review the S3 Block Public Access settings at both the account and bucket level. These settings can override permissions that allow public read access.

How do I enable CORS in CloudFront S3?

Step 1: enable CORS on your S3 bucketGo to your S3 bucket in the AWS (Amazon Web Services) console and select it. Click the Properties tab then open the Permissions area. You should see a button labelled 'Edit CORS Configuration' or something similar. Click it.


2 Answers

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

like image 190
ExoticChimp Avatar answered Oct 12 '22 05:10

ExoticChimp


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"
        }
    ]
}
like image 44
Aleksandr L Avatar answered Oct 12 '22 07:10

Aleksandr L