テストステ論

高テス協会会長が, テストステロンに関する情報をお届けします.

AmazonS3Clientに独自S3実装に対してリクエストさせるには?

AmazonS3Clientはデフォルトでは, AWSのS3に問い合わせを行ってしまう.

原理的には, 独自S3実装に対して問い合わせが出来ないことはあり得ないと思うのだが, 実装が糞だとその限りではない. 例えば, Amazon S3と通信していることを前提にしている箇所があったり. (認証周りが怪しい)

とりあえず, リクエストの行き先を変更するには, setEndpointに設定すればいいだけのようである. 今回はテンポラリにhitachi.com(133.145.228.249)にリクエストを送ってみた. もちろん「そんなリクエストは不正だ」と言われて弾かれた. 日立のウェブサーバーは堅牢だ.

  val cli = new AmazonS3Client(new BasicAWSCredentials("accessKey", "secretKey"))
  cli.setEndpoint("133.145.228.249:80")
  cli.createBucket("mybucket")

createBucketを発行するどこかのパスで署名はしてるはずなので, 署名するコードも例外で落ちたりはしていないと分かる.

実験として, 以下のようにsetRegionをしてみたらどうなるかというと,

    val cli = new AmazonS3Client(new BasicAWSCredentials("accessKey", "secretKey"))
    cli.setEndpoint("133.145.228.249:80")
    cli.setRegion(Region.AP_Tokyo.toAWSRegion)
    cli.createBucket("mybucket")

今度は, 本当にnortheastのサーバに接続しにいってしまう. (そして, そんな糞みたいなアクセスキーはないと弾かれる)

tcpdump: data link type PKTAP
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on pktap, link-type PKTAP (Packet Tap), capture size 65535 bytes
18:42:13.557204 IP 192.168.179.3.51630 > s3-ap-northeast-1-r-w.amazonaws.com.https: Flags [S], seq 810890366, win 65535, options [mss 1460,nop,wscale 5,nop,nop,TS val 258622493 ecr 0,sackOK,eol], length 0
18:42:14.559787 IP 192.168.179.3.51630 > s3-ap-northeast-1-r-w.amazonaws.com.https: Flags [S], seq 810890366, win 65535, options [mss 1460,nop,wscale 5,nop,nop,TS val 258623493 ecr 0,sackOK,eol], length 0

これは, "Overrides the default endpoint for this client. Callers can use this method to control which AWS region they want to work with."とコメントに書いてあるように, AWSのリージョンとendpointが書いてあるテーブルから設定するという, (AWSを使う人にとってはありがたい)APIなのだろうと思う.

事実, setEndpointとsetRegionを逆にすると, やはり日立のサーバに繋ぎにいく.

結論

コードをすべて追いかけてはいないものの, これらの挙動から私の推測は,

  • setRegionは, Region->EndpointのテーブルをsetEndpointしているようなものである. こちらは大変安全.

  • 署名は, Endpointのアドレスのみを元にしてアルゴリズムを決定している. この時, そのアドレスはAWSサーバのものでなくても良く, もし違う場合はたぶんv2にフォールバックしている. なぜv2かというと, v4は署名キーの生成にリージョンが必要となっているからである.

kSecret = Your AWS Secret Access Key
kDate = HMAC("AWS4" + kSecret, Date)
kRegion = HMAC(kDate, Region)
kService = HMAC(kRegion, Service)
kSigning = HMAC(kService, "aws4_request")

もし, クライアントがv4を使うように設定した場合はどういう挙動になるかは分からないが, いずれ分かるものと思うので, その時に追記する.

  • [重要] 明示的にsetRegionしているコードの接続先を独自S3実装にする場合, setRegionではなくsetEndpointでアドレス直打ちとする必要がある. (あるいは, セットされたリージョンがRegion Enumのものでない場合は〜みたいなコードを書く)

  • [重要] AWS SDKは, AWSサーバ以外にも接続するように設計されている. 理由: そうでないとしたら, setRegionのみがあれば十分なはずだから. setEndpointを公開していることが, 独自S3実装を歓迎している態度と判断する.