AWS WAFのカスタムレスポンス機能のみでCloudFrontのメンテナンスページを実現する

CloudFrontのカスタムエラーレスポンス機能を使ってメンテナンスページを表現する方法が有名ですが、WAFのカスタムレスポンス機能のみでも実現可能です。


やりたいこと

  • WAFのカスタムレスポンス機能を使用して、メンテナンスページを実現する


前提

  • CloudFrontでホスティングしている静的ページ・Webアプリに対しての実現方法です


AWS WAF v2のカスタムレスポンス機能とは

  • WAFでリクエストをブロックするように設定した際に、httpステータスコードやレスポンスヘッダー・ボディを自由に定義して返せる機能

docs.aws.amazon.com


従来の方法

WAFのカスタムレスポンス機能がリリースされる前は、CloudFrontのカスタムエラーレスポンスとWAFによるメンテナンスページの実現方法が有名でした。

同じ様な機能ですが、今までは「CloudFrontのカスタムエラーレスポンス」機能であり、今回のは「WAFのカスタム(エラー)レスポンス」機能になります。


※こちらの記事で、CloudFrontのカスタムエラーレスポンスとWAFによるメンテナンスページの実現方法に関して書きました。

go-to-k.hatenablog.com


今回の方法

今回は、WAFの新しい機能である「カスタムレスポンス」機能を使用してCloudFrontのメンテナンスページを実現してみます。

具体的には、WAF側に直接メンテナンスページで表示するHTML内容を定義することができます。


使用サービス

  • CloudFront
    • 構築方法は省略します
  • AWS WAF v2


実装

  • waf.yml
  WAFWebACL:
    Type: AWS::WAFv2::WebACL
    Properties:
      Name: "Maintenance-WebACL"
      Scope: "CLOUDFRONT"
      VisibilityConfig:
        CloudWatchMetricsEnabled: true
        MetricName: "WAFWebACLMentenance"
        SampledRequestsEnabled: true
      CustomResponseBodies: 
        CustomResponseBodyKeyForCloudfront:
          ContentType: TEXT_HTML
          Content: |
            <!DOCTYPE html>
            <html>
            <head>
              <title>メンテナンス中</title>
              <meta http-equiv="content-type" charset="utf-8">
            </head>
            <body>
              <h1>メンテナンス中</h1>
              <p>メンテナンスが終わるまでお待ちください</p>
            </body>
            </html>
      DefaultAction:
        Block: 
          CustomResponse:
            ResponseCode: 503
            CustomResponseBodyKey: CustomResponseBodyKeyForCloudfront
            ResponseHeaders:
              - Name: custom-error-type
                Value: "MaintenanceMode"


解説

  • Scope
    • アタッチするリソース(CloudFront)はグローバルサービスのため、ScopeはCLOUDFRONTにする
Scope: "CLOUDFRONT"


  • VisibilityConfig
    • 監視のための設定など
    • 今回は触れません
      VisibilityConfig:
        CloudWatchMetricsEnabled: true
        MetricName: "WAFWebACLMentenance"
        SampledRequestsEnabled: true


  • CustomResponseBodies
    • カスタムレスポンスのボディの詳細をここで定義できる
    • CustomResponseBodyKeyForCloudfrontの名前は自由に決められ、このキー名をCustomResponse:で呼び出す
    • ContentType: TEXT_HTMLにして、メンテナンスページのHTMLを記述するようにする
    • ボディ内容(Content)にHTMLを書く
      • |を先頭につけると、yaml内で改行したり、インデントをyamlブロックに合わせて見やすいまま書けます
      CustomResponseBodies: 
        CustomResponseBodyKeyForCloudfront:
          ContentType: TEXT_HTML
          Content: |
            <!DOCTYPE html>
            <html>
            <head>
              <title>メンテナンス中</title>
              <meta http-equiv="content-type" charset="utf-8">
            </head>
            <body>
              <h1>メンテナンス中</h1>
              <p>メンテナンスが終わるまでお待ちください</p>
            </body>
            </html>


  • CustomResponse
    • カスタムレスポンス本体の設定を書く
      • ResponseCodeを503にしています
      • CustomResponseBodyKeyには先程のCustomResponseBodyKeyForCloudfront
      • ResponseHeadersで カスタムヘッダーを追加することができる
        • Name: custom-error-type
        • Value: MaintenanceMode
      DefaultAction:
        Block: 
          CustomResponse:
            ResponseCode: 503
            CustomResponseBodyKey: CustomResponseBodyKeyForCloudfront
            ResponseHeaders:
              - Name: custom-error-type
                Value: "MaintenanceMode"


反映

このWAFをCloudFormationでデプロイし、CloudFrontにアタッチしてからブラウザでCloudFrontのURLにアクセスすると、メンテナンスページが表示されます。

f:id:go-to-k:20210905202731p:plain


WAFのカスタムレスポンス設定はこのように反映されています。

f:id:go-to-k:20210905202906p:plain

f:id:go-to-k:20210905202152p:plain


最後に

メンテナンスページを実現するには、従来のCloudFrontのカスタムエラーレスポンス機能を使うことが多いかと思われますが、WAFのカスタムレスポンス機能だけでも柔軟に行うことができます。

特にステータスコードやカスタムヘッダーなどと一緒に設定・定義することができるため、メンテナンスに関する実装を集約する意味でもWAFで全てやってしまうのもありかもしれませんね。