Azure Firewall の SNAT と X-Forwarded-For の挙動
azure
Published: 2022-06-17

はじめに

Azure Firewall のドキュメントには SNAT と X-Forwarded-For について次の記載があります。

指定したプライベート アドレス範囲は、ネットワーク規則にのみ適用されます。 現時点では、アプリケーション ルールでは常に SNAT が使用されます。

Azure Firewall の SNAT プライベート IP アドレス範囲

さらに、アプリケーション ルールによって処理されたトラフィックでは、常に SNAT が実行されます。 FQDN トラフィックのログに元の送信元 IP アドレスを表示する場合は、宛先 FQDN でネットワーク規則を使用できます。

Azure Firewall で、プライベート ネットワーク間のアウトバウンド SNAT は実行されますか?

HTTP および HTTPS プロトコル (TLS インスペクションあり) には常に、元の送信元 IP アドレスに相当する XFF (X-Forward-For) ヘッダーが Azure Firewall によって付けられます。 

ネットワーク ルールとアプリケーション ルール

つまり…

  • ネットワークルールで許可されたプライベート IP アドレス宛ての通信は SNAT されない
    • ただし、SNAT する宛先をカスタマイズできる
  • アプリケーションルールで許可された通信は宛先に関わらず SNAT される、さらに X-Forwarded-For が付与される

ということです。「百聞は一見に如かず」ということで、実際に環境を作って試してみました。

構成その1

まずはシンプルなサーバ2台の通信を Azure Firewall で制御する構成で試します。

構成その1

172.16.1.100 のサーバには、受信したリクエストの RemoteAddr と X-Forwarded-For だけを表示するシンプルな Web サーバ(kongou-ae/light-ip-echo)が動作しています。

192.168.4.100 のサーバから 172.16.1.100 のサーバへの通信をネットワークルールで許可した場合、次のような出力になります。Azure Firewall は通信を SNAT しないので、RemoteAddr には192.168.4.100 のサーバの IP アドレスが入ります。またネットワークルールの場合 X-Forwarded-For を付与しないので、X-Forwarded-For は空になります。

hubTestVM:~$ curl http://spksv01.aznet.test
{"RemoteAddr":"192.168.4.100:52822","RequestURI":"/","Xforwardedfor":""}

SNAT の宛先に 172.16.0.0/16 を含めるように設定を変更すると、プライベート IP アドレス宛ての通信をネットワークルールで許可した場合であっても SNAT されます。その結果、RemoteAddr が Azure Firewall の IP アドレスになります。

hubTestVM:~$ curl http://spksv01.aznet.test
{"RemoteAddr":"192.168.2.7:52824","RequestURI":"/","Xforwardedfor":""}

同様の通信をアプリケーションルールで許可した場合、次のような出力になります。アプリケーションルールは通信を SNAT するので、RemoteAddr が Azure Firewall の IP になっています、また、アプリケーションルールは X-Forwarded-For を付与するので、X-Forwarded-For に192.168.4.100 のサーバの IP アドレスが入ります。

hubTestVM:~$ curl http://spksv01.aznet.test
{"RemoteAddr":"192.168.2.6:61776","RequestURI":"/","Xforwardedfor":"192.168.4.100:37776"}

構成その2

インターネットへのアウトバウンド通信を試します。

構成その2

ifconfig.me への通信をネットワークルールで許可した場合、Azure Firewall は 192.168.4.100 のサーバの情報を X-Forwarded-For に付与しません。

hubTestVM:~$ curl ifconfig.me/forwarded
104.41.179.235, 34.117.59.81,35.191.10.86

一方で ifconfig.me への通信をアプリケーションルールで許可した場合、Azure Firewall は 192.168.4.100 のサーバの情報を X-Forwarded-For に付与します。

hubTestVM:~$ curl ifconfig.me/forwarded
192.168.4.100:41556, 104.41.179.235, 34.117.59.81,35.191.11.50

構成その3

Application Gateway を Azure Firewall の前に置いた構成を試します。

構成その3

