Доступ к загрузке AWS S3 запрещен из-за предварительно подписанного сообщения, созданного с помощью AWS-SDK PHP

Я пытаюсь загрузить файл (изображение для моих тестов) в свою корзину s3 с предварительно подписанным сообщением, созданным с помощью AWS SDK PHP. Сначала я создаю предварительно подписанный пост, а затем вручную создаю запрос с заданными данными PostObjectV4 с помощью Postman или через простую html-форму ... После заполнения всего запроса в результате запроса Access Denied :-(. Пользователь, связанный с клиентом для создания PostObjectV4 имеет разрешенную политику s3: PutObject в соответствующем сегменте.

Я уже пробовал:

  • Установите мое ведро как общедоступное, и оно работает! Это указывает на то, что у меня проблема с разрешением / политикой ... К сожалению, моя корзина не обязательно должна быть общедоступной ...
  • Загрузите файл через командную строку aws, он тоже работает

PHP-код для создания предварительно подписанного поста (данные находятся в $ postObject):

$assetAwsS3Key = $this->getAssetAwsS3Key($asset);

$options = [
    ['starts-with', '$key', 'myDir/'],
];

// Optional: configure expiration time string
$expires = '+24 hours';

// Set some defaults for form input fields
$formInputs = ['acl' => 'private'];

$postObject = new PostObjectV4(
    $this->buildAwsS3UserClient(),
    $this->awsBucketName,
    $formInputs,
    $options,
    $expires
);

// Get attributes to set on an HTML form, e.g., action, method, enctype
$formAttributes = $postObject->getFormAttributes();

// Get form input fields. This will include anything set as a form input in
// the constructor, the provided JSON policy, your AWS access key ID, and an
// auth signature.
$formInputs = $postObject->getFormInputs();

return ['formAttributes' => $formAttributes, 'formInputs' => $formInputs];

Политика моего пользователя (используется для создания клиентов):

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetObject",
                "s3:DeleteObject"
            ],
            "Resource": [
                "arn:aws:s3:::awsBucketName/*"
            ]
        }
    ]
}

Моя простая HTML-форма для тестовой загрузки:

<form method="post" action="https://my-bucket.s3.eu-west-3.amazonaws.com" enctype="multipart/form-data">
        <input type="hidden" name="key" value="myKey/sources/myImg.jpg" /><br />
        <input type="file"   name="file" /> <br />
        <input type="hidden" name="X-Amz-Credential" value="MYUSERACCESSKEY/20190510/eu-west-3/s3/aws4_request" />
        <input type="hidden" name="X-Amz-Algorithm" value="AWS4-HMAC-SHA256" /> 
        <input type="hidden" name="X-Amz-Date" value="20190510T132109Z" />
        <input type="hidden" name="Policy" value='MYBASE64ENCODEDPOLICY' />
        <input type="hidden" name="X-Amz-Signature" value="MYSIGNATURE" />
        <input type="submit" name="submit"/>
    </form>

У вас есть идея / ключ к разгадке, почему эта загрузка завершилась неудачно, когда для корзины не разрешен публичный доступ для записи?

Спасибо заранее !


person ffouillet    schedule 10.05.2019    source источник
comment
Вы когда-нибудь находили решение этой проблемы? У меня такой же вопрос, и я хотел бы узнать ответ.   -  person Jeremy Glover    schedule 24.12.2019
comment
Привет, @JeremyGlover, пожалуйста, проверьте мой новый ответ на сообщение, это было слишком долго для комментария, надеюсь, мы поможем, или вы уже избавились от проблемы;)   -  person ffouillet    schedule 08.01.2020


Ответы (1)


Я избавился от проблемы, я поделюсь изменениями, которые я сделал здесь с момента моего первого сообщения, чтобы загрузка работала. При необходимости адаптируйте его под свои нужды.

Используемая конфигурация AWS: - Та же самая встроенная политика, прикрепленная к моему пользователю, что и в первом сообщении (убедитесь, что имя корзины вы указали в ключе ресурса) - Корзина S3 без политики, прикрепленной к it - S3 Bucket All Public Access Disabled отключен

