なぜWAFとCloudFrontのカスタムエラーレスポンス機能でメンテナンスページを実現できるの?

AWS WAFとCloudFrontのカスタムエラーレスポンス機能でWebのメンテナンスページを実現する方法は有名ですが、その仕組みを考えてみたところ「あれ・・・?なぜだ・・・?」となりました。


CloudFrontのカスタムエラーレスポンスとは

オリジンで何らかのエラーが発生した際に、CloudFrontからエラーレスポンスをカスタマイズして返すことができる機能のことです。

具体的には、特定のhttpステータスコードの時に、指定したエラーページファイルへ遷移させ、かつhttpステータスコードを上書きすることができます。

docs.aws.amazon.com


WAFとCloudFrontによるメンテナンスページの表示

実際にWAFとCloudFrontのカスタムエラーレスポンスでメンテナンスページを表示する方法は以下の記事にまとめております。

go-to-k.hatenablog.com

具体的には、CloudFrontに直接WAFをアタッチして通信をブロックし、CloudFrontのカスタムエラーレスポンス機能を設定することで、指定したエラーページ(=メンテナンスページ)に遷移させることができます。


また、WAFのカスタムレスポンス機能のみでメンテナンスページを実現する方法は以下で書いています。

go-to-k.hatenablog.com


なぜ実現できるの?

カスタムエラーレスポンスの仕組み

まず、そもそも「CloudFrontのカスタムエラーレスポンス」ってどんな仕組みなんだっけ?というところから。


以下、実際のCloudFrontコンソール画面(ついに日本語対応されましたね!)の一番下の「エラーレスポンスをカスタマイズ」を見ると、、、


"オリジンから受け取ったエラーの代わりに、カスタムエラーレスポンスを送信します。"

「オリジンから」受けたエラーの代わりに、カスタムエラーレスポンスを返す仕組み・機能とのことでした。


CloudFrontにアタッチするAWS WAF

一方、メンテナンスページ実現のために、CloudFrontにアタッチするAWS WAFとは何なのか。

※ここではWAFはCloudFrontに直接アタッチする前提です。CloudFrontの後段に置いたELBやAPI GatewayなどにWAFをアタッチするケースは対象外としています。


WAFとは、Web Application Firewallという名の通り、アプリケーション/L7用のファイヤーウォールです。

ファイヤーウォールと聞くと、攻撃などから守ってくれるんだろうなというイメージがあると思います。実際にCloudFrontにWAFをアタッチすることで、様々な攻撃を検知したり防御することが可能になります。

何となく攻撃から守ってくれるという点から、CloudFrontの「前段」にあるんだろうかというイメージもありました。


ある疑問:前段と後段

そこでふと、疑問が生まれました。


CloudFrontの「前段」(CloudFrontに届く前)でWAFがブロックしてくれる・・・?

そこにカスタムエラーレスポンス機能を使えば、WAFでのブロック時に指定のエラーページ(=メンテナンスページ)に遷移・飛ばせるんだったよな・・・?



ここで、先程説明した、CloudFrontのカスタムエラーレスポンスの仕組みを思い返してみました。

"オリジンから受け取ったエラーの代わりに、カスタムエラーレスポンスを送信します。"


「オリジンから」受けたエラーの代わりに、カスタムエラーレスポンスを返す仕組み。。。


「オリジン」というのは、CloudFrontの「後段」にあるものです。

その「後段」にある「オリジンからの」エラーをカスタマイズする機能ということになります。


つまり、WAFはCloudFrontの前段にあるとイメージしていたが、CloudFrontの前段にあるWAFがブロックしたときに、後段のオリジンと連携するカスタムエラーレスポンスによってエラーページ・メンテナンスページに遷移できるのはおかしくないか・・・?

何か勘違いをしているのでは・・・?


「なぜ実現できるの?」の答え

AWSの公式ドキュメントのWAF項目にて載っていました。

