CloudFrontで「サービス終了の案内ページ」への、静的ウェブホスティング先変更に失敗した件

technologies

  • HOME
  • ブログ
  • technologies
  • CloudFrontで「サービス終了の案内ページ」への、静的ウェブホスティング先変更に失敗した件

おはようございます!ベンジャミンの木村です!

皆さんはサービス終了のアプリに「O年O月O日にサービスが終了します」の案内を出す方法はどうしてますでしょうか?

今回、CloudFrontのオリジン、ビヘイビアの変更だけで「サービス終了の案内ページ」が表示させようとして失敗しました…

その事象の共有しつつ、CloudFront Functionsを用いて「サービス終了の案内ページ」の全てのパスをリダイレクトする方法を共有させていただきます。

目次

本来したかったCloudFrontのリクエスト処理

上記のようにCloudFrontのオリジン、ビヘイビアの向け先を変更し、サービス終了の期間まで、どんなパスパターンで来ても、リクエスト先を「サービス終了の案内ページ」の入ったS3に向けることで、loginページにはアクセスできないように設定する予定でした…

今回起きたCloudFrontの事象

パスを付けずにドメイン(corporate.com)だけを叩けば、loginページを避けて、「サービス終了の案内ページ」につながるようになりましたが、/loginなどの後ろにパスをつけるとAccessDeniedの画面に繋がってしまいました…

corporate.com/loginのURLでブックマークしていたuserはAccessDeniedの画面に繋がってしまい、「変な画面が表示されたんだけど…」といった状態になってしまいました。

また、上記のようにコンソール上からビヘイビアの設定を確認しましたが、デフォルト(*)になっているので、『他のパスパターンでも、「サービス終了の案内ページ」に遷移するのでは…』という感じでした。

原因はエラーページの設定だった…

原因はCloudFrontのエラーページが設定されていることにありました。

どうやら、ビヘイビアデフォルト(*)に設定していても、CloudFrontのエラーページを設定していた場合、ビヘイビアなどで明示的にパス設定のされていないパス(今回で言うと「/」以外の「/login」のようなパス)でアクセスが来ると、自動的にエラーページにリダイレクトされるようです。

また今回さらに、S3内にエラーページで設定した403.htmlがなかったので、CloudFrontのエラーページからのリダイレクト先が存在せず、AccessDeniedのページが表示されたと言う結果になります。

(403.htmlがS3に存在していた場合は、/loginのパスでアクセスが来た場合403.htmlで設定した画面が表示されます。)

対策案

私の方では対応方法は以下3つほど考えましたが、結局のところ「3」を選択しました。

  1. エラーページの設定を全て消す
  2. オリジン、ビヘイビア、S3の設定を再度変更し、/loginのパスでも「サービス終了ページ」のS3にリクエストするようにする
  3. CloudFront Functionを設定し、全てのパスパターンでも「/」にリダイレクトするようにする

理由としては、1の場合、切り戻しが発生したときに、元のページに戻すときにエラーページも設定し直さないといけないので面倒な作業が少し発生する。

2の場合、作業工数が多い割に「/login」のみしか対応できない応急処置的対応なので、意味がないかなと…。

ですので、以下よりまずエラーの起きる手前までの作業手順を説明しつつ、「3」の手順でどんなパスでも「サービス終了の案内ページ」を表示させるようにしたいと思います。

1. S3に「サービス終了の案内ページ」を設置(静的Webサイトホスティングの設定方法)

1-1. 下記URLよりS3のコンソール画面へ移動する

https://s3.console.aws.amazon.com/s3/buckets?region=ap-northeast-1

1-2. 「バケットを作成」をクリックする

1-3. 作成後表示された画面で以下コードを入力し、「バケットを作成」をクリックする

  • AWSリージョン:東京リージョン
  • バケット名:任意
  • ブロックパブリックアクセス設定:オフ
  • バケットのバージョニング:有効

※他はデフォルト値でOK

1-3. 作成したS3をクリックする

1-4.「サービス終了の案内ページ」画面表示用のHTMLファイルをアップロードする

※テスト用におくindex.htmlだと<h1>サービス終了</h1>とかでも可

1-5. 「プロパティ」タブ→静的ウェブサイトホスティングの「編集」をクリックする

1-6. 以下の通りに値を入れ、「変更の保存」をクリックする

  • 静的ウェブサイトホスティング:有効
  • インデックスドキュメント:index.html

