これは ユニークビジョン株式会社 Advent Calendar 2021 の記事です。
はじめに
以前書いた以下の記事に追記と称して自分の twitter だけ張り付けた事象をちゃんと記事にしてみた。
s3からフォルダのようなkeyが帰ってくる。
cloudfront のオリジンにしているときに s3に空ファイルがあると妙な現象が起こる。
空ファイルなんて作るやつが馬鹿なのよ。という方も前記事を見ていただけるとなぜ空ファイルが生えるかわかります。
現象
悪さといっても具体的に何なのか。
まず最初に現象を見るのが早いでしょう。
s3 をアクセス先とした cloudfront を作成してブラウザでアクセスします。
遷移先にブラウザが解釈可能なオブジェクトが存在すればブラウザはその内容を表示してくれるはずです。
ちょっとこの後のタネが割れるのですが以下のようなパスにアクセスします。
(URLはイメージです。distribution ID は伏せているのでアクセスしても何もありません。)
https://XXXXXXXXXXX.cloudfront.net/test2/
するとこうなります。
なんかダウンロードしました。
空ファイルのようです。
実験
s3 の用意
以下の通り s3 を用意します
test-bucket
├── test1
│ └── index.html
└── test2
└── index.html
ディレクトリを2つ作成し、それぞれに index.html を配置しました。
AWS s3 コンソール上での見かけは同じですが、作成手順が異なります。
test1 の方は index.html の入った test1 というフォルダをアップロードしました。
一方 test2 はコンソールから test2 というフォルダを作成し、index.html だけをその中にアップロードしました。
cloudfront の作成
先の test-bucket をオリジンに設定した cloudfront を作成します。
オリジンアクセスアイデンティティとかなんとか s3 オブジェクトにアクセスできるようにする設定は適宜行いましょう。
それだけ。
index.html にアクセス
それぞれの index.html にアクセスしてみます。
https://XXXXXXXXXXX.cloudfront.net/test1/index.html
https://XXXXXXXXXXX.cloudfront.net/test2/index.html
それぞれアクセスできました。
index.html を削る
それぞれ以下の URL にアクセスしてみます。
https://XXXXXXXXXXX.cloudfront.net/test1/
https://XXXXXXXXXXX.cloudfront.net/test2/
結果は以下の通り、挙動が異なりました。
何が起こっているのか
s3 について簡単におさらい
詳細は概要の前記事で
空ファイル
フォルダの作成を使うと空のオブジェクトが生成されます
つまり先ほど挙げたこのAWSコンソールでの見かけのディレクトリ構造は誤りであり、
test-bucket
├── test1
│ └── index.html
└── test2
└── index.html
以下が本来の姿と考えられます。
test-bucket
├── test1
│ └── index.html
└── test2
├── (空ファイル)
└── index.html
フォルダはない
s3 は単純な Key-Value ストアであり、本来フォルダというものはありません。
つまり上記のディレクトリ構造すら正確には誤りであり、s3 の真に正しい姿は以下の通りになります。
<test-bucket>
test1/index.html
test2/
test2/index.html
実際、list_objects などで確認するとそのような返答が来ます。
cloudfront が実際にアクセスしているオブジェクト
つまり、https://XXXXXXXXXXX.cloudfront.net/test1/index.html
にアクセスしたときには、
https://XXXXXXXXXXX.cloudfront.net/test1/
にある index.html
ではなく、
https://XXXXXXXXXXX.cloudfront.net/
= <test-bucket>
にある test1/index.html
を呼び出していると考えるべきでしょう。
よって、https://XXXXXXXXXXX.cloudfront.net/test2/
にアクセスしたときのみ存在する <test-bucket>
の test2/
という空ファイルをブラウザは解釈できずダウンロードしてしまうということになっているのでしょう。
ちなみに、そのような理由で空ファイルが降ってくるので
今回の場合末尾にスラッシュのない以下のような URL
https://XXXXXXXXXXX.cloudfront.net/test1
https://XXXXXXXXXXX.cloudfront.net/test2
はシンプルに access denied になります。
どんな時に問題になるのか
単純に s3 の訳の分からんエラー画面が出るのも驚きですが、突如謎の空ファイルが落とされたら当然ユーザーはもっとびっくりするでしょう。
さらにあなたが cloudfront のエラーページの設定で s3 からくる 403 エラーに適切に対処している場合は大きな問題になります。
空ファイルとはいえファイルはファイル。
オブジェクトが存在するので s3 は 200 で返答してきますのでエラーページの設定に引っかかりません。
せっかくエラーに対処していたのにエラーも起こさずユーザーに謎のファイルを送り付ける姿はかなり不快感を煽るでしょう。
コンテンツとして公開する s3 にはコンソールからフォルダを作らないことをお勧めします。