※日本語版は非常に読みづらかったので英語ページを・・・

docs.aws.amazon.com


When AWS WAF blocks a web request based on the conditions that you specify, it returns HTTP status code 403 (Forbidden) to CloudFront. Next, CloudFront returns that status code to the viewer.

AWS WAFは、指定した条件に基づいてWebリクエストをブロックすると、HTTPステータスコード403(禁止)をCloudFrontに返します。次に、CloudFrontはそのステータスコードをビューアに返します。」(※Google 翻訳)


WAFがブロックした際、WAFからCloudFrontにエラーを返しているのだそうです。


そして、カスタムエラーレスポンスと連携できる旨もしっかり書いてありました。

If you'd rather display a custom error message, possibly using the same formatting as the rest of your website, you can configure CloudFront to return to the viewer an object (for example, an HTML file) that contains your custom error message.

「Webサイトの他の部分と同じフォーマットを使用して、カスタムエラーメッセージを表示したい場合は、カスタムエラーメッセージを含むオブジェクト(HTMLファイルなど)をビューアに返すようにCloudFrontを設定できます。」(※Google 翻訳)


つまり、WAFは後段ではないだろうけど、前段でもない・・・?

それか前段だけど後段のCloudFrontをプロキシして返す・・・?そもそもカスタムエラーレスポンスはオリジンからの受け取りだけでなかったって点もあるな・・・

それとも前段とか後段とかなくてセットみたいな感じ・・・?(nginxでWAFまで行う的な)



まあ、、、というように、一応以下のことがわかりました。

  • WAFでブロックするときは、CloudFrontにエラーを返す
  • CloudFrontはエラーを受け取って、カスタムエラーレスポンスでカスタムエラーメッセージを表示できる
  • つまり、WAFとCloudFrontのカスタムエラーレスポンス機能で、指定したページ(つまりメンテナンスページ)に遷移できる


前段なのか後段なのかどちらでもないのかはわかりませんでしたが、仕組みがわかってよかったです。


注意点

公式ドキュメントに、一つ注意点が書いてありました。


CloudFront can't distinguish between an HTTP status code 403 that is returned by your origin and one that is returned by AWS WAF when a request is blocked. This means that you can't return different custom error pages based on the different causes of an HTTP status code 403.

「CloudFrontは、オリジンから返されるHTTPステータスコード403と、リクエストがブロックされたときにAWSWAFから返されるHTTPステータスコードを区別できません。これは、HTTPステータスコード403のさまざまな原因に基づいてさまざまなカスタムエラーページを返すことができないことを意味します。」(※Google 翻訳)


WAFでブロックしてCloudFrontに返るエラーと、WAFと関係なくオリジンから返るエラーで、区別することができないそうです。


つまり、WAFでブロックするときと、本当にオリジンから403エラーが返ってきているときで、表示するページを変えることは難しいそうです。

たとえば、アクセス権限がないページに飛んだ時もメンテナンスページが表示されるということですね。


新たな疑問

カスタムエラーレスポンスではなくただWAFでブロックする場合も、結局CloudFrontを通ってエラーを返しているので、CloudFrontのhttpリクエスト料金などがかかる?DoS攻撃を喰らったときも料金がかかるのか?というような疑問も浮かびましたがどうなんでしょうかね。

そうだとしたらWAFのレートベースルールで防御しているときもそういうものなんですかね。AWS Shield Advanced(一部はStandard)でカバーすべきところなんでしょうか。


疑問は残りますがあまり調べきれなかったため、いつかの課題にしておきます。


最後に

メンテナンスページの実現は自分もとりあえずCloudFrontとWAFでできるでしょというノリで今まで行ってましたが、ふと社内のメンバーと話していてこの議題が浮かびました。

一度ちゃんと考えてみる機会ができてよかったです。



Twitter始めました!

良かったらぜひ。お知り合い増やせたら嬉しいです。

Twitter ID → @365_step_tech