Загрузка браузера на s3 с ролями экземпляра

Это продолжение моего предыдущего вопроса о подписании документа политики с использованием профилей экземпляров.

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

Процесс настройки загрузок на основе браузера объясняется здесь, и все это работает в локальной тестовой среде.

Однако, как только мое приложение будет развернуто в экземпляре EC2, я вижу эту ошибку, когда браузер пытается загрузить файл:

<Error> <Code>InvalidAccessKeyId</Code> <Message>The AWS Access Key Id you provided does not exist in our records.</Message> <RequestId>...</RequestId> <HostId>...</HostId> <AWSAccessKeyId>ASIAxxxyyyzzz</AWSAccessKeyId> </Error> 

Значение ASIAxxxyyyzzz здесь происходит из учетных данных роли экземпляра , полученных из службы метаданных; кажется, что эти учетные данные не могут использоваться вне EC2 для облегчения загрузки на основе браузера.

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

 $token = $sts->assumeRole(array( 'RoleArn' => 'arn:aws:iam::xyz:role/mydomain.com', 'RoleSessionName' => 'uploader', )); $credentials = new Credentials($token['Credentials']['AccessKeyId'], $token['Credentials']['SecretAccessKey']); 

Этот вызов дает мне новый набор учетных данных, но при его использовании он дает ту же ошибку, что и выше.

Я надеюсь, что кто-то это сделал раньше и может рассказать мне, какую тупую вещь я пропустил 🙂

Related of "Загрузка браузера на s3 с ролями экземпляра"

Документы AWS очень сбивают с толку, но я подозреваю, что вам нужно включить параметр x-amz-security-token в запросе POST для загрузки S3 и что его значение соответствует SessionToken вы получаете из STS ( $token['Credentials']['SessionToken'] ).

Временные учетные данные STS действительны только при включении соответствующего токена безопасности.

Документация AWS для запроса POST гласит, что:

Для каждого запроса, использующего Amazon DevPay, требуется два поля формы для маркеров безопасности: один для токена продукта и один для токена пользователя.

но этот параметр также используется вне DevPay, чтобы передать токен STS, и вам нужно будет только один раз передать его в полях формы.

Как указано в ответе dcro , токен сеанса должен быть передан службе, которую вы используете при использовании временных учетных данных. В официальной документации упоминается поле x-amz-security-token , но, похоже, предполагается, что оно используется только для DevPay; это, вероятно, потому, что DevPay использует один и тот же тип временных учетных данных и поэтому требует токена безопасности сеанса.

2013-10-16 : Amazon обновила свою документацию, чтобы сделать это более очевидным.

Как оказалось, даже не нужно использовать STS; учетные данные, полученные службой метаданных, также имеют такой токен сеанса. Этот токен автоматически передается для вас, когда SDK используется вместе с временными учетными данными, но в этом случае окончательный запрос выполняется браузером и, следовательно, должен быть явно передан.

Ниже приведен мой рабочий код:

 $credentials = Credentials::factory(); $signer = new S3Signature(); $policy = new AwsUploadPolicy(new DateTime('+1 hour', new DateTimeZone('UTC'))); $policy->setBucket('upload.mydomain.com'); $policy->setACL($policy::ACL_PUBLIC_READ); $policy->setKey('uploads/test.jpg'); $policy->setContentType('image/jpeg'); $policy->setContentLength(5034); $fields = array( 'AWSAccessKeyId' => $credentials->getAccessKeyId(), 'key' => $path, 'Content-Type' => $type, 'acl' => $policy::ACL_PUBLIC_READ, 'policy' => $policy, ); if ($credentials->getSecurityToken()) { // pass security token $fields['x-amz-security-token'] = $credentials->getSecurityToken(); $policy->setSecurityToken($credentials->getSecurityToken()); } $fields['signature'] = $signer->signString($policy, $credentials); 

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

Разрешения были последней проблемой; мой код устанавливает ACL для public-read и для этого требуется дополнительное разрешение s3:PutObjectAcl .

 { "Version": "2012-10-17", "Statement": [ { "Action": [ "s3:PutObject", "s3:PutObjectAcl" ], "Sid": "Stmt1379546195000", "Resource": [ "arn:aws:s3:::upload.mydomain.com/uploads/*" ], "Effect": "Allow" } ] }