🔥

【S3・CloudFront】URL の末尾が/(スラッシュ)で終わるリクエストを/index.html にルーティングする

に公開

はじめに

S3とCloudFrontで静的サイトをホスティングする際、設定によっては、URL の末尾が/(スラッシュ)で終わるリンクをクリックするとき、正しくルーティングできないことがあります。
(例:hrefが/case/のリンクをクリック → 内部的には/case/index.htmlにリンクさせたいがエラーになる)

この解決法としては、2点あります。
①S3のREST APIエンドポイント + CloudFront Functionsを使用する方法
- OAC (Origin Access Control) を利用
- CloudFront Functionsを利用
②S3のウェブサイトエンドポイント + カスタムヘッダーを使用する方法
- カスタムヘッダーを使用してバケットポリシー+CloudFrontでアクセス元を制限

※S3のREST APIエンドポイントとウェブサイトエンドポイントについて
https://blog.serverworks.co.jp/2022/03/02/100000

①S3のREST APIエンドポイント + CloudFront Functionsを使用する方法

S3の実装

S3のブロックパブリックアクセスをオンにしておきます。

バケットポリシー

{
{
  "Version": "2008-10-17",
  "Id": "PolicyForCloudFrontPrivateContent",
  "Statement": [
    {
      "Sid": "AllowCloudFrontServicePrincipal",
      "Effect": "Allow",
      "Principal": {
        "Service": "cloudfront.amazonaws.com"
      },
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::バケットネーム/*",
      "Condition": {
        "StringEquals": {
          "AWS:SourceArn": "CloudFrontのディストリビューションARN"
        }
      }
    }
  ]
}

CloudFrontの実装

CloudFrontのオリジン設定をREST APIエンドポイントのURLに設定します。
**※URLにwebsiteが付かないように

次にCloudFrontでオリジンアクセスを作成し、オリジンにアタッチしてOACを設定します。
ここまでで、静的サイトのホスティング自体はできています。
ここからはCloudFront FunctionsでURLを整形する関数を作成していきます。

CloudFrontの左ペインの関数で作成します。

CloudFront Functions
function handler(event) {
  var request = event.request;
  var uri = request.uri;

  // Check whether the URI is missing a file name.
  if (uri.endsWith("/")) {
    request.uri += "index.html";
  }
  // Check whether the URI is missing a file extension.
  else if (!uri.includes(".")) {
    request.uri += "/index.html";
  }

  return request;
}

作成したら該当のディストリビューションのビヘイビア関数の関連付けで作成した関数をアタッチします。 今回はエンドユーザーからのリクエストをCloudFrontが受け取った直後に発火させたいので「ビューワーリクエスト」で選択します。

こちらで①の設定は完了です。

ビューワーリクエスト等についての参考
https://qiita.com/itkz1016/items/4aafbb0309226bc3bdf0

②S3のウェブサイトエンドポイント + カスタムヘッダーを使用する方法

S3の実装

S3のブロックパブリックアクセスをオンにしておきます。
(バケットポリシーでS3のエンドポイントに直接アクセスできないようにします)

バケットポリシー

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowCloudFrontAccess",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::バケットネーム/*",
            "Condition": {
                "StringEquals": {
                    "aws:Referer": "CloudFrontのRefererヘッダーの値"
                }
            }
        }
    ]
}

S3の静的ウェブサイトホスティングをオンにします。
また、インデックスドキュメントの値にindex.htmlを設定しておきます。

CloudFrontの実装

CloudFrontのオリジン設定をウェブサイトエンドポイントのURLに設定します。

カスタムヘッダーを設定します。値は任意でOKです。(バケットポリシーにも記載)

こちらで②は完了です。

おわりに

今回は、S3とCloudFrontにおける末尾スラッシュ問題を解決するための2つの実践的な方法、①REST APIエンドポイント + CloudFront Functions と ②ウェブサイトエンドポイント + カスタムヘッダー をご紹介しました。

方法①はOACを利用するためセキュリティ面で優れており、AWSが推奨するモダンな構成です。CloudFront Functionsによる柔軟な制御も魅力です。
方法②はS3の標準機能で解決でき、設定がシンプルというメリットがあります。

基本的にはセキュリティと拡張性の高い①の方法をおすすめしますが、要件や手軽さに応じて②を選択するのも良いと思います。

Discussion