ALB の後ろの Web サーバーでクライアントの IP が分からないときの確認ポイント ── X-Forwarded-For と NLB の送信元 IP の保持

目次

概要

Web サーバーを Application Load Balancer(ALB)の後ろに置いたとたん、アクセスログの送信元 IP アドレスが 10.0.1.23 のような VPC 内のアドレスばかりになり、どのクライアントからのアクセスなのか分からなくなることがあります。これは設定ミスではなく、ALB の仕組みによるものです。ALB はクライアントとの接続をいったん受け取り、ターゲットへは ALB 自身が新しい接続を張るので、Web サーバーから見た送信元は ALB のプライベート IP アドレスになります。

クライアントの IP アドレスは、ALB がリクエストに付ける X-Forwarded-For ヘッダーに入っています。Web サーバーのログ形式にこのヘッダーを足せば、ログに実際のクライアント IP を出せます。一方、Network Load Balancer(NLB)は、ターゲットをインスタンス ID で登録すると、Web サーバー側で何も設定しなくても送信元 IP アドレスがクライアントのまま届きます。ただし、IP アドレスで登録したときは既定の動きが変わります。

この記事では、ALB と NLB でクライアント IP の届き方がどう違うかを整理します。実践では、ALB 配下の Apache のログに ALB の IP しか出ない状態を確かめてから、ログ形式に X-Forwarded-For を足して直します。続けて NLB を作り、インスタンス ID で登録したとき・IP アドレスで登録したときに、ログの送信元 IP がどう変わるかを比べます。

ALB の後ろでは送信元が ALB に変わり、クライアント IP は X-Forwarded-For で届く
ALB の後ろでは送信元が ALB に変わり、クライアント IP は X-Forwarded-For で届く
クラウドおさる

猿山の門番が手紙を預かって中へ届け直すと、受け取った猿には門番の名前しか見えぬのでござる。今日は、差出人の名前をどこに書いてもらえば分かるのかを確かめるでござるよ。

この記事のメリット

  • ALB の後ろの Web サーバーで、送信元 IP が ALB の IP になる理由を説明できるようになる
  • Apache のログ形式に X-Forwarded-For を足して、クライアント IP をログに出せるようになる
  • ALB の X-Forwarded-For の処理モード(付加・保持・削除)の違いと、ヘッダーをどこまで信用してよいかが分かる
  • NLB でターゲットをインスタンス ID で登録したときと IP アドレスで登録したときの、クライアント IP の保持の既定値の違いが分かる
  • NLB のセキュリティグループの有無で、ターゲット側のセキュリティグループに何を許可するかが変わることが分かる

執筆者とキャラクター紹介

執筆者:土肥(とひ)

株式会社ジェニュインの代表であり元エンジニア。これまでオンプレミスと AWS 環境のインフラ業務を担当。AWS 認定資格の学習で得た知識を、ハンズオンとともに解説するのが得意。直近では新人の教育も行っており、これから技術を学ぶ方が納得できる解説を心がけています。基礎編・Cloud Practitioner の記事では、解説役としても登場します。

土肥

クラウドおさる

クラウドおさる

はじめましてでござる。弊猿はクラウドおさる。IT インフラが異常に発達した猿山から、雲に乗って地上の AWS を学びに降りてきたのでござる。

クラウドおさる

基礎編や Cloud Practitioner の記事では、とひさんに素朴な疑問をぶつける役でござるな。Security - Specialty などの記事では、要所でワンポイントや注意点をひとこと添えるでござる。

クラウドおさる

猿山にもデータセンターや監視当番があって、地上で起きることはだいたい猿山にも同じ仕組みがあるのでござる。例え話がつい猿山に寄るのは、弊猿の癖でござる。

技術解説

なぜ ALB の後ろではクライアントの IP が見えないのか

