フランクフルトリージョンのS3アクセス失敗への対処法
今日はS3に関するちょっとしたハマりどころのご紹介です。
フランクフルトリージョンのS3へのアクセスに失敗する
先日チャイナリージョンを除く全リージョンのS3にオブジェクトを保存するプログラムを書いていたところ、フランクフルト(eu-central-1)リージョンへのアクセスのみ失敗する事象が発生しました。
PHPでの例
書いていたコードはPHPの以下のようなものです。利用しているSDKのバージョンは2.8.10で、コードはブログのために簡略化してあります。
$ cat s3.php <?php require 'vendor/autoload.php'; use AwsS3S3Client; $s3 = S3Client::factory(); // eu-west-1へのPutObjectは成功する $s3->putObject([ "Bucket" => "sample-eu-west-1", "Key" => "sample.txt", "Body" => "sample contents", ]); echo "Successed in eu-west-1"."n"; // eu-central-1へのPutObjectは失敗する $s3->putObject([ "Bucket" => "sample-eu-central-1", "Key" => "sample.txt", "Body" => "sample contents", ]);the echo "Successed in eu-central-1"."n"; $ php s3.php Successed in eu-west-1 Fatal error: Uncaught AwsS3ExceptionInvalidRequestException: AWS Error Code: InvalidRequest, Status Code: 400, AWS Request ID: 8123B096297AF66C, AWS Error Type: client, AWS Error Message: The authorization mechanism you have provided is not supported. Please use AWS4-HMAC-SHA256., User-Agent: aws-sdk-php2/2.8.10 Guzzle/3.9.3 curl/7.37.1 PHP/5.5.20 thrown in /Users/mochizukimasao/work/aws/aws-sdk-php/src/Aws/Common/Exception/NamespaceExceptionFactory.php on line 91
調べていたところ、FrankfurtのS3のみ、新しい署名バージョンのみに対応していることが理由だと判明しました。
S3 Signatureバージョン
S3で利用されている署名バージョンにはVersion 2とVersion 4が存在しています。v4のほうが新しいのですが、比較的歴史の浅いチャイナリージョンとフランクフルトリージョンでは、Signature v4のみがサポートされています。
ですが、AWS SDK for PHPでは *1、デフォルトでv2の署名を利用しようとしているため、フランクフルトリージョンへのアクセスに失敗しているというのが原因のようです。
解決策
AWS SDK for PHP v2の場合は、S3Client::factory()
で明示的にsignature versionを指定すればv4のsignatureが利用されます。v4の場合は、署名アルゴリズムの中でエンドポイントのリージョン名が必ず必要になるため、S3バケットの存在するリージョンもパラメータで指定してあげる必要があります。
$s3 = S3Client::factory([ 'signature' => 'v4', 'region' => 'eu-west-1' ]);
また、複数リージョンのS3バケットに対してアクセスする際には、S3Client::setRegion()
を実施して、その都度エンドポイントのリージョン名を切り替える必要があります。以上の点を踏まえると、先ほどのサンプルコードは以下のような内容になります。
$ cat s3.php <?php require 'vendor/autoload.php'; use AwsS3S3Client; $s3 = S3Client::factory([ 'signature' => 'v4', 'region' => 'eu-west-1' ]); $s3->putObject([ "Bucket" => "sample-eu-west-1", "Key" => "sample.txt", "Body" => "sample contents", ]); echo "Successed in eu-west-1"."n"; // 別リージョンのS3にアクセスする時は、明示的にリージョンを切り替える $s3->setRegion('eu-central-1'); $s3->putObject([ "Bucket" => "sample-eu-central-1", "Key" => "sample.txt", "Body" => "sample contents", ]); echo "Successed in eu-central-1"."n"; $ php s3.php Successed in eu-west-1 Successed in eu-central-1
無事成功しました。
実は、PHP SDKの内部で「フランクフルトリージョンへのアクセスの場合はv4を使う」というようなロジックが記載されているようで、signatureパラメータを与えずにregionパラメータだけを与えて実行したところしっかりv4が使われていました。ですが、明示的に記述しておいたほうが意図しないハマりを回避できるでしょう。
まとめ
TokyoリージョンのS3だけを使っていると遭遇しないエラーなので、最初に見た時には戸惑うかもしれません。
ですが参考に記したドキュメントにも記載がある通り、今後リージョンが増えた場合、S3ではフランクフルト同様にSignature v4のみがサポートされるようです。
Amazon S3 supports Signature Version 4, a protocol for authenticating inbound API requests to AWS services, in all AWS regions. At this time, existing AWS regions continue to support the previous protocol, Signature Version 2. Any new regions after January 30, 2014 will support only Signature Version 4 and therefore all requests to those regions must be made with Signature Version 4.
Authenticating Requests (AWS Signature Version 4)
Signature v4にすることでS3へのアクセスはよりセキュアになります。全てのリージョンのS3でSignature v4はサポートされていますので、こういった落とし穴を回避する目的も兼ねてS3へのアクセスをSignature v4に統一してみてはいかがでしょうか。
参考
- Appendix B: Authenticating Requests (AWS Signature Version 2) - Amazon Simple Storage Service
- Authenticating Requests (AWS Signature Version 4) - Amazon Simple Storage Service
- Using the AWS SDKs and Explorers - Amazon Simple Storage Service
- AWS Developer Forums: [Frankfurt] The authorization mechanism ...
脚注
- 全言語のSDKを確認したわけではありませんので、こういう書き方にしています。 ↩