подпись boto3 не совпадает с S3

#heroku #amazon-s3 #boto3

#heroku #amazon-s3 #boto3

Вопрос:

Я пытаюсь выполнить загрузку с Heroku S3 помощью boto3 , но продолжаю получать сообщение об ошибке <Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message> . Я пытался использовать a pre-signed post и a pre-signed url , но ошибка сохраняется. Учетные данные, которые я предоставляю Heroku для отправки запроса, — это мой корневой AWSAccessKeyId и секретный ключ, поэтому у меня не должно быть проблем с разрешениями. Я могу напрямую загружать файлы в S3 из своей командной строки.

Значения, возвращаемые после создания предварительно подписанного сообщения:

 {'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'}
  

Код, который в настоящее время находится на 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)
  

В конечном итоге я собираюсь настроить код для возврата предварительно подписанного запроса в мой интерфейс и прямой загрузки оттуда. Просто делаю это в качестве тестового запуска.

Ответ №1:

Мне действительно было трудно с этим. Я обратился в службу поддержки S3, и они сказали, что запрос, который они получали, выглядел хорошо и что, должно быть, что-то не так с тем, как подпись генерируется в Heroku. Я обратился к Heroku, и они на самом деле не ответили. Что решило проблему, так это удаление моего корневого доступа AWS и создание нового, а затем перенастройка heroku с новыми идентификаторами доступа. Супер просто, но очень странно, что это была проблема. Надеюсь, это поможет кому-то справиться с той же проблемой.

Комментарии:

1. Вы получили ключи из csv, загруженного с консоли? В конце этого файла нет пустой строки, что приводит к тому, что некоторые инструменты (например, cat ) отображают a % , чтобы указать это. Если вы скопировали дополнительный символ, это не сработало бы. Кроме того, не рекомендуется использовать учетные данные учетной записи root. Рекомендуется использовать пользователей и роли даже для одного пользователя.

2. @JordonPhillips хотел запустить его с помощью root, чтобы убедиться, что ошибки не связаны с какими-либо проблемами с разрешениями. Я в замешательстве — csv, на который я смотрю, находится в AWSAccessKeyID одной строке и AWSSecretKey в строке ниже. Вы хотите сказать, что в конце каждого ключа должен быть пустой символ, например _