ALB は HTTP / HTTPS のレベルで動くロードバランサーです。クライアントとの接続は ALB で受け止め、ターゲットへのリクエストは ALB が自分の接続で送り直します。そのため、Web サーバーが受け取るパケットの送信元は、ALB のノード(ALB を置いたサブネットにあるネットワークインターフェイス)のプライベート IP アドレスになります。

ロードバランサーWeb サーバーから見た送信元 IPクライアント IP の受け取り方
ALBALB のプライベート IP アドレスX-Forwarded-For ヘッダーから読む
NLB(インスタンス ID で登録)クライアントの IP アドレス(既定でクライアント IP を保持)そのまま送信元 IP として見える
NLB(IP アドレスで登録・TCP / TLS)NLB のプライベート IP アドレス(既定ではクライアント IP を保持しない)クライアント IP の保持を有効にするか、プロキシプロトコル v2 を使う

NLB は X-Forwarded-For ヘッダーを付けません。また、ロードバランサーのヘルスチェックのリクエストにも X-Forwarded-For は含まれません。ログでこのヘッダーの欄が空(-)になっている行があっても、それだけで異常とは限りません。

ALB は接続を受け直してヘッダーにクライアント IP を足し、NLB はパケットの送信元をそのまま渡す
ALB は接続を受け直してヘッダーにクライアント IP を足し、NLB はパケットの送信元をそのまま渡す

X-Forwarded-For ヘッダーと Apache のログ形式

ALB は、ターゲットへ送るリクエストの X-Forwarded-For ヘッダーにクライアントの IP アドレスを入れます。

X-Forwarded-For: 203.0.113.7

Web サーバーのアクセスログは、既定では接続の送信元(ALB の IP アドレス)を記録します。クライアント IP を残すには、ログ形式にこのヘッダーを足します。Amazon Linux の Apache(httpd)では、設定ファイル /etc/httpd/conf/httpd.conf の LogFormat に %{X-Forwarded-For}i を加えます。

LogFormat "%{X-Forwarded-For}i %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined

%h は接続の送信元、%{X-Forwarded-For}i はリクエストヘッダー X-Forwarded-For の値です。両方を残しておくと、どのロードバランサーのノードを経由したかと、元のクライアントが誰かを 1 行で見られます。設定を変えたら Apache をリロードします。NGINX なら log_format に $http_x_forwarded_for を足します。

クラウドおさる

門番の名前(%h)は消さずに、手紙に書かれた差出人(X-Forwarded-For)を横に並べて書き写すのでござる。どちらも残しておけば、どの門を通ってきたかも後で追えるのでござるな。

X-Forwarded-For の処理モード

ALB の属性 routing.http.xff_header_processing.mode で、ALB が X-Forwarded-For をどう扱うかを選べます。コンソールでは、ロードバランサーの「属性」タブの「トラフィックの設定」→「パケット処理」にある「X-Forwarded-For ヘッダー」です。

モードコンソールの表示動き
append(既定)付加クライアント IP を X-Forwarded-For に入れてターゲットへ送る。リクエストにすでにヘッダーがあれば、その末尾にクライアント IP を付け足す
preserve保持リクエストの X-Forwarded-For を変えずにそのまま送る
remove削除ターゲットへ送る前に X-Forwarded-For を取り除く

append では、クライアントが自分で X-Forwarded-For: 127.0.0.4, 127.0.0.8 を付けて送ってくると、ターゲットには 127.0.0.4, 127.0.0.8, 127.0.0.1(末尾が ALB が見た接続元)が届きます。先頭のほうの値はクライアントが自由に書けるので、そのまま信用してはいけません。AWS のドキュメントでも、X-Forwarded-For のエントリは、ネットワーク内で適切に保護されたシステムが付けたものだけを信頼できるとしています。ALB の直後の Web サーバーで見るなら、ALB が付け足した末尾の値がクライアント IP です。

このほか、処理モードが append のときに属性 routing.http.xff_client_port.enabled を有効にすると、X-Forwarded-For に IP アドレスとあわせてクライアントのポート番号(203.0.113.7:8080 の形)も入ります。preserve や remove を選んでいる場合は、処理モードのほうが優先され、ポート番号は付きません。

