RailsTweeter
RailsTweeter

Reputation: 1635

boto3 signed url resulting in SignatureDoesNotMatch

My code is successfully uploading documents into the correct bucket. I can login and see the docs in the buckets on AWS S3. When I try to use the generate_signed_url method in boto3 to obtain a URL for these documents that can then be sent to users for accessing the doc, I'm getting a SignatureDoesNotMatch with the message saying "The request signature we calculated does not match the signature you provided. Check your key and signing method."

When i save the object (verified that it is working correctly by logging into AWS and downloading the files manually), I use:

  s3 = boto3.client('s3', region_name='us-east-2', aws_access_key_id='XXXX', aws_secret_access_key='XXXX', config=Config(signature_version='s3v4'))

  s3.put_object(Bucket=self.bucket_name,Key=path, Body=temp_file.getvalue(),ACL='public-read')

Then, when I try to get the URL, I'm using:

  s3 = boto3.client('s3', region_name='us-east-2', aws_access_key_id='XXXX', aws_secret_access_key='XXXX', config=Config(signature_version='s3v4'))

  url = s3.generate_presigned_url(
        'put_object', Params={
        'Bucket':self.pdffile_storage_bucket_name, 
        'Key':self.pdffile_url
        },
        ExpiresIn=604799,
    )

I saw quite a bit of users on the web talking about making sure your AWS access key doesn't include any special characters. I did this, and I still get the same issue.

Upvotes: 2

Views: 12212

Answers (5)

Ojus sangoi
Ojus sangoi

Reputation: 716

I tried many solutions from many different places. None of the worked for me. Then i got a solution on GitHub, that worked for me. Here is the original solution, just copy pasting his solution.

s3 = boto3.client(
    's3', region_name='us-east-2',
    aws_access_key_id='XXXX', aws_secret_access_key='XXXX',
    config=Config(signature_version='s3v4'),
    endpoint_url='https://s3.us-east-2.amazonaws.com'
)

Upvotes: 7

Ryan Mahuron
Ryan Mahuron

Reputation: 11

As stated above, adding parameter config=Config(signature_version='s3v4') when creating the boto3 client (or boto3 Session) fixed this error.

Note also that Config is located in botocore.client

Upvotes: 0

Sher Sanginov
Sher Sanginov

Reputation: 595

I had a trailing space on my secret access key variable. That was causing the issue. E.g: AWS_SECRET_KEY = "xyz "

Upvotes: 1

Stefan
Stefan

Reputation: 807

(after 3+ hours of debugging and almost smashing the keyboard....)

in the response, it's telling you which header is missing:

<Error>
    <Code>SignatureDoesNotMatch</Code>
    <Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message>
    <!-- .... -->
    <CanonicalRequest>PUT (your pre-signed url)
    content-type:image/jpeg
    host:s3.eu-west-2.amazonaws.com
    x-amz-acl:

    content-type;host;x-amz-acl
    UNSIGNED-PAYLOAD</CanonicalRequest>

Needed a x-amz-acl header matching the ACL set when generating the pre-signed URL

def python_presign_url():
    return s3.generate_presigned_url('put_object', Params={
        'Bucket': bucket_name,
        'Key': filename,
        'ContentType': type,
        'ACL':'public-read' # your x-amz-acl
    })
curl -X PUT \
    -H "content-type: image/jpeg" \
    -H "Host: s3.eu-west-2.amazonaws.com" \
    -H "x-amz-acl: public-read" \
    -d @/path/to/upload/file.jpg "$PRE_SIGNED_URL"

Upvotes: 2

Michael - sqlbot
Michael - sqlbot

Reputation: 179084

You are generating a pre-signed URL for an upload, not a download. You don't want put_object here... it's get_object.

Also, as @ThijsvanDien pointed out, ACL='public-read' may not be what you want, when uploading -- this makes the object accessible to anyone with an unsigned URL.

Upvotes: 2

Related Questions