albert
albert

Reputation: 4468

boto3: generate_presigned_url get access denied during upload

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

Answers (1)

albert
albert

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

Related Questions