Вот мой обновленный php-код для создания postObject:

    $objectKey = $this->objectKeyGenerator->getObjectKey($object);

    $options = [
        ['bucket' => $this->getBucketName()],
        ['eq', '$key', $objectKey],
        ['acl' => 'private']
    ];

    // Optional: configure expiration time string
    $expires = '+2 hours';

    // Set some defaults for form input fields
    $formInputs = [
        'acl' => $acl,
        'key' => $objectKey
    ];

    $postObject = new PostObjectV4(
        $this->getS3Client(),
        $this->getBucketName(),
        $formInputs,
        $options,
        $expires
    );

    // Get attributes to set on an HTML form, e.g., action, method, enctype
    $formAttributes = $postObject->getFormAttributes();

    // Get form input fields. This will include anything set as a form input in
    // the constructor, the provided JSON policy, your AWS access key ID, and an
    // auth signature.
    $formInputs = $postObject->getFormInputs();

    return ['formAttributes' => $formAttributes, 'formInputs' => $formInputs];

Какие изменения в генерации postObject по сравнению с моим первым постом:

  • Я больше не использовал опцию «начинается с» и генерировал ключ объекта вручную, чтобы загруженный файл нужно было выгружать только по сгенерированному ключу (если задан другой ключ, он завершится ошибкой из-за несоответствия ключей), но я думаю, что это не было причиной ошибки, и я уверен, что она всегда будет работать с опцией «начинается с».
  • Атрибуты bucket и acl теперь находятся в массиве $ options в виде примера кода Create PostObjectV4, приведенного в Руководстве разработчика AWS SDK для PHP (см. [https://docs.aws.amazon.com/sdk-for-php/v3/developer-guide/s3-presigned-post.html]).
  • В массиве $ formInputs присутствует ключ, так что я могу вернуть его в postObject (поскольку отправленный ключ должен быть рассчитанным). Думаю, это не обязательно.

Я попытался воспроизвести ошибку, удалив bucket и acl из массива $ option, и это привело к ошибке «403 Forbidden», но с сообщением «Invalid согласно Политика: Дополнительные поля ввода: bucket ', которые я считаю не очень очевидными ... Я не исследовал эту ошибку более подробно.

Я также делюсь своей html-формой, которая немного изменилась с момента первого сообщения, порядок полей ввода изменился и поле acl было добавлено, потому что это требуется политикой.

    <form method="post" action="https://my-bucket.s3.eu-west-3.amazonaws.com/" enctype="multipart/form-data">
    <input type="hidden" name="key" value="object/key.txt" /><br />
    <input type="hidden" name="acl" value="private"/>
    <input type="hidden" name="X-Amz-Credential" value="MYUSERACCESSKEY/20190510/eu-west-3/s3/aws4_request" />      
    <input type="hidden" name="X-Amz-Algorithm" value="AWS4-HMAC-SHA256" /> 
    <input type="hidden" name="X-Amz-Date" value="20200108T093921Z" />
    <input type="hidden" name="Policy" value='MYBASE64ENCODEDPOLICY' />
    <input type="hidden" name="X-Amz-Signature" value="MYSIGNATURE" />
    File: 
    <input type="file"   name="file" /> <br />
    <!-- The elements after this will be ignored -->
    <input type="submit" name="submit"/>

В заключение, в моем исходном сообщении я не говорю о конфигурации публичного доступа и политики сегмента s3 и думаю, что проблема могла быть здесь.

Надеюсь, это поможет, не стесняйтесь спрашивать подробности, если это необходимо.

person ffouillet    schedule 08.01.2020
comment
Отличная работа. В итоге я получил свою работу и использовал ключ массива key и сравнение starts-with, потому что я хотел убедиться, что файл был загружен именно в то место, которое я ожидал. Для входных данных формы я устанавливаю ключи acl и content-type. Для параметров формы я устанавливаю ключи acl, bucket, key и content-type. Спасибо за продолжение, и я рад видеть, что мы оба можем двигаться вперед. - person Jeremy Glover; 09.01.2020