boto3 signature doesn't match with S3

2019-09-14 21:04发布

问题:

I'm trying to make an upload from Heroku to S3 using boto3 but I keep getting the error <Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message>. I've tried using a pre-signed post and a pre-signed url but the error persists. The credentials that I'm providing to Heroku to make the request are my root AWSAccessKeyID and Secret key, so I shouldn't have issues with permissions. I'm able to directly upload to S3 from my command line.

Values returned after generating a pre-signed post:

{'fields': {'x-amz-signature': '26eff5417d0d11a25dd294b059a088e2be37a97f14713962f4240c9f4e33febb', 'x-amz-algorithm': 'AWS4-HMAC-SHA256', 'key': u'sound.m4a', 'x-amz-credential': u'<AWSAccessID>/20161011/us-east-1/s3/aws4_request', 'policy': u'eyJjb25kaXRpb25zIjogW3siYnVja2V0IjogImZ1dHVyZWZpbGVzIn0sIHsia2V5IjogInNvdW5kLm00YSJ9LCB7IngtYW16LWFsZ29yaXRobSI6ICJBV1M0LUhNQUMtU0hBMjU2In0sIHsieC1hbXotY3JlZGVudGlhbCI6ICJBS0lBSTdLRktCTkJTNEM0VktKQS8yMDE2MTAxMS91cy1lYXN0LTEvczMvYXdzNF9yZXF1ZXN0In0sIHsieC1hbXotZGF0ZSI6ICIyMDE2MTAxMVQyMDM4NDlaIn1dLCAiZXhwaXJhdGlvbiI6ICIyMDE2LTEwLTExVDIxOjM4OjQ5WiJ9', 'x-amz-date': '20161011T203849Z'}, 'url': u'https://s3.amazonaws.com/bucketname'}

Code currently on Heroku:

@api.route('/post_track', methods=['POST'])
@login_required
def post_track():
    if request.method == 'POST':
        file = request.files['file']
        track = Track.upload_fromJSON(request.form.get('share'), request.form.get('title'))

        //Postgres entry
        conn = get_conn()
        with conn.cursor() as cur:
            cur.execute('INSERT INTO tracks(user_id, title, share)'
                    'VALUES (%s, %s, %s) RETURNING id;',
                    (track.user_id, track.title, track.share))
            track_id = cur.fetchone()[0]
            conn.commit()

            //Obtain pre-signed request
            signed_request = get_signed_request(track.title, request.form.get('type'), track_id, file)
            return json.dumps({'response':signed_request})


def get_signed_request(title, type, track_id, file):
    S3_BUCKET = os.environ.get('S3_BUCKET')
    file_name = title
    file_type = type
    region = 'us-east-1'
    s3 = boto3.client('s3', region_name=region, config=Config(signature_version='s3v4'))

    presigned_post = s3.generate_presigned_post(
        Bucket = S3_BUCKET,
        Key = file_name
    )

    files = {'file': file}

    r_response = requests.post(presigned_post["url"], data=presigned_post["fields"], files=files)

    print(r_response)
    print(r_response.text)

I'm eventually going to set up the code to return the pre-signed request to my frontend and do a direct upload from there. Just doing this as a test run.

回答1:

I really had a hard time with this one. I reached out to S3 support and they said the request they were receiving looked good and that there must be something wrong with the way the signature was being generated on with Heroku. I reached out to Heroku and they didn't really respond. What solved the problem was deleting my AWS root access and generating a new one then reconfiguring heroku with the new access ID's. Super simple, but very strange that that was the issue. Hopefully this helps someone dealing with the same problem.