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:
aws:CurrentTime– you can restrict access to your website based on current time.
aws:Referer– restrict access based on the
Refererrequest header. If only you could make your browser send this header when you access the website, it would be a way to go. But I have no idea how to make Chrome do that.
aws:SourceIp– we’ve seen this one already.
aws:UserAgent– this one maps to
User-Agentrequest header. You can allow access for Chrome and forbid for IE.
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:
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
I definitely don’t recommend this approach for production, but in some cases it should be good enough for development sandboxes.