Cloud Intelligence™Cloud Intelligence™

Cloud Intelligence™

Tomcatのログに実クライアントIPを記録する(Google Load Balancer配下)

By Eran ChetzroniJan 24, 20192 min read

このページはEnglishDeutschEspañolFrançaisItalianoPortuguêsでもご覧いただけます。

1 2zp9g30kerhlin0nkhtc7q

テクニカルサポート業務の中で、Google Cloud Platform上で稼働するお客様のTomcatサーバーがアクセスログに正しいリモートIPアドレスを記録していないことが判明しました。

原因はもちろん、TomcatがGoogleの優秀なロードバランサーの背後に配置されていたためです。ロードバランサーはクライアントのリモートIPアドレスをX-Forwarded-For HTTPヘッダーに追記します。

1 2zp9g30kerhlin0nkhtc7q

正しいTomcatの設定にたどり着くまで数時間を要したため、同じ問題で悩む方が少しでも時間を節約できるよう、ここで手順を公開しておきます。

変更前:

remoteHostname: 130.211.2.139 // 内部ロードバランサーのアドレス
x-fwd-for= 192.115.200.197, 35.186.199.42

変更後:

remoteHostname: 192.115.200.197 // 実クライアントIP
x-fwd-for= 192.115.200.197, 35.186.199.42

「RemoteIpValve」クラスは、リクエストに記録される見かけ上のクライアントリモートIPアドレスおよびホスト名を、プロキシやロードバランサーからリクエストヘッダー(例: 「X-Forwarded-For」)経由で渡されたIPアドレスのリストで置き換えます。

仕組みは以下の通りです。

  • RemoteIpValveは、前段のロードバランサーまたはプロキシがリクエストのHTTPヘッダー $remoteIpHeader(デフォルトは x-forwarded-for)に格納した、カンマ区切りのIPおよびホスト名のリストをループ処理します。値は右から左の順に処理されます。
  • リスト内の各IP/ホストに対し、internalProxiesと照合します:
  • 内部プロキシのリストに一致した場合、そのIP/ホストは破棄されます。
  • 一致しなかった場合、そのIP/ホストをリモートIPと判定し、ループを終了します。

あとは、IPレンジ 130.211.0.0/2235.191.0.0/16 にマッチする「internalProxies」の正規表現を用意するだけです。

このレンジはGoogleが以下のページで公開しています:

https://cloud.google.com/load-balancing/docs/https/#firewall_rules

"130\.211\.\d{1,3}\.\d{1,3}|35\.191\.\d{1,3}\.\d{1,3}"

さらに、ロードバランサーの外部IPもX-Forwarded-Forヘッダーに追加されるため、これも正規表現に含める必要があります。

今回のケースでは 35.186.199.42 です。

最終的な正規表現は次のようになります:

"130\.211\.\d{1,3}\.\d{1,3}|35\.191\.\d{1,3}\.\d{1,3}|35\.186\.199\.42"

完成形の設定は以下のようになります:

<Valve className="org.apache.catalina.valves.RemoteIpValve"
internalProxies="130\.211\.\d{1,3}\.\d{1,3}|35\.191\.\d{1,3}\.\d{1,3}|35\.186\.199\.42"
/>
<Valve className="org.apache.catalina.valves.AccessLogValve"
directory="logs"
prefix="access_log"
suffix=".txt"
pattern="combined"
requestAttributesEnabled="true" />

これをserver.xmlに追記し、Tomcatサービスを再起動すれば完了です。

それでは、快適なロギングを :)