Reputation: 4468
I'm testing to generate pre-signed URL to upload files to S3. I have no issues generating the signed URL, but and I'm getting AccessDenied error when attempting to upload it.
I've summarised my issue to the following code for testing.
Source code
import boto3
import os
s3 = boto3.client('s3')
def list_files():
print("Listing files in bucket:")
bucket = boto3.resource('s3').Bucket(bucket_name)
for obj in bucket.objects.all():
print(" - "+obj.key)
bucket_name = "asf-bucket"
list_files()
key= "test.py"
print (" Generating pre-signed url...")
url=s3.generate_presigned_url('put_object', Params={'Bucket':bucket_name, 'Key':key}, ExpiresIn=3600, HttpMethod='PUT')
command="curl --request PUT --upload-file {} {}".format(key, url)
print(command)
print (" Uploading with curl ...")
os.system(command)
Script Output
$ python3 test.py
Listing files in bucket:
- Dropped text.txt
Generating pre-signed url...
curl --request PUT --upload-file test.py https://asf-bucket.s3.amazonaws.com/test.py?AWSAccessKeyId=----&Signature=----&Expires=----
Uploading with curl ...
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>AccessDenied</Code><Message>Access Denied</Message><RequestId>A0E4587FFEB9F1EE</RequestId><HostId>kvfkV7YdDmtNNCSfWAjDTdZ/8+y2HrfcXSseQPlrq0300vjg9zYe1H0Qidsqf7kcBIieUGoXoUA=</HostId></Error>
Tested with AWS root account. I've get the same error.
CORS configuration
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>POST</AllowedMethod>
<AllowedMethod>PUT</AllowedMethod>
<AllowedMethod>DELETE</AllowedMethod>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
What I'm missing?
https://docs.aws.amazon.com/AmazonS3/latest/dev/PresignedUrlUploadObject.html
Update - Adding content type
Following @kichik advice I added the content type with no changes on the current behaviour
url=s3.generate_presigned_url('put_object', Params={'Bucket':bucket_name, 'Key':key, 'ContentType':'text/plain'}, ExpiresIn=3600, HttpMethod='PUT')
command="curl --header \"Content-Type: text/plain\" --request PUT --upload-file {} {}".format(key, url)
Upvotes: 0
Views: 2768
Reputation: 4468
Everything was alright, the mistake was not escaping the URL on the shell.
So instead of
curl --request PUT --upload-file test.py https://asf-bucket.s3.amazonaws.com/test.py?AWSAccessKeyId=----&Signature=----&Expires=----
Do
curl --request PUT --upload-file test.py 'https://asf-bucket.s3.amazonaws.com/test.py?AWSAccessKeyId=----&Signature=----&Expires=----'
Upvotes: 3