お久しぶりです、AWSが好きなインフラ担当の大久保です。
12月にフルマラソンに参加することになり、最近ジョギングに力を入れてます。
今回は、以前遭遇した「Apacheのアクセスログと、Redmineのproduction.logの送信元アドレスが異なっている状態」について、調査・検証した内容と、解決方法について話したいと思います。
目次
どんな環境で起こるか?
そもそも、どんな環境で送信元IPが異なる状態になるか?というと、以下の条件に当てはまる環境で起こる可能性があります。
X-Forwarded-For
ヘッダーの付与を行うプロキシ、リバースプロキシサーバーを複数経由している- Apacheで
RemoteIPHeader X-Forwarded-For
とRemoteIPInternalProxy
の設定が有効化されている
一例ですが、図にするとこんな環境です。
場所 | X-Forwarded-For ヘッダーの中身 |
---|---|
端末 | – |
プロキシサーバー | xxx.xxx.xxx.xxx |
ALB | xxx.xxx.xxx.xxx, yyy.yyy.yyy.yyy |
上図の環境では、X-Forwarded-For
ヘッダー付与の設定がされた「プロキシサーバー」と「ALB(リバースプロキシサーバー)」の2つを経由することで、Redmineサーバーにリクエストが届く時にはX-Forwarded-For
ヘッダー内に複数のIPアドレスがある状態になります。
そして、Apacheのアクセスログ上での送信元がyyy.yyy.yyy.yyy
、Redmineのproduction.log上での送信元はxxx.xxx.xxx.xxx
という、不可思議な状態となっていました。
なんでこんなことになるのか?
大久保が調査・検証した結果ベースでの話になりますが、下記の2つが起因していると考えています。
- Apacheの設定によって、
X-Forwarded-For
ヘッダーの評価方法が違う - Apacheから
X-Forwarded-For
ヘッダーを渡された場合、Redmineはヘッダー内の一番右のIPアドレスを送信元IPアドレスとして利用する
根拠
たぶんX-Forwarded-For
ヘッダーが悪さしてるんだろうなーと思い、Apacheの設定によってX-Forwarded-For
ヘッダーがどう扱われるかを調査しました。
具体的には、以下の4パターンの設定で検証を行いました。
パターン | RemoteIPHeader X-Forwarded-For | RemoteIPInternalProxy | RequestHeader unset X-Forwarded-For |
---|---|---|---|
1 | ◯ | – | – |
2 | ◯ | ◯ | – |
3 | ◯ | – | ◯ |
4 | ◯ | ◯ | ◯ |
結果は以下の表の通りとなり、送信元IPアドレスが異なっている状態となったのは「パターン2」でした。
パターン | 評価前のX-Forwarded-For ヘッダーの中身 | Apache上での送信元IPアドレス | 評価後のX-Forwarded-For ヘッダーの中身 | Redmine上での送信元IPアドレス |
---|---|---|---|---|
1 | xxx.xxx.xxx.xxx, yyy.yyy.yyy.yyy | xxx.xxx.xxx.xxx | – | xxx.xxx.xxx.xxx |
2 | xxx.xxx.xxx.xxx, yyy.yyy.yyy.yyy | yyy.yyy.yyy.yyy | xxx.xxx.xxx.xxx | xxx.xxx.xxx.xxx |
3 | xxx.xxx.xxx.xxx, yyy.yyy.yyy.yyy | xxx.xxx.xxx.xxx | – | xxx.xxx.xxx.xxx |
4 | xxx.xxx.xxx.xxx, yyy.yyy.yyy.yyy | yyy.yyy.yyy.yyy | – | yyy.yyy.yyy.yyy |
この結果から以下のような動きをしていそうなことがわかり、Apacheの処理でX-Forwarded-For
ヘッダーの中身が一部残された状態で、RedmineにX-Forwarded-For
ヘッダー引き渡されることが原因と判断しました。
- Apacheでの処理
RemoteIPHeader X-Forwarded-For
を設定した場合- ヘッダー内のアドレスを一番右から評価していき、一番左のアドレスが信頼出来る送信元として判定され利用される (たぶんREMOTE_ADDR変数に代入される)
- 評価されたアドレスはヘッダー内から削除される
RemoteIPInternalProxy
でALBのプライベートIPアドレスも設定した場合- ヘッダー内のアドレスを一番右から評価していき、ALBが
X-Forwarded-For
ヘッダーに追加したIPアドレス(今回だとyyy.yyy.yyy.yyy
)が、信頼出来る送信元として判定され利用される - ALBより前に
X-Forwarded-For
ヘッダーに追加されたIPアドレスは評価されず、ヘッダー内に残る
- ヘッダー内のアドレスを一番右から評価していき、ALBが
- Redmineでの処理
- Apacheから
X-Forwarded-For
ヘッダーを渡された場合- ヘッダー内の一番右のアドレスを送信元IPアドレスとして利用する
- Apacheから
X-Forwarded-For
ヘッダーを渡されない場合- Apacheと同じIPアドレスを送信元IPアドレスとして利用する (たぶんREMOTE_ADDR変数の値を使ってる)
- Apacheから
解決方法
ということで、ApacheでRequestHeader unset X-Forwarded-For
を設定し、Redmineに渡す前に必ずX-Forwarded-For
ヘッダーを削除することで、ApacheとRedmineで送信元IPアドレスが異なる状態になることを防げます。
おまけ
ちなみに、パターン3の設定で端末のIPアドレスを送信元IPアドレスに、パターン4の設定でプロキシサーバーのIPアドレスを送信元IPアドレスにすることが出来ます。
RemoteIPHeader X-Forwarded-For
RequestHeader unset X-Forwarded-For
RemoteIPHeader X-Forwarded-For
RequestHeader unset X-Forwarded-For
RemoteIPInternalProxy <ALBが配置されるサブネットのCIDR>
まとめ
今回の調査で、Apacheの設定によってX-Forwarded-For
ヘッダー内のどのIPアドレスが利用されるかが分かり、とても勉強になりました。
ただ、今回調査した内容はググってもあまり詳細な情報が出てこず、本当にこの理解で良いのだろうか?という引っかかりもあるため、時間が空いた時にまた調査出来ればと思います。
この情報が誰か助けになれば幸いです。