Trying to generate a presigned url link so an user can download an Amazon S3 object, but getting invalid request
When you generate a pre-signed GET object URL, you need to provide all of the same params that you would pass to Aws::S3::Object#get
.
s3.get(sse_customer_algorithm: 'AES256', sse_customer_key: customer_key).body.read
This means you need to pass the same sse_customer_* options to #presigned_url
:url = obj.presigned_url(:get,
sse_customer_algorithm: 'AES256',
sse_customer_key: customer_key)
This will ensure that the SDK correctly signs the headers that Amazon S3 expects when you make the final GET request. The next problem is that you are now responsible for sending those values along with the GET request as headers. Amazon S3 will not accept the algorithm and key in the query string.uri = URI.parse(url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Get.new(uri.request_uri, {
"x-amz-server-side-encryption-customer-algorithm" => 'AES256',
"x-amz-server-side-encryption-customer-key" => Base64.encode64(cpk),
"x-amz-server-side-encryption-customer-key-MD5" => Base64.encode64(OpenSSL::Digest::MD5.digest(cpk))
})
Please note - while testing this, I found a bug in the presigned URL implementation of the current v2.0.33 version of the aws-sdk
gem. This has been fixed now and should be part of v2.0.34 once it releases.See the following gitst for a full example that patches the bug and demonstrates:
- Uploads an object using a cpk
- Gets the object using the SDK
- Generates a presigned GET url
- Downloads the object using just Net::HTTP and the presigned URL
https://gist.github.com/trevorrowe/49bfb9d59f83ad450a9e
Just replace the bucket_name
and object_key
variables at the top of the script.
Does an S3 bucket need to be Public to serve user viewable images to an app?
Objects in Amazon S3 are private by default. You can grant access to an object in several ways:
- A Bucket Policy that can grant access to everyone ('Public'), or to specific IP addresses or users
- An IAM Policy on an IAM User or IAM Group that grants access to that user or group -- however, they would need to access via an AWS SDK so that they can authenticate the call (eg when an application makes a request to S3, it would make an authenticated API call)
- An Access Control List (ACL) on the object, which can make the object public without requiring the bucket to be public
- By using an Amazon S3 pre-signed URL, which is a time-limited URL that provides temporary access to a private object
Generating the pre-signed URL only takes a few lines of code and does not involve an API call to AWS. It is simply creating a hash of the request using your Secret Key, and then appending that hash as a 'signature'. Therefore, there is effectively no speed impact of generating pre-signed URLs for all of your images.
I don't see how SEO would be impacted by using pre-signed URLs. Only actual web pages (HTML) are tracked in SEO -- images are not relevant. Also, the URLs point to the normal image, but have some parameters at the end of the URL so they could be tracked the same as a non-signed URL.
Related Topics
Rails3 Activerecord::Statementinvalid:... No Such Table in Every Test
Rvm Can No Longer Install 1.8.7-P352 on MAC Os X Mountain Lion
Ruby Fails on Osx Lion with Rbenv
Use Pry in Gems Without Modifying The Gemfile or Using 'Require'
How to Troubleshoot Memory Bloat at Boot for Rails App
Where to Reopen a Class in Ror
Capybara & Cucumber | Getting Cookies
Many to Many Table with an Extra Column in Rails
Rails Gem Prawn, Image and Anchor
How to Avoid Circular Creation of Associated Models in Factory_Girl
How to Tell Unicorn to Understand Heroku's Signals
Where Is Ruby's Erb Format "Officially" Defined
Without Converting to a String, How Many Digits Does a Fixnum Have
Why Use Gemspec + Gemfile When Checking for Dependencies
How to Catch an "Undefined Method '[]' for Nil:Nilclass" Error