※その他はデフォルト値

1-7. 「アクセス許可」タブ→バケットポリシーの「編集」ボタンをクリックする

1-8. 以下の通りバケットポリシーを設定し、「変更の保存」ボタンをクリックする

{
    "Version": "2008-10-17",
    "Id": "PolicyForCloudFrontPrivateContent",
    "Statement": [
        {
            "Sid": "AllowCloudFrontServicePrincipal",
            "Effect": "Allow",
            "Principal": {
                "Service": "cloudfront.amazonaws.com"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::<S3バケット名>/*",
            "Condition": {
                "StringEquals": {
                    "AWS:SourceArn": "<CloudFrontのARN>"
                }
            }
        }
    ]
}

※上記の<S3バケット名><CloudFrontのARN>の部分は変更してください。

2. CloudFrontのオリジン、ビヘイビアの変更

手順1で作成したS3を既存のCloudFrontで向け先変更を行う手順になります。

2-1. 下記URLよりCloudFrontのコンソール画面へ移動する

https://us-east-1.console.aws.amazon.com/cloudfront/v4/home?region=us-east-1#/distributions

2-2.対象のCloudFrontの画面へ移動し、「オリジン」タブ→「オリジンを作成」のボタンをクリックする

2-3. 以下の通りに値を入れ、「変更を保存」をクリックする

  • Origin domain:手順1で作成した接続対象のS3を指定する
  • Origin path:空白
  • オリジンアクセス:Origin access control settings (recommended)
  • Origin access control:「Create new OAC」をクリックし、Origin domainと同じS3を指定してOACを作成する

※他はデフォルト値を入れる

2-4. 「ビヘイビア」のタブをクリックし、オリジンを変更したいビヘイビアを選択し、「編集」をクリックする

2-5. 「オリジンとオリジングループ」の項目を項番3-3で作成したオリジン名に変更し、「変更を保存」をクリックする

3. CloudFront Functionのリダイレクト設定手順

3-1. 下記URLよりCloudFrontのコンソール画面へ移動する

https://us-east-1.console.aws.amazon.com/cloudfront/v4/home?region=us-east-1#/distributions

3-2. 左ペインの「関数」→表示された画面の「関数を作成」をクリックする

3-3. 以下の通りに値を入れ、「関数の作成」をクリックする

  • 名前:任意
  • 説明:任意(空白でも可)
  • Runtime:cloudfront-js-2.0

3-4. 作成後表示された画面で以下コードを入力し、「変更を保存」をクリックする

function handler(event) {
  const uri = event.request.uri
  if (isNotRedirect(uri)) return event.request

  const newUri = getNewUri(uri)
  return {
    statusCode: 301,
    statusDescription: 'Moved Permanently',
    headers: { location: { value: newUri } },
  }
}

function isNotRedirect(uri) {
  return uri === '/' || uri === '/index.html'
}

function getNewUri(uri) {
  return '/'
}

3-5. 「発行」タブ→「関数を発行」をクリックする

3-6. 「関連付けを追加」をクリックする

3-7. 以下の通りに値を入れ、「関連付けを追加」をクリックする

  • ディストリビューション:対象のCloudFront
  • イベントタイプ:Viewer request
  • キャッシュビヘイビア:Default(*)(複数設定されている場合は、リダイレクトしたいビヘイビアを全て選択)

3-8. 関連付けたCloudFrontの「デプロイ」のステータスが「最終変更日 O月O日」の表示に変わっていることを確認する。

4. 動作確認

4-1.「キャッシュ削除」タブをクリックし、「キャッシュ削除を作成」をクリックする

4-2. 以下の通りに値を入れ、「キャッシュ削除を作成」をクリックする

  • オブジェクトパスを追加:/*

4-3. 下記のようにCloudFrontに紐づけているURLにパスを付けてブラウザに入力し、「/」にリダイレクトされれば作業完了

例)https://corporate.com/login(これ以外にもhttps://corporate.com/xxxxxでも試してみる)

まとめ

今回このエラーを受けて、CloudFrontの知見が深まりました…。

障害対応はやはり成長の機会になりますね。(起こしたくはないですが)

「サービス終了の案内ページ」を表示する作業はおそらくどこのIT会社にも存在すると思いますので、ご参考にしていただければと思います。

関連記事一覧