TL;DR
CloudFrontのオリジンにAPI Gatewayを追加したい時には、
Origin Request Policyにて、AllViewer
の設定で全てのヘッダをバイパスするように設定するとエラーとなる。
原因はCloudFront向きのHost
ヘッダの情報をAPI Gatewayにそのままバイパスしてしまうため。
はじめに
よく知られていることですが、API Gatewayは内部的にCloudFrontの仕組みを利用しているため、
レスポンスデータのキャッシュやスケーラビリティの確保については、CloudFrontをユーザー側で用意しなくても、
CloudFrontのメリットを受けられるようになっています。
しかしながら、例えば
- WAFによるアクセス制限の仕組みを利用したい
- キャッシュ設定をより細かく設定したい
(Maximum TTL
,Minimum TTL
、Invalidation
等)
などのユースケースにて、意図的にAPI Gatewayの前段にCloudFrontを置きたくなることがあります。
今回自分もキャッシュ設定のメリットを受けるためにこの構成を採用しましたが、表題の通りヘッダ設定周りでハマったので残しておこうと思います。
今回実施した構成
今回実施した構成は以下のようなイメージです。
ユーザーはAPIにアクセスする際はCloudFrontを経由します。
CloudFrontにキャッシュデータがある場合はキャッシュを返し、キャッシュがない場合のみAPI Gateway経由で各Lambdaに配置されたAPI関数を実行します。
また、CloudFrontとAPI Gatewayにはそれぞれドメインを用意します。ドメインはRoute53でAレコード、ACMによってSSL証明書とCNAMEレコードを発行します。
API Gatewayにもカスタムドメインを用意するのは、自動で着くステージ名のパスが要求仕様的に不要で、カスタムドメインによって内包するためです。
最初に行った設定
早速CloudFrontのDistributionを作成します。
最初は、おおよそ以下のような設定で作成を行いました。(主要部分の抜粋)
Origin Settings
-
Origin Domain Name
: <API Gatewayのカスタムドメイン> -
Origin Pass
: *
Cache Policy
- Cache Key Content
-
Headers
:whitelist
-
Authorization
(↑BASIC認証の成功有無でキャッシュするか決定するため)
-
-
QueryString
:All
(←全てのパターンで識別するため) - 圧縮は行わない
-
Origin Request Policy
- Origin Request contents
- Headers : AllViewer
-
QueryString
:All
(↑元々のリクエスト同等のリクエスト内容となるように)
さて、上記のような設定でDistributionを作成し、早速アクセスをしてみました。すると、以下のようなHTMLページがレスポンスで帰ってきました。
うーん困った...
APIは全てjsonを返すものなので、HTMLが帰ってきていると言うことはCloudFrontとAPI Gateway部分でのエラーだろうと考え設定周りを調べました。
原因
調査を行ったところ、原因は設定内でも太字にしていた、Origin Request PolicyにてHeadersをAllViewer
として、リクエストの全てのヘッダをオリジンへバイパスしていることが原因でした。
今回のキーとなったのは、リクエストにて自動的に付与される、Host
ヘッダの内容です。
Host
ヘッダとは、リクエストが送信される先のサーバーのホスト名とポート番号を指定するためのヘッダ情報です。HTTP/1.1だと唯一の必須ヘッダになっています。
(参考:https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Host)
API Gatewayに直接アクセスしようとしていた時は(当たり前ですが)Host
ヘッダの宛先はAPI Gatewayのドメインになっています。
しかし今回、CloudFrontからAPI Gatewayにアクセスする際、AllViewer
の設定によって、ユーザーがCloudFrontへリクエストを投げる際に付与されていたHost
ヘッダもそのままバイパスしてAPI Gatewayにリクエストするようになっています。
ここからは確認できていませんが恐らく、
-
Host
ヘッダにCloudFrontのドメインを設定したままAPI Gatewayのドメインにアクセスしようとした - CloudFrontアクセス時の
Host
ヘッダに加え、API Gatewayアクセス時のHost
ヘッダが作成され、2つのHost
ヘッダがある不正なリクエストとなってしまった
かのいずれかでアクセスエラーとなっていたのでしょう。その結果、CloudFrontがエラーを検知して403のHTMLを返していた、ということです。
対応方法
原因がわかったので対策として、Headersの設定をwhitelist
にし、必要なヘッダのみをバイパスするように設定を変更しました。今回はAccept
とAccept-Language
を追加しています。
なお、Authorization
ヘッダについてはCache Policyにて識別対象に設定しているため、こちらで設定を行わなくともオリジンへのリクエスト時にはバイパスされています。
これによって、CloudFrontからオリジンとしてAPI Gatewayにアクセスする際に適切なHost
ヘッダが再設定されるようになり、正常にアクセスができるようになりました。
まとめ
原因の調査には時間がかかりましたが、おかげで普段あまり意識しきれていなかったHTTP/1.1の仕様部分まで理解を深められて良かったです。
低レベルなコンピューターサイエンスの知識はやはり重要です。