【小ネタ】カスタム認証を使うAPI GatewayをCloudFrontの後ろに置いたらAPIを叩けなくなった
はじめに
こんにちは、夏目です。
現在私が関わっているサーバーレスの案件で、今までAPI Gatewayがインターネットにむき出しになっていたのを、セキュリティ強化のためにWAFをつけたいという要望がありました。
AWS WAFはELBやCloudFrontにはつけることができるのですが、API Gatewayにつけることができません。 そのため、API Gatewayの前にCloudFrontを置くことになりました。
すると今まで動いていた、API Gatewayのカスタム認証が通らないためAPIを叩くことができなくなりました。
どういった設定にしていたのか
CloudFrontのBehaviorsで"Cache Based on Selected Request Headers"を"All"にしていました。
"Learn More"と書かれたリンクの先のドキュメントには以下のように書かれています。
ウェブディストリビューションの各キャッシュ動作を以下のいずれかを実行するように設定できます。
- 全てのヘッダーをオリジンに転送する 重要 すべてのヘッダーをオリジンに転送するように CloudFront を設定した場合、 CloudFront はこのキャッシュ動作に関連付けられたオブジェクトをキャッシュしません。 その代わりに、すべてのリクエストをオリジンに送信します。
- 指定したヘッダーのホワイトリストを転送する。CloudFront は、指定されたヘッダーすべての値に基づいてオブジェクトをキャッシュします。CloudFront は、デフォルトで転送するヘッダーも転送しますが、指定されたヘッダーの値にのみ基づいてオブジェクトをキャッシュします。
- デフォルトのヘッダーのみを転送する。この設定の場合、CloudFront は、リクエストヘッダーの値に基づいてオブジェクトをキャッシュすることはしません。
API Gatewayでカスタム認証を使うために"Authorization"ヘッダーを使用しています。そのため、「すべてのリクエストをオリジンに送信します」と書かれた"All"で問題ないように見えました。
もちろん、以後API Gatewayが動かなくなったので実際には問題があります。
なぜ"All"ではダメなのか
ヘッダーの値に基づいてキャッシュするようにCloudFrontを設定しない場合、CloudFrontからオリジンへの中継の際に一部のヘッダーは削除されたりすることがあります(HTTP リクエストヘッダーと CloudFront の動作)。
API Gatewayの認証で使用している"Authorization"ヘッダーも、キャッシュしない場合はCloudFrontはGETメソッドの場合削除してからオリジンへリクエストを行ってしまうのです。
気づいた方もいるとは思いますが、ここでもう一度ドキュメントを見てみます。
- 全てのヘッダーをオリジンに転送する 重要 すべてのヘッダーをオリジンに転送するように CloudFront を設定した場合、 CloudFront はこのキャッシュ動作に関連付けられたオブジェクトをキャッシュしません。 その代わりに、すべてのリクエストをオリジンに送信します。
"All"を指定した時、"CloudFront はこのキャッシュ動作に関連付けられたオブジェクトをキャッシュしません"。 そう、"CloudFrontはオブジェクトをキャッシュしないのです"。
オブジェクトをキャッシュしないから、"Authorization"ヘッダーが消されてしまってAPIを叩けなくなったのです。 すべてのヘッダーをオリジンに転送すると書いていますが、決してすべてではありません。
どう設定すべきだったのか
理由さえわかってしまえば、答えは単純です。 "Authorization"ヘッダーに基づいてオブジェクトをキャッシュするように設定すればいいのです。
これで、API Gatewayも正常に動くようになりました。めでたしめでたし。 というのが、今回の小ネタです。
まとめ
API Gatewayに限らず、CloudFrontでカスタムオリジンを使う際には気をつける必要がありそうです。 見落とさないようにしていきましょう。
参考資料
リクエストヘッダーに基づいてオブジェクトをキャッシュするように CloudFront を設定する 選択されたリクエストヘッダーに基づいたキャッシュ HTTP リクエストヘッダーと CloudFront の動作