フランクフルトリージョンのS3アクセス失敗への対処法

2015.06.24

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

今日は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に統一してみてはいかがでしょうか。

参考

脚注

  1. 全言語のSDKを確認したわけではありませんので、こういう書き方にしています。