AWS SDK (PHP) での認証なしの S3 へのアップロード

メモです。

パブリックで誰でもアップロードできる AWS S3 バケットにアップロードしたくて、AWS SDK for PHP のサンプルに沿って、次のコードをかいたとします:


upload_public_bucket.php

<?php

require 'vendor/autoload.php';

use Aws\S3\S3Client;

$s3 = new S3Client([
'version' => 'latest',
'region' => 'ap-northeast-1',
]);

try {
$s3->putObject([
'Bucket' => 'your-public-bucket',
'Key' => 'test.txt',
'Body' => 'test',
]);
} catch (Exception $e) {
echo "failed to upload:" . PHP_EOL . $e->getMessage() . PHP_EOL;
}


これを特に認証情報も設定してない個人の環境で実行すると、認証情報が取れなくてエラーになります (オンプレとか個人 PC とか):


Failed to upload:

Error retrieving credentials from the instance profile metadata server. (Error creating resource: [message] fopen(http://169.254.169.254/latest/meta-data/iam/security-credentials/): failed to open stream: Connection timed out

[file] /tmp/s3/vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.php

[line] 323)


特に認証情報プロバイダを指定しないと、環境変数やインスタンスメタデータを取りに行くようになっていて、最後のインスタンスサーバーに認証情報を取りにいこうとして、取れなくてエラーになる感じですね。


Aws\Credentials\CredentialProvider::defaultProvider はデフォルトの認証情報プロバイダです。このプロバイダは、クライアントの作成時に credentials オプションを指定しなかった場合に使用されます。このプロバイダは、環境変数、.ini ファイル (.aws/credentials ファイルから .aws/config ファイルの順)、インスタンスプロファイル (EcsCredentials から Ec2 メタデータの順) の順で認証情報のロードを試行します。


あえて認証情報を指定せずに匿名でアクセスする場合は credentialfalse を与えてクライアントのインスタンスを生成すればいいです:

$s3 = new S3Client([

'version' => 'latest',
'region' => 'ap-northeast-1',
'credentials' => false,
]);

案外 SDK のドキュメントに載ってなくて意外と調べないとわからなかったので地味なハマりポイントです。

実際のところはバケットポリシーで IP 制限するなりする用途の想定ですね。