クラウドおさる

差出人の欄は、手紙を書いた本人がいくらでも書き足せるのでござる。アクセス制限や不正の調査に使うなら、門番(ALB)が最後に書き足した末尾の名前を見るのでござるぞ。

NLB のクライアント IP の保持

NLB は TCP / UDP のレベルで動き、ターゲットグループの属性 preserve_client_ip.enabled(コンソールでは「クライアント IP アドレスの保持」)で、ターゲットに届く送信元 IP をクライアントのままにするかを決めます。既定値はターゲットタイプとプロトコルで変わります。

ターゲットグループクライアント IP の保持の既定値
ターゲットタイプが「インスタンス」有効
ターゲットタイプが「IP アドレス」、プロトコルが TCP / TLS無効(有効に変えられる)
ターゲットタイプが「IP アドレス」、プロトコルが UDP / TCP_UDP / QUIC / TCP_QUIC有効(無効にできない)

ターゲットタイプは、ターゲットグループを作った後では変えられません。IP アドレスで登録するターゲットグループには、ターゲットグループの VPC のサブネットのほか、RFC 1918 などのプライベート IP アドレス範囲のアドレスを指定できます(パブリックにルーティングできる IP アドレスは指定できません)。

クライアント IP の保持には制約もあります。主なものは次のとおりです。

  • 設定の変更は、新しい TCP 接続にだけ効く
  • ターゲットが NLB を経由して自分自身にアクセスする構成(NAT ループバック、ヘアピン)はサポートされない
  • トランジットゲートウェイ経由でターゲットに届く場合や、AWS PrivateLink 経由のトラフィックでは、送信元 IP はクライアントにならない(PrivateLink のトラフィックの送信元は常に NLB のプライベート IP アドレス)

クライアント IP の保持を使えない場合は、プロキシプロトコル v2 を有効にする方法があります。NLB が送信元・送信先などの接続情報をバイナリ形式のヘッダーにして、TCP のデータの先頭に付けて送ります。受け取るアプリケーションがこのヘッダーを解釈できる必要があり、解釈できないまま有効にすると通信が壊れます。Apache なら mod_remoteip モジュール(Apache 2.4.31 以降)の RemoteIPProxyProtocol On で読み取れます。

NLB のセキュリティグループとターゲット側の許可

ALB のターゲットでは、ターゲットのセキュリティグループのインバウンドルールの送信元に ALB のセキュリティグループを指定し、ALB からの通信だけを受け付けるのが基本です。

NLB はセキュリティグループを付けても付けなくても作れますが、セキュリティグループを付けずに作った NLB には、後からセキュリティグループを関連付けられません。作成時に 1 つ以上付けておけば、後で入れ替えられます。どちらにしたかで、ターゲットのセキュリティグループで許可するものが変わります。

NLB のセキュリティグループターゲットのセキュリティグループで許可するもの
ありNLB のセキュリティグループを送信元にしたルール。クライアント IP の保持が有効でも、これで NLB 経由の通信を受け付けられる
なしクライアント IP を保持しているなら、許可したいクライアントの IP アドレス。保持していないなら NLB のプライベート IP アドレス。ヘルスチェックは NLB のプライベート IP アドレスから

セキュリティグループの無い NLB でクライアント IP を保持していると、ターゲット側でクライアントの IP アドレス(公開サイトなら 0.0.0.0/0)を許可することになり、「NLB からだけ受け付ける」という絞り方ができません。NLB を作るときはセキュリティグループを付けておくと、ALB と同じ考え方でターゲットを守れます。

新卒・未経験の方へ
クラウドおさる

AWS を仕事にしたい方へ ── 新卒・未経験から

