Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AWS Bucket policy for a reverse proxy

I am trying to use an s3 bucket as a simple web host, but want to put it behind a reverse proxy capable of layering some required security controls.

I have IP addresses associated with the reverse proxy that I would like to restrict the s3 web access to. When I apply the IP based restriction in the bucket policy though it seems to make administrative interaction in the account extremely difficult to blocked.

I would like not disrupt access from within the account via console/IAM user/federated role, but enable http access to the s3 site for just the IPs associated with the reverse proxy.

The AWS documentation on what is required to enable web access shows that I need this policy statement, so I have included it to start with.

{
    "Id": "S3_Policy",
    "Statement": [
        {
            "Sid": "AllowWebAccess",
            "Effect": "Allow",
            "Principal": "*",
            "Action": [
                "s3:GetObject"
            ],
            "Resource": [
                "arn:aws:s3:::mybucket/*"
            ]
        }
    ]
}

Then I want to restrict the web traffic to a particular set of IPs so I have added this statement.

{
    "Id": "S3_Policy",
    "Statement": [
        {
            "Sid": "AllowWebAccess",
            "Effect": "Allow",
            "Principal": "*",
            "Action": [
                "s3:GetObject"
            ],
            "Resource": [
                "arn:aws:s3:::mybucket/*"
            ]
        },
        {
            "Sid": "DenyNonProxyWebAccess",
            "Effect": "Deny",
            "Principal": "*",
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::mybucket/*", 
                "arn:aws:s3:::mybucket"
              ],
            "Condition": {
                "NotIpAddress": {
                    "aws:SourceIp": [
                        "99.99.99.1/32",
                        "99.99.99.2/32",
                        "99.99.99.3/32",
                        "99.99.99.4/32",
                        "99.99.99.5/32"
                    ]
                }
            }
        }
    ]
}

This deny policy has the unintended consequence of blocking my ability to access it from inside my account with IAM users or assumed federated roles, so I have added an explicit allow for those resources. I would like to just place a blanket allow for "the account" if possible. That leaves me with this policy, and it just doesn't seem to work how I would like it to. I can't seem to either manage it as my users or access the web content from the proxy.

{
    "Id": "S3_Policy",
    "Statement": [
        {
            "Sid": "AllowWebAccess",
            "Effect": "Allow",
            "Principal": "*",
            "Action": [
                "s3:GetObject"
            ],
            "Resource": [
                "arn:aws:s3:::mybucket/*"
            ]
        },
        {
            "Sid": "DenyNonProxyWebAccess",
            "Effect": "Deny",
            "Principal": "*",
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::mybucket/*", 
                "arn:aws:s3:::mybucket"
              ],
            "Condition": {
                "NotIpAddress": {
                    "aws:SourceIp": [
                        "99.99.99.1/32",
                        "99.99.99.2/32",
                        "99.99.99.3/32",
                        "99.99.99.4/32",
                        "99.99.99.5/32"
                    ]
                }
            }
        },
        {
            "Sid": "AllowAccountUsersAccess",
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws:IAM::999999999999:user/user@place",
                    "arn:aws:IAM::999999999999:user/user2@place",
                    "999999999999"
                ]
            },
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::mybucket/*", 
                "arn:aws:s3:::my bucket"
            ]
        } 
    ]
}

Is there a way to have an S3 bucket be a static web host restricted to only select IP ranges for web access, without disrupting the ability to manage the bucket itself from the account?

like image 488
Matthew Lee Avatar asked Nov 08 '25 10:11

Matthew Lee


1 Answers

There are multiple ways that access can be granted to resources in an Amazon S3 bucket:

  • IAM permissions
  • Bucket Policy
  • Pre-signed URL

If an access request meets any of the above, they will be granted access (although a Deny might override it).

IAM Permissions are used to assign permissions to a User or Group. For example, if you want to have access to the bucket, you can add create a policy and assign it to you as an IAM user. If you wish all of your administrators to access the bucket, then put them in an IAM Group and assign the policy to the group. All access made this way needs to be done with AWS credentials (no anonymous access).

A Bucket Policy is typically used to grant anonymous access (no credentials required), but can include restrictions such as IP address ranges, SSL-only, and time-of-day. This is the way you would grant access to your reverse proxy, since it is not sending credentials as part of its requests.

A Pre-signed URL can be generated by applications to grant temporary access to a specific object. The URL includes a calculated signature that authenticates the access. This is typically used when generating links on HTML pages (eg to link to private images).

Your situation

So, firstly, you should grant access to yourself and your administrators, using a policy similar to:

{
    "Id": "S3_Policy",
    "Statement": [
        {
            "Sid": "AllowWebAccess",
            "Effect": "Allow",
            "Action": [
                "s3:GetObject"
            ],
            "Resource": [
                "arn:aws:s3:::mybucket/*"
            ]
        }
    ]
}

Note that there is no Principal because it applies to whatever users/groups have been assigned this policy.

Next, you wish to grant access to your reverse proxies. This can be done via a Bucket Policy:

{
    "Id": "S3_Policy",
    "Statement": [
        {
            "Sid": "DenyNonProxyWebAccess",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::mybucket/*", 
                "arn:aws:s3:::mybucket"
              ],
            "Condition": {
                "IpAddress": {
                    "aws:SourceIp": [
                        "99.99.99.1/32",
                        "99.99.99.2/32",
                        "99.99.99.3/32",
                        "99.99.99.4/32",
                        "99.99.99.5/32"
                    ]
                }
            }
        }
    ]
}

This policy is permitting (Allow) access to the specified bucket, but only if the request is coming from one of the stated IP addresses.

Granting access via Allow is always preferable to denying access because Deny always overrides Allow. Therefore, use Deny sparingly since once something is denied, it cannot then be Allowed (eg if a Deny blocks administrative access, you cannot then Allow the access). Deny is mostly used where you definitely want to block something (eg a known bad actor).

VPC Endpoint

A final option worth considering is use of a VPC Endpoint for S3. This allows a directly communication between a VPC and S3, without having to go via an Internet Gateway. This is excellent for situations where resources in a Private Subnet wish to communicate with S3 without using a NAT Gateway.

Additional policies can be added to a VPC Endpoint to define which resources can access the VPC Endpoint (eg your range of Reverse Proxies). Bucket Policies can specifically refer to VPC Endpoints, permitting requests from that access method. For example, you could configure a bucket policy that permits access only from a specific VPC -- this is useful for separating Dev/Test/Prod access to buckets.

However, it probably isn't suitable for your given use-case because it would force all S3 traffic to go via the VPC Endpoint, even outside of your reverse proxies. This might not be desired behavior for your architecture.

Bottom line: IAM policies grant access to users. Bucket Policies grant anonymous access.

You certainly do not "need" the first policy you have listed, and in fact you should rarely ever use that policy because it grants complete access to the bucket.

like image 190
John Rotenstein Avatar answered Nov 10 '25 18:11

John Rotenstein



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!