0

First time using AWS S3 here. I've been trying to figure this out the entire week but I just can't get my Django + NGINX site to display both my CSS and uploaded images from S3. I'm probably missing something but I just don't know exactly. I've looked into this, this, and this but I'm still unable to get things running.

I have a Bucket Policy and a CORS Config in my bucket maybe you can take a look. What I have so far:

  1. My site works fine only without any CSS or other static files like images
  2. CSS and image file URLs are correct. They all direct to my S3 bucket.
  3. Image uploading has no problem saving to S3
  4. To test, accessing each CSS/image manually from the browser returns the standard AccessDenied page from S3
  5. I have an IAM role with the AmazonS3FullAccess policy applied to my EC2 instance
  6. All public access is blocked in my bucket

My Bucket Policy

For testing purposes, I created a user with AmazonS3FullAccess along with the role. Not sure if that's necessary...

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws:iam::<NUMBERS>:role/<MYEC2ROLE>",
                    "arn:aws:iam::<NUMBERS>:role/<MYUSER>",
                ]
            },
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::<MYBUCKET>",
                "arn:aws:s3:::<MYBUCKET>/*"
            ]
        }
    ]
}

My CORS Configuration

My gut tells me this is not needed. Or maybe I'm just hungry...

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
    <AllowedOrigin>*</AllowedOrigin>
    <AllowedMethod>POST</AllowedMethod>
    <AllowedMethod>GET</AllowedMethod>
    <AllowedMethod>PUT</AllowedMethod>
    <AllowedMethod>DELETE</AllowedMethod>
    <AllowedMethod>HEAD</AllowedMethod>
    <ExposeHeader>ETag</ExposeHeader>
    <AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>

Was there anything else I was supposed to do? I'll continue reading up on this and maybe figure it out.

halfer
  • 19,824
  • 17
  • 99
  • 186
enchance
  • 29,075
  • 35
  • 87
  • 127

1 Answers1

0

If you're trying to access the served resources in the browser then the IAM role no longer applies as the principal is the user in the browser not the EC2 host that runs the site.

If you don't mind the general public being able to access these resources then you can simply expand your bucket policy to grant public s3:GetObject such as below.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws:iam::<NUMBERS>:role/<MYEC2ROLE>",
                    "arn:aws:iam::<NUMBERS>:role/<MYUSER>",
                ]
            },
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::<MYBUCKET>",
                "arn:aws:s3:::<MYBUCKET>/*"
            ]
        },
        {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": [
                "arn:aws:s3:::<MYBUCKET>",
                "arn:aws:s3:::<MYBUCKET>/*"
            ]
        }
    ]
}

However, if you want to lock it down further there are couple of options you could take.

The first is if you want to restrict so that these assets are restricted to only be loaded on your site but not behind any security wall (there's no private information).

In this case you can use a CloudFront distribution in front of your S3 bucket with an attached AWS WAF. This WAF would simply reject any requests when the referer header is not your domain.

If there is private information you have 2 approaches:

Chris Williams
  • 32,215
  • 4
  • 30
  • 68
  • When I try to edit the original policy and change the Principal to `"*"` I get an access denied error. Is that correct? I'm already the account owner. – enchance Aug 22 '20 at 07:22
  • 1
    You likely have the `Block all public access` settings on which is causing this. If you temporarily disable this, then make your change and then re-enable all settings except "Block public and cross-account access to buckets and objects through any public bucket or access point policies" it should work :) – Chris Williams Aug 22 '20 at 07:29
  • Chris, does it really have to be `"Principal": "*",` to work? Your solution worked (using it now) but I'm just curious about the security implications. – enchance Aug 22 '20 at 18:54
  • So this is fine the objects should be accessible (in my example I limited to the `GetObject` action via a second statement). If the objects should not be publicly readable then I put a couple of suggestions :) – Chris Williams Aug 22 '20 at 18:59