CloudFrontで「サービス終了の案内ページ」への、静的ウェブホスティング先変更に失敗した件
おはようございます!ベンジャミンの木村です!
皆さんはサービス終了のアプリに「O年O月O日にサービスが終了します」の案内を出す方法はどうしてますでしょうか?
今回、CloudFrontのオリジン、ビヘイビアの変更だけで「サービス終了の案内ページ」が表示させようとして失敗しました…
その事象の共有しつつ、CloudFront Functionsを用いて「サービス終了の案内ページ」の全てのパスをリダイレクトする方法を共有させていただきます。
目次
- 本来したかったCloudFrontのリクエスト処理
- 今回起きたCloudFrontの事象
- 原因はエラーページの設定だった…
- 対策案
- 1. S3に「サービス終了の案内ページ」を設置(静的Webサイトホスティングの設定方法)
- 2. CloudFrontのオリジン、ビヘイビアの変更
- 3. CloudFront Functionのリダイレクト設定手順
- 4. 動作確認
本来したかった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」を選択しました。
- エラーページの設定を全て消す
- オリジン、ビヘイビア、S3の設定を再度変更し、/loginのパスでも「サービス終了ページ」のS3にリクエストするようにする
- 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会社にも存在すると思いますので、ご参考にしていただければと思います。