Skip to content
Go back

A funny way to restrict access to website hosted on S3

Edit page

S3 is a popular choice when you want to host a static website. Often, “a website” means a public website. But not all websites are made to be public. If you tried googling the options to restrict access to the website, you’ve probably seen the recipes like restricting based on IP addresses or even 3-rd party services.

IP address-based approach doesn’t work for me, because I often work from home and I definitely don’t want to whitelist my ISP’s subnets. The 3-rd party services are by default to be avoided when it’s about security. So I had to look for alternatives.

S3 bucket policies seemed like a good area to learn more about. One of the optional IAM policy elements is Condition. It allows you to specify under what circumstances the policy is applied. In an example I’ve mentioned previously, they use Condition to allow access when the request comes from the IP address (aws:SourceIp) that belongs to a specific subnet.

I was curious what other keys similar to aws:SourceIp are there, and discovered this list of Global Condition Keys. Among the others, there are:

The last one looked promising, because I knew that faking the User-Agent sometimes can be useful. I thought that there should be Chrome extensions that allow you to exactly this.

Condition Operators are how you check if the value matches the criteria you have. In my case, I want to allow access if aws:UserAgent contains some predefined secret substring, so I’m going to use StringLike operator for this. Here’s what my bucket policy looks like:

{
  "Version": "2008-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::agibalov-dummy-bucket1/*",
      "Condition": {
        "StringLike": {
          "aws:UserAgent": "*secret123*"
        }
      }
    }
  ]
}

So, only if HTTP request has the User-Agent header and the value contains secret123, access will be granted. Here’s a demo (I’m using User-Agent Switcher for Google Chrome):

And after switching to a custom User-Agent that has my secret substring secret123:

I definitely don’t recommend this approach for production, but in some cases it should be good enough for development sandboxes.


Edit page
Share this post on:

Previous Post
My Take on SOLID
Next Post
Using CloudFormation to route the webhooks