Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I get boto to generate signed URLs for S3 that trigger downloads?

Tags:

boto

I've attempted this:

connection = S3Connection(
    aws_access_key_id=settings.AWS_ACCESS_KEY_ID,
    aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY)

url = connection.generate_url(
    60,
    'GET',
    settings.AWS_STORAGE_BUCKET_NAME,
    self.get_object().image,
    headers={'Content-Type': 'application/octet-stream'})

but when I try to visit the signed URL I get this message:

The request signature we calculated does not match the signature you provided. Check your key and signing method.

If I remove the headers attribute on the other hand, I can access the image just fine. What am I doing wrong?

like image 563
Kit Sunde Avatar asked May 07 '13 00:05

Kit Sunde


People also ask

How do S3 pre-signed URLs work?

Pre-signed URLs are used to provide short-term access to a private object in your S3 bucket. They work by appending an AWS Access Key, expiration time, and Sigv4 signature as query parameters to the S3 object. There are two common use cases when you may want to use them: Simple, occasional sharing of private files.

How do I create a signed URL?

To create a valid pre-signed URL for your object, you must provide your security credentials, specify a bucket name, an object key, specify the HTTP method (for instance the method is "GET" to download the object) and expiration date and time. Anyone who receives the pre-signed URL can then access the object.

Are S3 pre-signed URLs secure?

There is an access check on the S3 side but that only checks whether the signer entity is allowed to get the file. You can remove that permission but that invalidates all signed URLs. Signed URLs provide secure a way to distribute private content without streaming them through the backend.


1 Answers

The issue is that you can't set arbitrary headers using generate_url, and while the response_headers option exists AWS also has limited options as to what you can set. This will do what's expected in this case.

url = connection.generate_url(
    60,
    'GET',
    settings.AWS_STORAGE_BUCKET_NAME,
    self.get_object().image,
    response_headers={
        'response-content-type': 'application/octet-stream'
    })
like image 181
Kit Sunde Avatar answered Oct 22 '22 22:10

Kit Sunde