A couple weeks ago I was preparing for a workshop. Making life easy for students on their fun day of hacking, GraphQL, Serverless, React, and Gatsby.
The workshop was great and then my AWS account got suspended 😅
Uploading files to S3 from the browser is really hard. You need an S3 bucket, that's easy, then you need a server that accepts a file from your submitted form and uploads it to S3 with the SDK and gets back the URL and ...
You can't upload files straight to S3 from the browser because Amazon believes in security by default. Thou shalt not have an app out in the wild that is not secure.
Great in theory, annoying when you're tight against a deadline for a toy app you intend to kill 3 days later.
You can make an S3 bucket public. You can make files public too. You need an S3 access key to upload anyway.
Yes even if it's a public bucket and a public file. You have to upload securely.
Were this not the case, anyone could upload a bunch of nefarious things to your S3 and report you to the FBI. You don't want that. 😉
Uploading a file with the S3 SDK looks something like this:
Looks fine, right?
Notice this part:
If you send that to the browser, anyone can see your credentials and upload nefarious things.
You're supposed to run that code on a server.
That keeps your credentials secure (unless your server is hacked) and means you now have to deal with file uploads in two places:
- browser submits file upload form to server
- server uploads file to S3
- server returns URL
But I didn't want a server.
The whole point of my workshop is that there's no servers and everything runs on AWS Lambda. Plus data transfer on AWS can get expensive.
You don't want to transfer each file twice. First to your lambda, then to your S3.
AWS offers a secure solution 👉 pre-signed URLs.
With a pre-signed URL, your server creates a unique URL with credentials, filenames, and other params baked in. Your browser code makes a
fetch() request with some data and a file shows up on your S3 bucket.
You request a new pre-signed URL for the next file.
I'll write more about secure S3 file uploads from the browser soon, but here's the server code in a nutshell:
You still need a server, but you can run this on a Lambda. It's a small request that's quick to calculate. A perfect fit ☺️
Returns an upload URL that expires in 5 minutes with a pre-baked filename and read URL.
See this part of my code:
Before I cleaned my GitHub that contained actual access keys. I knew it was bad, I knew I shouldn't, I did it anyway. Correct secrets management just felt too complicated in this case.
First I created a special S3 user with access to a specific bucket. Then I copy pasted those credentials into my code and pushed away.
You might steal my credentials but it's okay. They're limited!
And boy oh boy did that make the workshop wonderful. Having access keys baked into my code made everything so easy. Pull my code and get started right away.
We built the whole UI before students had to even think about AWS. It was fire. 🔥
A few days before the workshop, almost as soon as I "leaked" my credentials, Amazon sent me an email.
Hey we saw your credentials got leaked. We get it, shit happens, no biggie, please fix it ... ... AND IF YOU DON'T WE WILL KILL YOUR ACCOUNT
Whoa wait what? They can't be serious.
So I ignored the warning and thought to myself Pfft, paranoid ops people, it's an example account. Who cares
They kept emailing me. First every day. Then every couple hours. Like yo, you should really fix this.
After the workshop I though fine fine, if you insist, I'll fix it.
Once your AWS credentials are out there, there's only one thing you can do: change everything
- You have to change your AWS password
- You have to go into the IAM app and delete all existing keys for all sub-users
- Generate new keys
- Scrub GitHub clean
First 3 are easy. Go into your AWS console and click the things.
The 4th ... how the hell do you scrub your entire GitHub history of a specific string? BFG
Put the strings you want to replace in
passwords.txt and BFG rewrites your entire history. Each password becomes a
accessKeyId: "***REMOVED***", ... but you can still see the diff. Lol
I guess that's part of why you also delete the keys. Deactivating isn't enough Amazon says, you have to delete.
Once you've finished all the steps tell Amazon. They might be omniscient in detecting that you did something bad, but they don't see that you fixed it. I don't know why.
I forgot to tell them and my account got suspended.
swizec.com looked like a brutalist website, techletter.app didn't work so I couldn't write newsletters, everything died. You don't know how much of your life relies on AWS until it dies.
Amazon support was wonderful however. A little aloof when scolding me for leaking the credentials, but absolutely wonderful once I got suspended and started crying about it on Twitter.
What surprised me most was that I could use Support with a suspended account. Can't log into AWS, can't see any of the services, but you can see support and get help.
Top notch UX 👌
PS: everything works now ^_^
Here's how it works 👇
And get thoughtful letters 💌 on mindsets, tactics, and technical skills for your career. Real lessons from building production software. No bullshit.
"Man, love your simple writing! Yours is the only newsletter I open and only blog that I give a fuck to read & scroll till the end. And wow always take away lessons with me. Inspiring! And very relatable. 👌"
Ready to Stop copy pasting D3 examples and create data visualizations of your own? Learn how to build scalable dataviz components your whole team can understand with React for Data Visualization
Curious about Serverless and the modern backend? Check out Serverless Handbook, modern backend for the frontend engineer.
Ready to learn how it all fits together and build a modern webapp from scratch? Learn how to launch a webapp and make your first 💰 on the side with ServerlessReact.Dev
By the way, just in case no one has told you it yet today: I love and appreciate you for who you are ❤️