この記事を書いているのは、AWS の設計・構築を仕事にしている現役エンジニアです。運営元の株式会社ジェニュインでは、新卒・未経験の方も募集しています。異業種や文系からインフラエンジニアになり活躍しているメンバーもいます。

  • ✓システム開発・WEB エンジニア / インフラ構築などの職種で、未経験から応募できます
  • ✓未経験から入社した社員の声を含む社員アンケートを掲載
  • ✓応募フォームから 1 分で応募できます

実践

ALB 配下の Apache のアクセスログに ALB の IP アドレスしか出ない状態を確かめてから、ログ形式に X-Forwarded-For を足してクライアント IP を出します。続けて NLB を作り、ターゲットをインスタンス ID で登録したとき、IP アドレスで登録したとき、IP アドレスで登録してクライアント IP の保持を有効にしたときの 3 つで、ログの送信元 IP を比べます。

前提条件

  • リージョン: ap-northeast-1(東京)
  • EC2・Elastic Load Balancing・Systems Manager の操作権限を持つ IAM ユーザーまたはロールでコンソールにログイン済みであること
  • 手元のパソコンで curl コマンドが使えること(Windows 10 以降・macOS には標準で入っています)

以下のリソースが作成済みであることを前提とします。

まだ用意していない場合は、「作り方の参考」の記事の手順で作れます。リソース名は、この記事の名前に読み替えてください。

リソース種別リソース名内容作り方の参考
VPCxff-lab-vpcCIDR 10.0.0.0/16。インターネットゲートウェイ xff-lab-igw 付きAmazon VPC で仮想ネットワークを構築しサブネットを設定する ※AZ を 2 つにする
パブリックサブネットxff-lab-public-1a / xff-lab-public-1c10.0.1.0/24(1a)/ 10.0.2.0/24(1c)同上
セキュリティグループxff-lab-alb-sgALB 用。HTTP 80 をどこからでも許可セキュリティグループとネットワーク ACL でアクセスを制御する
セキュリティグループxff-lab-nlb-sgNLB 用。TCP 80 をどこからでも許可(この記事で NLB を作るときに選ぶ)同上
セキュリティグループxff-lab-web-sgEC2 用。TCP 80 を xff-lab-alb-sg と xff-lab-nlb-sg からだけ許可同上
EC2 インスタンスxff-lab-webxff-lab-public-1a に配置。Amazon Linux 2023 に Apache(httpd)を入れ、ログ形式は既定のまま。IAM ロール xff-lab-web-role(AmazonSSMManagedInstanceCore)付きで Session Manager で接続できるAmazon EC2 でインスタンスを起動しSSH接続する
Application Load Balancerxff-lab-albインターネット向け、xff-lab-public-1a / 1c、xff-lab-alb-sg。HTTP:80 のリスナーでターゲットグループ xff-lab-alb-tg(xff-lab-web を登録)へ転送―

このハンズオンで作成するリソースは以下のとおりです。

リソース種別リソース名用途
ターゲットグループxff-lab-nlb-tgNLB 用。ターゲットタイプ「インスタンス」で xff-lab-web を登録
ターゲットグループxff-lab-nlb-ip-tgNLB 用。ターゲットタイプ「IP アドレス」で xff-lab-web のプライベート IP アドレスを登録
Network Load Balancerxff-lab-nlbインターネット向け、xff-lab-public-1a、xff-lab-nlb-sg。TCP:80 のリスナー

ALB と NLB は、存在している間ずっと時間単位で課金され、処理したトラフィックに応じた料金(LCU / NLCU)もかかります。ロードバランサーと EC2 インスタンスに付くパブリック IPv4 アドレスも課金対象です。検証が終わったら必ず削除してください。

手順 1: ALB 経由のアクセスで、ログに ALB の IP しか出ないことを確かめる

AWS マネジメントコンソールにログインし、リージョンが ap-northeast-1(東京)であることを確認します。上部の検索バーに EC2 と入力し、「EC2」を選択します。

