5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

CloudFront+API Gateway構成ではHostヘッダに気をつけよう

Posted at

TL;DR

CloudFrontのオリジンにAPI Gatewayを追加したい時には、
Origin Request Policyにて、AllViewerの設定で全てのヘッダをバイパスするように設定するとエラーとなる。
原因はCloudFront向きのHostヘッダの情報をAPI Gatewayにそのままバイパスしてしまうため。

はじめに

よく知られていることですが、API Gatewayは内部的にCloudFrontの仕組みを利用しているため、
レスポンスデータのキャッシュやスケーラビリティの確保については、CloudFrontをユーザー側で用意しなくても、
CloudFrontのメリットを受けられるようになっています。
しかしながら、例えば

  • WAFによるアクセス制限の仕組みを利用したい
  • キャッシュ設定をより細かく設定したい
    (Maximum TTL, Minimum TTLInvalidation等)

などのユースケースにて、意図的にAPI Gatewayの前段にCloudFrontを置きたくなることがあります。

今回自分もキャッシュ設定のメリットを受けるためにこの構成を採用しましたが、表題の通りヘッダ設定周りでハマったので残しておこうと思います。

今回実施した構成

今回実施した構成は以下のようなイメージです。

構成.png

ユーザーは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ページがレスポンスで帰ってきました。

エラー画面.png

うーん困った...
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のドメインになっています。

apigw直接.png

しかし今回、CloudFrontからAPI Gatewayにアクセスする際、AllViewerの設定によって、ユーザーがCloudFrontへリクエストを投げる際に付与されていたHostヘッダもそのままバイパスしてAPI Gatewayにリクエストするようになっています。
ここからは確認できていませんが恐らく、

  • HostヘッダにCloudFrontのドメインを設定したままAPI Gatewayのドメインにアクセスしようとした
  • CloudFrontアクセス時のHostヘッダに加え、API Gatewayアクセス時のHostヘッダが作成され、2つのHostヘッダがある不正なリクエストとなってしまった

かのいずれかでアクセスエラーとなっていたのでしょう。その結果、CloudFrontがエラーを検知して403のHTMLを返していた、ということです。

CF経由不明Host.png

対応方法

原因がわかったので対策として、Headersの設定をwhitelistにし、必要なヘッダのみをバイパスするように設定を変更しました。今回はAcceptAccept-Languageを追加しています。
なお、AuthorizationヘッダについてはCache Policyにて識別対象に設定しているため、こちらで設定を行わなくともオリジンへのリクエスト時にはバイパスされています。

対策.png

これによって、CloudFrontからオリジンとしてAPI Gatewayにアクセスする際に適切なHostヘッダが再設定されるようになり、正常にアクセスができるようになりました。

まとめ

原因の調査には時間がかかりましたが、おかげで普段あまり意識しきれていなかったHTTP/1.1の仕様部分まで理解を深められて良かったです。
低レベルなコンピューターサイエンスの知識はやはり重要です。

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?