CloudFront + ALB 構成でX-Forwarded-Forを利用して地域制御を設定してみた

CloudFront + Application Load Balancer(ALB) という構成において、ALBから単純にリクエスト元を参照するとCloudFrontのエッジロケーションになります。CloudFrontに対するリクエスト元を参照したい場合は、X-Forwarded-ForというHTTPヘッダーを利用する必要があります。では、ALBに関連づけたAWS WAFを使ってリクエストを地域制御したい場合、X-Forwarded-Forヘッダーを参照すればリクエスト元の国や地域に応じた制御が設定できるでしょうか?
2021.01.29

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

コンサル部のtobachi(@toda_kk)です。

CloudFrontやAWS WAFでは地域制御の設定が可能です。特定の国や地域からのアクセスのみ許可/禁止する挙動を設定できます。

例えば、ECサイトを運用する際に管理用アプリケーションへのアクセスを日本国内のみに制限したいといった要件があるときに、地域制御の設定が役立ちます。

単純にCloudFrontに対するリクエストを全て制御したい場合は、下記の手順でCloudFrontの設定から地域制御を有効化するだけで解決できます。

また、Application Load Balancer(ALB)に対するリクエストを制御したい場合、AWS WAFを利用すれば地域制御を含めさまざまな制御の設定が可能になります。

CloudFront + ALB 構成におけるリクエスト元の参照

ここで、 CloudFront + Application Load Balancer という構成におけるリクエスト元の参照について考えてみます。

フロントとなるCloudFrontから見ると、リクエスト元とはエンドのクライアントになります。一方、ALBにおいてリクエスト元を単純に参照してしまうと、CloudFrontのエッジロケーションを示すことになります。

このような場合に、ALBに関連づけたAWS WAFの設定で地域制御すると、単にリクエスト元を設定するだけでは意図した挙動にならない可能性があります。

X-Forwarded-Forヘッダーの利用

そこで、ALBからでもエンドのクライアントをリクエスト元として参照するために、X-Forwarded-For(XFF)ヘッダーを利用します。AWS WAFでは2020年7月にサポートされました。

ALBに関連づけたAWS WAFにおいて、XFFヘッダーを参照することでエッジロケーションにかかわらずリクエスト元の地域制御を設定できます。

リクエストをパスベースで地域制御してみる

地域制御が可能かどうか、実際に検証してみました。

検証構成

今回は、ECサイトと、サイトを管理するためのインスタンスを分けて構築しているような下図の構成を考えています。

  • CloudFrontのオリジンとしてALBを指定する。
  • ALBにはAWS WAFを関連づけて "/admin" 以下のパスにリクエストがきた場合は地域制御する。
  • それ以外のパスにリクエストがきた場合は制御しない。
  • ECサイト用/管理アプリケーション用インスタンスにはそれぞれnginxをインストールして起動しておく。

AWS WAFの設定

ALBに関連づけるAWS WAFを作成し設定します。下記のように、 "/admin" 以下のパスへのリクエストについてAllow/Block用のルールをそれぞれ作成します。

Allow用のルールでは "matchs all the statements (AND)" を指定して、地域制御とURI pathをAND条件で設定します。また、地域制御では "IP address in header" を指定してXFFヘッダーを利用するように設定します。

Block用のルールでは "match the statement" でURI pathに "/admin" 以下を指定してリクエストをBlockします。

検証

では、いよいよ地域制御の検証をしてみます。今回は、東京リージョン(ap-northeast-1)とバージニア北部リージョン(us-east-1)にそれぞれEC2インスタンスを立てて curl コマンドでリクエストを送信することで検証してみます。

まず、東京リージョンで立てたEC2インスタンスからのリクエストの検証です。

$ curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone | sed -e 's/.$//'
ap-northeast-1

# ECサイトにリクエスト
$ curl http://ec.tobachi.dev/
……(略)……
<h1>Welcome to <strong>nginx</strong> on Amazon Linux!</h1>
……(略)……

# 管理用アプリケーションにリクエストを送信すると正常にアクセスできる
$ curl http://ec.tobachi.dev/admin
……(略)……
<h1>Welcome to <strong>nginx</strong> on Amazon Linux!</h1>
……(略)……

続いて、バージニア北部リージョンで立てたEC2インスタンスからのリクエストの検証です。結果として、ECサイトへのリクエストは正常にアクセスできましたが、管理用アプリケーションへのリクエストは権限エラーとなりました。

$ curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone | sed -e 's/.$//'
us-east-1

# ECサイトにリクエスト
$ curl http://ec.tobachi.dev/
……(略)……
<h1>Welcome to <strong>nginx</strong> on Amazon Linux!</h1>
……(略)……

# 管理用アプリケーションにリクエストを送信すると権限エラーとなる
$ curl http://ec.tobachi.dev/admin
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
</body>
</html>

無事に意図した通りの挙動になっていることが確認できました。

おわりに

CloudFront + ALB という構成において、ALBに関連づけたAWS WAFでもX-Forwarded-Forヘッダーを参照すれば、エッジロケーションに関係なくリクエスト元の国や地域に応じた制御が可能となります。

こうした構成の場合、実際のユースケースにおいてAWS WAFを利用する場合はCloudFrontに関連づけることが一般的には多いのではないかと思っています。しかし、要件によってはALBに関連づけることもケースもあるでしょう。

そういった場合でも、地域制御を設定することは可能であることが検証できました。

以上、コンサル部のtobachi(@toda_kk)でした。