左側ナビゲーションの「ロードバランシング」→「ロードバランサー」を選択し、xff-lab-alb を選択します。「詳細」の「DNS 名」をコピーします。

手元のパソコンのターミナル(Windows の PowerShell では curl の代わりに curl.exe と入力します)で、自分のグローバル IP アドレスを確かめてから、ALB にアクセスします。

curl -s https://checkip.amazonaws.com
curl -s http://<コピーした ALB の DNS 名>/

1 行目で表示された IP アドレスが、この後ログに出てほしいクライアント IP です。2 行目で xff-lab-web と表示されれば、ALB 経由で Web サーバーに届いています。

コンソールに戻り、左側ナビゲーションの「インスタンス」で xff-lab-web を選択して、「接続」をクリックします。「Session Manager」タブで「接続」をクリックし、表示されたターミナルで次のコマンドを実行します。手元の curl からのアクセスだけを取り出して、最後の 3 行を表示します。

sudo grep curl /var/log/httpd/access_log | tail -n 3

行の先頭の送信元 IP アドレスが、10.0.1.x や 10.0.2.x のような ALB のサブネットのアドレスになっていることを確認します。手元のグローバル IP アドレスはどこにも出ていません。

xff-lab-web の Session Manager で access_log を表示した結果(送信元が 10.0.1.x / 10.0.2.x の ALB の IP になっている)
xff-lab-web の Session Manager で access_log を表示した結果(送信元が 10.0.1.x / 10.0.2.x の ALB の IP になっている)

手順 2: ALB の X-Forwarded-For の処理モードを確かめる

EC2 コンソールの「ロードバランサー」で xff-lab-alb を選択し、「属性」タブを開きます。「パケット処理」の「X-Forwarded-For ヘッダー」が 付加(既定)になっていることを確認します。ALB は、ターゲットへ送るリクエストの X-Forwarded-For にクライアント IP を付け足しています。ここは変更しません。

手順 3: Apache のログ形式に X-Forwarded-For を足す

xff-lab-web の Session Manager に戻り、次のコマンドで、ログ形式 combined の先頭に %{X-Forwarded-For}i を足します。

sudo sed -i '/" combined$/s/LogFormat "%h/LogFormat "%{X-Forwarded-For}i %h/' /etc/httpd/conf/httpd.conf
sudo grep 'combined$' /etc/httpd/conf/httpd.conf

表示された LogFormat の行が、LogFormat "%{X-Forwarded-For}i %h %l %u %t …" combined に変わっていることを確認します。設定ファイルの書き方に誤りがないかを確かめてから、Apache をリロードします。

sudo apachectl configtest
sudo systemctl reload httpd

Syntax OK と表示されれば問題ありません。手元のパソコンから、もう一度 ALB にアクセスします。

curl -s http://<ALB の DNS 名>/

Session Manager でログを確かめます。

sudo grep curl /var/log/httpd/access_log | tail -n 3

最後の行の先頭に、手順 1 で確かめた手元のグローバル IP アドレスが出ていることを確認します。その次の欄(%h)は、これまでどおり ALB の IP アドレスです。

ログ形式を変えた後の access_log(先頭にクライアントのグローバル IP、続けて ALB の IP が出ている)
ログ形式を変えた後の access_log(先頭にクライアントのグローバル IP、続けて ALB の IP が出ている)

手順 4: X-Forwarded-For を自分で付けて送るとどうなるかを確かめる

手元のパソコンから、X-Forwarded-For ヘッダーを自分で付けて ALB にアクセスします。192.0.2.10 はドキュメント用に予約されたアドレスです。

curl -s -H "X-Forwarded-For: 192.0.2.10" http://<ALB の DNS 名>/

Session Manager でログを確かめます。

sudo grep curl /var/log/httpd/access_log | tail -n 1

先頭の欄が 192.0.2.10, <手元のグローバル IP> になっていることを確認します。ALB は既定の「付加」モードで、クライアントが送ってきた値の末尾に、自分が見た接続元の IP アドレスを付け足しています。先頭の 192.0.2.10 はクライアントが書いた値なので、クライアント IP として使うのは末尾の値です。

