Last Updated: July 26, 2022
·
37.94K
· mcansky

Signing Amazon S3 URLs

Using the aws gem (https://github.com/appoxy/aws/) you can easily handle put and get actions in a bucket but if you've set your bucket rights to private you will need a bit more code to provide signed and time limited urls.

AWS S3 has some documentation on the topic : http://s3.amazonaws.com/doc/s3-developer-guide/RESTAuthentication.html and it's quite easy to follow and get it working. Still the example is not Ruby code, so here is a ready to use one.

A signed S3 url is composed of the classic get url where you add your AWS Access key id, an expire date (in Unix format) and a signature. The first two are easy, the signature is where the fun is.

The signature is basically a base64 encoded string made from an OpenSSL HMAC digest.

You need two things as initial parameters :

  • expire date : a Unix time in the future
  • path : the path of the file in the S3 bucket (that's right this doesn't include the bucket name)

You need to create a new SHA1 digest using the OpenSSL lib :

digest = OpenSSL::Digest::Digest.new('sha1')

You then create the a string corresponding to the http request you want to make :

can_string = "GET\n\n\n#{expire_date}\n/#{S3_BUCKET}/#{path}"

You can do the final digest using that string, the previous request and the S3 key :

hmac = OpenSSL::HMAC.digest(digest, S3_SECRET_ACCESS_KEY, can_string)

The signature is made from that digest using the Base64 encoder :

signature = URI.escape(Base64.encode64(hmac).strip).encode_signs

You then just have to add up all of these to get the signed url :

"https://s3.amazonaws.com/#{S3_BUCKET}/#{path}?AWSAccessKeyId=#{S3_ACCESS_KEY_ID}&Expires=#{expire_date}&Signature=#{signature}"

All the code : https://gist.github.com/3434417.

The Base64.encode64 and URI.escape methods don't always encode some characters like "+", "?" etc ... You need to do it yourself. If you check the gist linked above you will find the String::encode_signs that encode those characters properly.

5 Responses
Add your response

Thanks!

over 1 year ago ·

Hi I wrote one up for bash shell: https://github.com/gdbtek/aws-tools

over 1 year ago ·

You don't need the CONTENT-MD5 or CONTENT-TYPE in the signature? http://s3.amazonaws.com/doc/s3-developer-guide/RESTAuthentication.html

over 1 year ago ·

nevermind, didn't read far enough in the doc

over 1 year ago ·

what about specifying a region ?

over 1 year ago ·