Securing S3 Assets


3 mins


recorded on iMac using the Chrome browser

This post is about securing S3 assets.

Certainly, S3 has been used to back applications for a long time. Uh, no big surprise there - it works.

Well, this post is about a particular scenario that I found challenging to get right and had a couple of edge cases. A very obscure case is that could leak confidential member data. And by member data, I mean, posts. No PII data was leaking - neither passwords nor email addresses.

But under a particular scenario, if a user were to gain access to the bucket name and the member name of another member, that third party could view posts for the first member, so obviously that’s not good.

Here’s how I resolved this.

First of all, I removed all public access to the bucket. That’s procedure number one. Next, the member bucket/folder were created per the usual techniques.

I then created the cloudfront distribution of that folder using the S3 REST endpoint and not the S3 website definition - this was a big difference right here. Now, in order to access that REST endpoint, since it’s no longer public, I had to use an Origin Access Identity role to access that bucket and folder and that is kind of obscure.

It is in the documentation, but based upon my experience with this, it’s fairly obscure.

I continued using signed cookies for all requests to the pretty DNS name for the member. From there, this next part is what finally made everything work.

When you use the S3 REST endpoint, only the root folder’s index will be served automatically. Any nested folders, even if they have index files in them, will not be served. It’s not a website. It just doesn’t behave that way.

In order to get that behavior I’m using a Lambda@Edge function to rewrite the request URI. It triggers on any origin request.

All requests that end with ’/’ are rewritten to ’/index.html’. That gives me the ability to transform any depth of a path as long as it ends in ’/’ to properly include the ‘index.html’ in the request, ensuring that the member gets the resource they expect and doesn’t encounter the ‘specified key does not exist’ error.

It works very well.

So finally, all access requires a login which creates a user authentication jwt token and that also generates the signed cookies that are tied to the members.

A logout deletes those cookies and they expire in 10 hours, even if you stay logged in. If you don’t have that cookie, you’re not getting access to any member folders.

It’s just that simple. That’s it.

- jbminn