自分で X-Forwarded-For を付けて送ったときの access_log(192.0.2.10 の後ろに手元のグローバル IP が付け足されている)
自分で X-Forwarded-For を付けて送ったときの access_log(192.0.2.10 の後ろに手元のグローバル IP が付け足されている)

手順 5: NLB 用のターゲットグループ(インスタンス)を作る

EC2 コンソールの左側ナビゲーションで「ロードバランシング」→「ターゲットグループ」を選択し、「ターゲットグループの作成」をクリックします。以下を設定します。

  • ターゲットの種類: インスタンス
  • ターゲットグループ名: xff-lab-nlb-tg
  • プロトコル: TCP、ポート: 80
  • VPC: xff-lab-vpc

その他の項目(ヘルスチェックなど)はデフォルトのままにして、「次へ」をクリックします。ヘルスチェックのプロトコルは、API の既定では TCP ですが、撮影時のコンソールでは HTTP(パス /)が入っていました。Apache が / に 200 を返すので、どちらのままでもヘルスチェックに合格します。

ターゲットグループの作成画面(ターゲットタイプがインスタンス、プロトコル TCP、ポート 80)
ターゲットグループの作成画面(ターゲットタイプがインスタンス、プロトコル TCP、ポート 80)

「ターゲットの登録」で xff-lab-web にチェックを入れ、ポートが 80 であることを確認して「保留中として以下を含める」をクリックします。「ターゲットグループの作成」をクリックします。

手順 6: NLB を作る

左側ナビゲーションの「ロードバランサー」で「ロードバランサーの作成」をクリックし、「Network Load Balancer」の「作成」をクリックします。以下を設定します。

  • ロードバランサー名: xff-lab-nlb
  • スキーム: インターネット向け
  • ロードバランサーの IP アドレスタイプ: IPv4
  • ネットワークマッピング: VPC は xff-lab-vpc、アベイラビリティーゾーンは ap-northeast-1a だけにチェックを入れ、サブネット xff-lab-public-1a を選択(ターゲットの xff-lab-web が ap-northeast-1a にあるため)
  • セキュリティグループ: 既定で選ばれている default を外し、xff-lab-nlb-sg を選択
  • リスナーとルーティング: プロトコル TCP、ポート 80、デフォルトアクションのターゲットグループに xff-lab-nlb-tg を選択

その他の項目はデフォルトのままにして、「ロードバランサーの作成」をクリックします。

NLB の作成画面(セキュリティグループに xff-lab-nlb-sg、リスナーが TCP:80 → xff-lab-nlb-tg)
NLB の作成画面(セキュリティグループに xff-lab-nlb-sg、リスナーが TCP:80 → xff-lab-nlb-tg)

NLB のセキュリティグループは、作成するときに 1 つ以上付けておかないと、後から付けられません(付けて作った NLB なら、後でいつでも入れ替えられます)。ここで外したまま作らないように注意してください。

クラウドおさる

NLB の門番の腕章(セキュリティグループ)は、門を建てるときにしか渡せないのでござる。付け忘れて建てると、Web サーバー側でクライアントの IP を直接許可するしかなくなるでござるぞ。

手順 7: インスタンス ID で登録したときの送信元 IP を確かめる

xff-lab-nlb の状態が アクティブ になり、ターゲットグループ xff-lab-nlb-tg の「ターゲット」タブで xff-lab-web のヘルスステータスが Healthy になるまで数分待ちます。xff-lab-nlb の「DNS 名」をコピーし、手元のパソコンからアクセスします。

curl -s http://<コピーした NLB の DNS 名>/

Session Manager でログを確かめます。

sudo grep curl /var/log/httpd/access_log | tail -n 1

