🌟

AWS CloudFrontでメンテナンスページに切り替える方法

2024/07/28に公開

はじめに

とある案件でAWS上でCloudFront + S3 + ALBの構成でWEBサイトホスティングを実装している時に、「特定の時間帯はメンテナンス用のページを表示したい」という業務要件が出てきました。
単純にALBのリスナールールを切り替えることで、CloudFrontにエラーコードを返しS3内のメンテナンスページにリダイレクトする方法かなと考えたのですが、そもそも他に方法がないのか気になったので検証してみました。

今回の構成

今回題材にする構成は以下のような構成となっています。(なお案件での構成とは異なり、簡略化しています。)

以下の簡易的な要件のもと、メンテナンスページを表示する構成を考えていきたいと思います。

  • CloudFront + S3で静的サイトホスティング(SPA)
  • APIはALBを経由してEC2上のアプリケーションでホストする
  • ALBはHttps化する
  • CloudFrontをHttps化するため証明書はus-east-1で取得する
  • CloudFrontにWAFをアタッチしてフィルタリングを行う
  • メンテナンス時はS3内のメンテナンス用の静的ファイルを表示する
  • メンテナンス時は index.html への遷移はなく、直接メンテナンス用HTMLを表示する
  • メンテナンスページは時限で表示・非表示を行う
  • アクセスエラーの時はエラーページに遷移するようにする
  • 時限は厳密ではなく、5分程度のラグは許容できる

構成案としては以下のパターンがあるのではないかと考えています。

  1. ALBのリスナールールを変更して特定の時間にカスタムレスポンスを返すようにする
  2. ALBのリスナールールを変更して特定の時間にエラーレスポンスコードを返し、CloudFront側でエラーページの設定を行う
  3. WAFのルールを変更して任意の通信をブロックし、CloudFront側でエラーページの設定を行う
  4. CloudFrontのデフォルトページを切り替える

今回、基本的な環境はのんピさん(@non____97)の記事を参考にさせていただきました。いつもお世話になっていますm(_ _)m

実際の挙動

ALBのリスナールールで特定の時間にカスタムレスポンスを返すようにする

まずはCDKで構築した環境にALBのみ追加します。(本来はEC2などで正しくレスポンスを返すのが良いですが、今回は簡略化しています。)
ALBを作成後はCloudFrontのビヘイビアとオリジンにALBを指定しておきます。
次にALBのリスナーページで正常レスポンスのルールとメンテナンス用のルールを作成します。

まずは正常なレスポンスの場合を確認します。想定通り200のレスポンスを返しています。

次にルールの優先順位を変更してみます。

想定通りメンテナンス用の固定レスポンスが表示されました。
ここにメンテナンス用のHTMLをベタ書きしても良いですが、リッチなものであればリダイレクトしても良いかと思います。

ここまででALBのみでメンテナンスレスポンスを返す動作を確認できました。

ALBのリスナールールを変更して特定の時間にエラーレスポンスコードを返し、CloudFront側でエラーページの設定を行う

先ほどのノーマルHTMLではなく、きちんとしたメンテナンス用のページを表示したい場合を検証します。
まずはリスナールールを元に戻しておきます。
CloudFront側のエラーページの設定で503の設定を追加します。503のレスポンスの場合はS3内に配置したmaintenance.htmlを表示するようにします。

この状態で再度検証してみます。まずは200エラーが表示されている状態です。

次にALBのリスナールールを変更して検証します。

想定通りメンテナンス用のHTMLを表示してくれています。

あとは時刻をトリガーにしてルールを変更できれば良さそうです。これはset-rule-prioritiesというAPIで実行できるので、これをLambdaなどで実装してEventBridgeでトリガーするというのが基本的な流れになると思います。
こちらが参考になると思います。ありがとうございますm(_ _)m

https://zenn.dev/mn87/articles/041d694d08d002

WAFのルールで任意の通信をブロックし、CloudFront側でエラーページの設定を行う

これまでは全ての通信を一律リスナールールで制限してきました。
もちろんリスナールールにIPベースのルールを追加することも可能ですが、CloudFrontを経由しているのでALBから見ると通信元がCloudFrontとなり一筋縄ではいきません。例えば、一般ユーザーにはメンテナンスページを表示しながら、管理者は固定IPベースに動作確認をしたいケースなどがあるかと思います。この場合リスナールールだけでは若干取り扱いが面倒になると思い、WAFを使う方法を検証してみます。

まずはWAFの設定です。これはCloudFrontのセキュリティタブに統合されたので、かなりシンプルな動線で設定できるようになっています。今回はIPベースで以下のように制御できるように設定します。

From 挙動
PC(管理者) 許可
スマホ(一般ユーザー) 拒否

事前動作確認

どちらもIndexページが表示できています。

PC
PC側

スマホ
スマホ側

WAF設定

CloudFrontにWAFを設定する場合は、リージョナルではなくグローバルを選択して設定する必要があるので注意が必要です。
自身のPCアドレスのIPSetを作成し、WAF ACLのデフォルト動作をBlock、先ほど作成したIPSetを許可するルールを設定します。

事後動作確認

PC側ではIndexページが表示でき、スマホ側ではエラーページが表示されています。

PC
PC側

スマホ
スマホ側

これであれば、CloudFrontのオリジンに来る前にフィルタリングされ、S3内のエラーページが表示できているので、エラーページへの遷移も若干スムーズに感じます。(CloudFrontのエラーページ設定で、403をメンテナンスページに設定するとALBと同様のページ表示も可能です。)
また、必要なタイミングでIPSetをアタッチすることで、任意のタイミングでのメンテナンス切り替えに利用できるかと思います。

こちらが参考になるかと思います。ありがとうございますm(_ _)m
https://zenn.dev/tetoteto/articles/419a728554b6c3#createwebacl

さらに、WAFのカスタムレスポンスを設定することで、CloudFrontで利用できる任意のレスポンスコードでのみメンテナンスページへの遷移を設定することも可能です。

CloudFrontのデフォルトページを切り替える

最後にCloudFrontのデフォルトページ設定を変えるというものです。
これは一番シンプルに初期ページを置き換えてしまうことになるので、管理者・一般ユーザーといったアクセスの切り分けは難しいですが、メンテナンスページを表示するという要件だけであれば十分かと思います。
ただし、デフォルトページの切り替えにはCloudFrontの変更時間が発生するため、厳密な時間で遮断するというのはできません。

最後に

一通り検証をしてみましたが、ALBでのリスナールールの切り替えかWAFでのACLルールの変更が有力かなと思いました。
業務要件や監視などの運用要件なども踏まえて、どのレイヤでフィルタリングするか次第かなと思いますので、この記事を参考に検討いただけると幸いです。

なお、他にも対応の手段は数多あるかと思いますので、ぜひコメントや実装など共有いただけると嬉しいです!

GitHubで編集を提案

Discussion