S3のHeadObjectを実行するポリシーにはS3:ListBucketアクションをつけたほうがいいよという話
HeadObject とは
Amazon S3 の HeadObject API を使うと、オブジェクト自体を返さずにオブジェクトからメタデータを読み出すことができます。これを使うことでオブジェクトの存在チェックをすることができます。
公式ドキュメントは以下です。
CLIでは以下のように実行する形になります。
aws s3api head-object --bucket my-bucket --key path/to/file.txt
オブジェクトの存在チェックをする別の手段としては、GET Object や List Objects などがあります。しかし、GET Object ではオブジェクト本体のデータも取得するためデータ転送料金が発生やレイテンシーの面が気になります。List Objects ではあるパス以下の複数のオブジェクトの存在確認をする場合には向いているかもしれませんが、単体のオブジェクトの存在確認をするには不要なデータを取得するため効率的ではない場合があると思います。
HeadObject を使う際のポリシーの注意点
HeadObject の permissions について公式ドキュメントに以下の説明があります。
== ドキュメント抜粋 ==
=================
つまり、オブジェクトの存在しないパスに対してHeadObjectのリクエストを実行すると、
- S3:ListBucket アクションの権限があると、404 Not Found error
- S3:ListBucket アクションの権限がないと、403 Forbidden error
になります。
API実行時の期待値はどちらでしょうか。オブジェクトの存在確認をしたいケースでは404が返ってきて、その他の実行できないエラーの場合は403が返ってきたほうがハンドリングしやすいケースが多いと個人的には思います。
この挙動の把握していないと404が返ってくる場合の処理を実装するなどの際に意図しない挙動となってしまうので注意しましょう(自戒)。
余談: なぜそのような挙動の違いになっているか
Claude Sonnet 4 に挙動の違いについて理由を聞いてみました。
s3:ListBucket権限がある場合:
- バケット内のオブジェクト一覧を見る権限がある
- そのため「オブジェクトが存在しない」ことを教えても問題ない
- → 404 Not Found
s3:ListBucket権限がない場合:
- バケット内のオブジェクト構造を知る権限がない
- オブジェクトの存在/非存在を教えることは情報漏洩になる
- → 403 Forbidden(アクセス拒否として扱う)
と、オブジェクト構造を知る権限があるかどうかで404であるか403であるかを決めているのではないかと言っています。個人的には納得感がありました。
まとめ
今回は、HeadObject の実行する際のポリシーについて過去に自分がハマった点について備忘として残す目的も併せて書いてみました。全ての仕様を把握することは困難ですが、公式ドキュメントにちゃんと記載があるのでハマった際や実装時には公式に当たることの大切さを再認識しました。どなたかの参考になれば幸いです。
Discussion