先頭の X-Forwarded-For の欄は -(NLB はヘッダーを付けない)で、次の欄(%h、接続の送信元)が手元のグローバル IP アドレスになっていることを確認します。Web サーバー側で何も設定しなくても、送信元 IP がクライアントのまま届いています。

NLB(インスタンス ID で登録)経由の access_log(X-Forwarded-For は「-」、送信元にクライアントのグローバル IP が出ている)
NLB(インスタンス ID で登録)経由の access_log(X-Forwarded-For は「-」、送信元にクライアントのグローバル IP が出ている)

手順 8: IP アドレスで登録したターゲットグループに切り替える

EC2 コンソールの「インスタンス」で xff-lab-web を選択し、「詳細」タブの「プライベート IPv4 アドレス」を控えておきます。

「ターゲットグループ」で「ターゲットグループの作成」をクリックし、以下を設定します。

  • ターゲットの種類: IP アドレス
  • ターゲットグループ名: xff-lab-nlb-ip-tg
  • プロトコル: TCP、ポート: 80
  • VPC: xff-lab-vpc

「次へ」をクリックし、「ターゲットの登録」で、控えておいた xff-lab-web のプライベート IPv4 アドレスを入力し、ポート 80 で「保留中として以下を含める」をクリックします。「ターゲットグループの作成」をクリックします。

作成した xff-lab-nlb-ip-tg を開き、「属性」タブを選択します。「クライアント IP アドレスの保持」が オフ になっていることを確認します。IP アドレスで登録した TCP のターゲットグループでは、これが既定値です。

xff-lab-nlb-ip-tg の属性タブ(クライアント IP アドレスの保持がオフ)
xff-lab-nlb-ip-tg の属性タブ(クライアント IP アドレスの保持がオフ)

「ロードバランサー」で xff-lab-nlb を選択し、「リスナーとルール」タブで TCP:80 のリスナーにチェックを入れ、「リスナーの管理」→「リスナーの編集」を選択します。デフォルトアクションのターゲットグループを xff-lab-nlb-ip-tg に変えて、「変更内容の保存」をクリックします。

xff-lab-nlb-ip-tg の「ターゲット」タブで、登録した IP アドレスのヘルスステータスが Healthy になるまで待ってから、手元のパソコンから NLB にアクセスし、Session Manager でログを確かめます。

curl -s http://<NLB の DNS 名>/
sudo grep curl /var/log/httpd/access_log | tail -n 1

%h の欄が、手元のグローバル IP アドレスではなく 10.0.1.x(NLB のプライベート IP アドレス)になっていることを確認します。同じ NLB でも、ターゲットを IP アドレスで登録すると、既定ではクライアント IP が届かなくなります。

NLB(IP アドレスで登録・保持オフ)経由の access_log(送信元が NLB のプライベート IP になっている)
NLB(IP アドレスで登録・保持オフ)経由の access_log(送信元が NLB のプライベート IP になっている)

手順 9: クライアント IP アドレスの保持を有効にする

xff-lab-nlb-ip-tg の「属性」タブで「編集」をクリックし、「トラフィック設定」の「クライアント IP アドレスの保持」をオンにして、「変更内容の保存」をクリックします。

設定の変更は新しい TCP 接続にだけ効きます。手元のパソコンから、もう一度 NLB にアクセスします(curl はコマンドごとに新しい接続を張ります)。

curl -s http://<NLB の DNS 名>/
sudo grep curl /var/log/httpd/access_log | tail -n 1

%h の欄が、手元のグローバル IP アドレスに戻ったことを確認します。xff-lab-web-sg は送信元に xff-lab-nlb-sg を指定しているだけですが、NLB にセキュリティグループを付けてあるので、クライアント IP のまま届く通信も受け付けられています。

クライアント IP アドレスの保持をオンにした後の access_log(送信元がクライアントのグローバル IP に戻っている)
クライアント IP アドレスの保持をオンにした後の access_log(送信元がクライアントのグローバル IP に戻っている)
クラウドおさる

