Reputation: 6129
Related to my question about the same thing in Go.
I would like to do a pre-signed POST file upload to a bucket on AWS S3 which only has public-read with the following bucket policy:
{
"Version": "2012-10-17",
"Id": "Policy1441191234567",
"Statement": [
{
"Sid": "Stmt1441195123456",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::mytestbucket/*"
}
]
}
A pre-signed URL is created that allows anyone that has it to do an upload with HTTP POST like described here.
I have successfully got the pre-signed PUT to work that is described here. I.e. I have proper credentials in ~/aws/credentials
that has full access to the bucket.
In the AWS Ruby SDK, I have found that there’s a PresignedPost for the bucket so I have tried the following:
require 'aws-sdk-resources'
require 'net/http'
require 'time'
require 'uri'
s3 = Aws::S3::Resource.new(region:'eu-central-1')
bucket = s3.bucket('mytestbucket')
post = bucket.presigned_post({
key: 'larry',
acl: "public-read",
expires: Time.now() + 30,
content_length_range: 1...1024,
success_action_redirect: "https://example.com/callback",
})
puts post.url
puts post.fields
uri = URI(post.url)
fields = post.fields.merge(file: "ken sent me")
res = Net::HTTP.post_form(uri, fields)
puts res.body
Unfortunately, running this results in an error:
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>InvalidArgument</Code><Message>Conflicting query string parameters: acl, policy</Message><ArgumentName>ResourceType</ArgumentName><ArgumentValue>acl</ArgumentValue><RequestId>6132C47A14212345</RequestId><HostId>abcdKciFUKxvC4717Zm9w2ZB5lXJna+NSkxXzkb9123tjHZHb60JJa123KctSu862gY/j+a5+3w=</HostId></Error>
I have tried removing the acl
field, but that results in another error:
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>MethodNotAllowed</Code><Message>The specified method is not allowed against this resource.</Message><Method>POST</Method><ResourceType>BUCKETPOLICY</ResourceType><RequestId>9B3D7AAAE45BB47F</RequestId><HostId>yk823Z12345uucETlpQaG1234T0lxqjGAX4Uka123LQ6Pf22NVf45xxMmZAlFoQHaP+C4N60oLI=</HostId></Error>
The URI is: https://mytestbucket.s3.eu-central-1.amazonaws.com
What is the problem and how can I make it work?
Thanks for any help!
UPDATE
As one of the errors say, the issue is likely a conflicting acl and bucket policy. I would like it to be read for all and upload is only possible with a pre-signed URL (where I assume the owner becomes the one who created the URL). This is how I thought I had it set up.
Upvotes: 2
Views: 2987
Reputation: 6129
So I have updated the Go question with an answer and the same applies for Ruby. The problem I had was to correctly generate the multipart form data.
Upvotes: 0
Reputation: 126
I think that there are multiple plolicies in play here. The bucket policy and the post policy. See also the Ruby docs on PresignedPost -- you'll have to search for "Post Policy" as there is no anchor to the heading that I can see. It looks like Ruby creates a post policy for you, but that:
you must specify every form field name that will be posted by the browser. If you omit a form field sent by the browser, Amazon S3 will reject the request.
Additionally, it appear that this PresignedPost which is provided is meant to generate an HTML form which in turn generates the POST request and URL. You could generate that instead of letting the form do it. However if you already know all the details of the URL and request -- as asked in your Go question about the same thing -- why not Upload an Object Using a Pre-Signed URL.
Upvotes: 0