Last time, I walked through directly uploading an image to an S3 bucket from the browser with no server involved. That last bit is important. If you are using a server, then PreSigned URLs are a better choice as they do not require a world-writable bucket.
The world-writable version scales out to infinity, or at least to S3s limits, which are simply amazing, but at lower volumes or when your servers need to be involved anyway, pre-signing URLs comes with less risk of people filling up your buckets with crap.
Let’s look at how to do this in Rails. To sign requests we need the
aws-sdk gem. In your Gemfile:
In order to access AWS, the gem needs to find your credentials.
The gem first looks for
ENV['AWS_SECRET_ACCESS_KEY']. In production you would commonly set
these environment variables in the web server.
Alternatively, you can setup a
This approach works well in production if you securely store the credentials using something like sekrets.
Finally, if you’re playing around on your dev machine and have a properly formatted AWS credential file it will be used automatically. Typically, you wouldn’t do this in production.
Now that credentials are out of the way, we need an
If we’re passing in credentials, it’s
Once we have the resource object, all we need to get the presigned URL is the bucket name, the path to the file we want to access.
path is the full path of the file in the bucket (or just the
filename, if it’s in the root of the bucket). The above gets permission
to write the object, you could also request a read only URL by using
:get instead of
:put By default, the presigned url becomes invalid
after 900 seconds (15 minutes). You can adjust this by passing in the
expires_in option (in seconds):
Once we have the URL we can directly upload an image from Rails (presumes a file field called photo in your form):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Next time we’ll look at combining server generated signatures with a browser side AJAX upload.