ALB なら「X-Forwarded-For をログに出す」、NLB なら「インスタンス ID で登録すればそのまま、IP アドレスで登録したら保持の設定かプロキシプロトコル v2」でござる。どのロードバランサーで、どう登録したかを取り違えないことでござるな。

まとめ

構成Web サーバーから見た送信元クライアント IP を知る方法
ALBALB のプライベート IP アドレスX-Forwarded-For ヘッダーをログに出す(末尾の値が ALB が見た接続元)
NLB(インスタンス ID で登録)クライアントの IP アドレス設定不要(クライアント IP の保持が既定で有効)
NLB(IP アドレスで登録・TCP / TLS)NLB のプライベート IP アドレスクライアント IP の保持を有効にする。使えない構成ではプロキシプロトコル v2
  • ALB はクライアントとの接続を終端し、ターゲットへは自分の接続で送るので、送信元 IP は ALB のプライベート IP アドレスになる
  • Apache は LogFormat に %{X-Forwarded-For}i、NGINX は log_format に $http_x_forwarded_for を足すとクライアント IP をログに出せる
  • X-Forwarded-For の処理モードは「付加」(既定)・「保持」・「削除」。付加ではクライアントが送った値の末尾に ALB が接続元を付け足すので、先頭の値はそのまま信用しない
  • NLB は X-Forwarded-For を付けない。クライアント IP の保持の既定値は、インスタンスなら有効、IP アドレス(TCP / TLS)なら無効。ターゲットタイプは後から変えられない
  • プロキシプロトコル v2 は、受け取るアプリケーションがヘッダーを解釈できるようにしてから有効にする
  • セキュリティグループを付けずに作った NLB には、後から付けられない(付けて作れば後で入れ替えられる)。付けておけば、ターゲットのセキュリティグループで NLB のセキュリティグループを送信元に指定できる。付けないと、クライアント IP を保持している場合はクライアントの IP アドレスを直接許可することになる

関連する記事として、ターゲットにつながらないときの切り分けは「ALB環境でのWeb Serverインバウンド接続トラブルシューティング ── 1台だけつながらない原因の切り分け」、ALB と NLB のヘルスチェックの違いは「ALB と NLB のヘルスチェックの違い ── HTTP のパスと成功コードで見るか、TCP の接続で見るか」で扱っています。

参照先

キャリア相談
クラウドおさる

独学の先に、AWS の仕事がある ── ジュニアおさるのキャリア相談

CLF には受かったけれど、次に何をすればいいのか分からない。独学で AWS を学ぶジュニアおさるの相談に、株式会社ジェニュイン代表の土肥が答えています。

  • ✓資格はゴールか、CLF の次に何から手を付けるか
  • ✓EC2 の次に作ってみる構成と、IaC・コスト管理
  • ✓実務経験ゼロでも、面接で話せる「これまで」の作り方
新卒・未経験の方へ
クラウドおさる

AWS を仕事にしたい方へ ── 新卒・未経験から

この記事を書いているのは、AWS の設計・構築を仕事にしている現役エンジニアです。運営元の株式会社ジェニュインでは、新卒・未経験の方も募集しています。異業種や文系からインフラエンジニアになり活躍しているメンバーもいます。

  • ✓システム開発・WEB エンジニア / インフラ構築などの職種で、未経験から応募できます
  • ✓未経験から入社した社員の声を含む社員アンケートを掲載
  • ✓応募フォームから 1 分で応募できます

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

株式会社ジェニュイン(https://genuine-pt.jp)の代表取締役.

2018年〜インフラエンジニアとしてキャリアをスタートし、オンプレミスのネットワーク・サーバ環境で3年半、クラウド環境で4年半の8年間エンジニアとして従事。
2021年に佐藤氏の創業した株式会社Luxyを引き継ぎ、代表に就任。
その後アガルートグループ内の株式会社ジェニュインと合併。
合併後同社代表に就任。

目次