Application Gateway から172.16.1.100 のサーバへの通信をネットワークルールで許可した場合、Azure Firewall は通信を SNAT しないので、Application Gateway から172.16.1.100 のサーバに到達したリクエストの RemoteAddr は Application Gateway の IP アドレスになります。また、ネットワークルールは X-Forwarded-For を付与しないため、172.16.1.100 のサーバに到達したリクエストの X-Forwarded-For には、前段の Application Gateway が付与した 192.168.4.100 のサーバの IP アドレスだけが含まれます。

hubTestVM:~$ curl http://agw.aznet.test:8080
{"RemoteAddr":"192.168.5.7:35194","RequestURI":"/","Xforwardedfor":"192.168.4.100:45200"}

Application Gateway から172.16.1.100 のサーバへの通信をアプリケーションルールで許可した場合、Azure Firewall は通信を SNAT するので、Application Gateway から172.16.1.100 のサーバに到達したリクエストの RemoteAddr は Azure Firewall の IP アドレスになります。また、アプリケーションルールは X-Forwarded-For を付与するのですが、現在の仕様では、Azure Firewall は X-Forwarded-For を上書きします。そのため、172.16.1.100 のサーバに到達したリクエストの X-Forwarded-For には、Azure Firewall が付与した Application Gateway の IP アドレスだけが含まれます。前段の Application Gateway が X-Forwarded-For に付与した 192.168.4.100 のサーバの IP アドレスは消失します。

hubTestVM:~$ curl http://agw.aznet.test:8080
{"RemoteAddr":"192.168.2.7:45062","RequestURI":"/","Xforwardedfor":"192.168.5.5:55432"}

構成その4

X-Forwarded-For の挙動を確認するために、Application Gateway を Azure Firewall の後段に置いた構成も試します。

構成その4

クライアントから Application Gateway への通信をネットワークルールで許可した場合、Azure Firewall は通信を SNAT しないので、Application Gateway に到達するリクエストは「RemoteAddr:192.168.4.100 のサーバの IP アドレス、X-Forwarded-For:なし」になります。

このリクエストをもとに Application Gateway が 172.16.1.100 のサーバにアクセスする際に、Application Gateway はアクセス元である 192.168.4.100 のサーバの情報を X-Forwarded-For に付与します。したがって、172.16.1.100 のサーバに到達するリクエストは「RemoteAddr:Application Gateway の IP アドレス、X-Forwarded-For:192.168.4.100 のサーバの IP アドレス」になります。

hubTestVM:~$ curl http://agwspk.aznet.test:8080
{"RemoteAddr":"172.16.2.4:36142","RequestURI":"/","Xforwardedfor":"192.168.4.100:34234"}

この通信をアプリケーションルールで許可した場合、Azure Firewall は通信を SNAT かつ X-Forwarded-For を付与するので、Application Gateway に到達するリクエストは「RemoteAddr:Azure Firewall の IP アドレス、X-Forwarded-For:192.168.4.100 のサーバの IP アドレス」になります。

このリクエストをもとに Application Gateway が 172.16.1.100 のサーバにアクセスする際に、Application Gateway はアクセス元である 192.168.4.100 のサーバの情報を X-Forwarded-For に追記します。Application Gateway は X-Forwarded-For を上書きしません。したがって、172.16.1.100 のサーバに到達するリクエストは「RemoteAddr:Application Gateway の IP アドレス、X-Forwarded-For:192.168.4.100 のサーバの IP アドレス, Azure Firewall の IP アドレス」になります。

hubTestVM:~$ curl http://agwspk.aznet.test:8080
{"RemoteAddr":"172.16.2.5:32636","RequestURI":"/","Xforwardedfor":"192.168.4.100:34232, 192.168.2.6:51910"}

まとめ

様々な構成を組んだうえで、Azure Firewall の SNAT と X-Forwarded-For の動作を確認しました。現在の仕様では Azure Firewall は X-Forwarded-For を上書きします。そのため次のような振る舞いだと理解したうえで設計に臨みましょう。

  • ネットワークルールで許可されたプライベート IP アドレス宛ての通信は SNAT されない
    • ただし、SNAT する宛先をカスタマイズできる
  • アプリケーションルールで許可された通信は宛先に関わらず SNAT される、さらに X-Forwarded-For を上書きする
    • 上書きが望ましくない場合は、上書きされたくない通信をネットワークルールで許可する