2020-12-07

S3+CloudFrontの構成で静的なサイトを公開する場合の注意点

最近静的なサイトを公開するためにS3と、サイトをSSLにするため+高速化のためにCloudFrontを組み合わせて構築した際に、サブディレクトリのページを更新すると403が返されてしまう現象に遭遇し、一時間くらいハマったのでメモしておく
なお、このサイト(hakozaru.com)は単にFirebaseでホスティングされているので今まで遭遇することがなかった

構成と設定

すごくオーソドックスな構成(Gatsby+S3+CloudFront)の構成で静的なサイトを構築していた
サーバーレスは偉大である

  • S3
    • バケットのパブリックアクセスは全て遮断
    • CloudFront向けのバケットポリシーだけを設定し、CloudFront経由のアクセスだけを許可
    • よって「静的ウェブサイトホスティング」も無効
  • CloudFront
    • オリジンにはS3バケットそのものを指定↓して配信

と言う感じで特に違和感を感じることもなく、サイトも普通に表示されているように見えた
(ACMを使ってSSL化と、Routes53も使ってるけど関係ないので略)

問題の発生

そんなこんなで構築もある程度終わり、動作確認していたところ、サブディレクトリのページでリロードを行うと403が返されてしまうことが判明した

  • トップページなどにあるリンクから https://example.com/hogehoge へ移動するのは問題ない
  • しかし移動後に https://example.com/hogehoge をリロードすると403になる

と言う感じだった

問題の検証と原因の特定

イマイチ状況が理解できなかったので、思いつく範囲で色々調べてみた

  • Gatsby.jsのビルドは問題なさそうで、ビルドで生成されたファイルがアップロードされた後にS3のバケットを覗いてみるとサブディレクトリは存在していて、 index.html も存在している
  • https://example.com/hogehoge に直接アクセスしても403になるけど、 https://example.com/hogehoge/index.html はアクセスできて即 https://example.com/hogehoge へリダイレクトされる

最初Gatsbyに原因があるのか、AWS側に原因があるのかちょっとわからなかったけど、調べてみた感じCloudFrontがサブディレクトリの index.html を参照できていないっぽいことがわかったので、CloudFrontに絞って調査を進めたところこの記事へ行き着いた
サイトの構成的に「サブディレクトリのインデックスファイルが効かない」状態となっていたということらしい

問題の解消

S3+CloudFrontの構成で静的なサイトを構築する場合、2つの方法があるらしい

  1. CloudFront のオリジンにS3バケットそのものを指定する構成
  2. CloudFront のオリジンにS3バケットのStatic website hostingのエンドポイントを指定する構成

静的なサイトを公開すると言う点において違いはありませんが、若干違いがあり表にしてみると

CloudFront + S3 で静的サイトを運用する際の注意点より引用

と言う感じ
↑で説明した通り、僕が構築していたサイトの構成はここで言う構成1の状態なので、CloudFrontのサブディレクトリのインデックスファイルは使えなかった

と言うことで一旦構成2の状態にしてサイトを公開し、セキュリティ部分に関してはできることを随時対応している
(もしかしたらパスに index.html を強制するようにして、構成1に戻すかもしれないが、今のところ未定。やりながら考える)

なお、 S3バケットのStatic website hostingのエンドポイントを指定する とはどう言うことなのかですが
↑でスクショを貼ったCloudFrontのOrigin Domain Nameに、S3バケットの静的ウェブサイトホスティングを有効にした際に表示されるURL(http://バケット名.s3-website-リージョン.amazonaws.com)を入れればOKです

いやー知らなかった、とても勉強になりました

参考