Up until now, every file I've touched in S3 has gone through the console, or through a bucket policy that made things public for everyone. Today's problem was different: how do you let one specific person upload or download one specific file, temporarily, without making anything public and without giving them AWS credentials at all? That's what presigned URLs solve. Alongside that, I set up SNS to get notified whenever something actually happens in a bucket, instead of having to go check manually.
The Problem With "Just Make It Public"
Public bucket policies work fine for something like a static website, where everyone should see the same content. They fall apart the moment access needs to be temporary or user-specific — a private document one customer should download, or an upload slot for one user that shouldn't stay open forever. Making the whole bucket public to solve that is the wrong tool for the job, and it's the kind of shortcut that turns into a real security problem later.
Implementing Presigned URLs
A presigned URL is a normal S3 object URL with a signature and expiry baked into the query string, generated using AWS credentials that already have permission on that object. Anyone holding that URL can perform the specific action it was signed for — a GET to download, a PUT to upload — until it expires, without needing any AWS credentials of their own.
I generated these using the AWS SDK rather than the console, since that's how this actually gets used in a real app: the backend decides someone is allowed to access a specific file, generates a short-lived signed URL for it, and hands that URL back to the client. The backend never has to stream the file itself, and the client never touches an AWS secret key.
The part worth paying attention to is the expiry window. Set it too long and you've basically recreated a public link with extra steps. Set it too short and legitimate users start hitting expired links mid-download. I ended up treating this as something to tune per use case rather than a single fixed number.
Adding SNS for Event Notifications
The second half of today was hooking up SNS (Simple Notification Service) to S3, so that instead of periodically checking a bucket to see if anything changed, the bucket tells me when something does. S3 can publish an event — object created, object removed, etc. — directly to an SNS topic, and anything subscribed to that topic (an email address, an endpoint, another service) gets notified.
Wiring this up is less about writing code and more about configuration: create the SNS topic, give the S3 bucket permission to publish to it, then configure the bucket's event notifications to fire on the events that matter (I focused on object creation for now, since "someone just uploaded something" is the one I actually needed to react to). Once that was in place, uploading a test file into the bucket produced a notification within seconds, with no polling involved anywhere.
Why These Two Belong Together
On their own, presigned URLs and SNS solve different problems — one is about controlled access, the other is about knowing when something happened. Put together, they start to look like the shape of a real upload pipeline: a backend issues a presigned URL so a user can upload directly to S3, and the moment that upload lands, an SNS notification fires so the rest of the system can react — kick off processing, update a database record, whatever needs to happen next — without the backend ever having to sit there polling the bucket to find out.
What's Next
Right now the SNS notification just proves the event fired — nothing is actually consuming it yet. The obvious next step is subscribing something more useful than my own inbox to that topic, likely an SQS queue or a Lambda function, so the notification actually triggers work instead of just being observed.
Top comments (0)