nginxやその他のリバースプロキシをフロントにおいて、バックエンドにApache httpdを置くという構成をとることがあります。
その場合に何も対処しないと、アクセスログやアプリが認識するクライアントIPアドレスがリバースプロキシのIPアドレスになってしまうので、モジュールを入れることでそれを対処していると思います。
バックエンドに置くApacheを2.4系でクライアントIPアドレスの変換を試していたのですが、どうもハマりどころが幾つかあったので、今回のエントリではそれを共有しておこうと思います。
クライアントIPアドレス変換モジュール
バックエンドのApacheで受け取るクライアントIPアドレスを、リバースプロキシのIPアドレスから実際のクライアントIPアドレスへと適切に変換するモジュールで代表的なものを以下に列挙します。
モジュール名 | Apache対応バージョン | 特徴 |
---|---|---|
mod_rpaf | 2.2.x | 2.4系に対応していない。IPv6回りで問題があってアクセス制御できなかったが今は改修したものがGitHubにあるらしい。 |
mod_extract_forwarded | 2.2.x | 2.4系に対応していない。普通にアクセス制御もできる。 |
mod_remoteip | 2.4.xの標準モジュール | 2.4系の標準モジュールなのでこれ使えば良い? |
上記を見ると、2.4系で使う上では選択肢などあってないようなもので、mod_remoteip使えば良いという話なのですが、mod_remoteipはできない事がありました。
mod_remoteipを使った場合ホスト名でアクセス制御できない
mod_remoteipを使った場合、allow
やdeny
、require
ディレクティブでホスト名によるアクセス制御ができませんでした。というわけで、実際にmod_access_compatやmod_authz_host、及び、mod_remoteipのコードを読んでみました。
すると、deny
やallow
ディレクティブではIPアドレスの場合、mod_remoteip
によって、リクエストヘッダから渡された本来のクライアントIPアドレスを入れておくr->useragent_addr
やr->useragent_ip
を使用してアクセス制御を行います。ここで、r->useragent_ip
等は、Apache2.4系から追加された構造体のメンバで、用途としてはリバースプロキシから渡された実際のクライアントIPアドレスを保存しておく場所です。
一方で、HOST名によるアクセス制御場合は、本来のクライアントIPアドレスではなく、ロードバランサやプロキシ等のコネクションのIPアドレス情報r->connection->client_addr
やr->connection->client_ip
、あるいは、r->connection->remote_host
からホスト名を取得しようとします。
つまり、allow
やdeny
、require
ディレクティブを使ったホスト名によるアクセス制御は、依然としてr->connection->client_ip
という、バックエンドに直接アクセスのあったIPアドレス、すなわち、リバースプロキシのIPアドレスから逆引きを行いホスト名を解決していたからでした。
うーん、これは困った。
mod_extract_forwardedを2.4系に対応させた
ということで、例のごとくこれらの処理をApache2.4系で実現できるモジュールを作りました。
matsumoto-r/mod_extract_forwarded_for_2.4 · GitHub
といってもmod_extract_forwardedは開発がかなり昔に止まっているようで、連絡をとっていいかも分からなかったので、mod_extract_forwardedのコードをベースに、Apache2.4系に対応させつつmod_remoteipできなかった事をできるように実装しました。
また、2.4系対応時に注意しなければならない点として、wordpressといったアプリケーションは管理画面でコメントやアクセスのあったIPアドレスをREMOTE_ADDR
という環境変数から取得する事が多いです。2.2系の時の仕様ではr->connection->client_ip
をREMOTE_ADDR
にセットするため、クライアントIPアドレス変換モジュールではr->connection->client_ip
をリバースプロキシのIPアドレスから一時的に本来のクライアントIPアドレスに書き換える必要がありました。
しかし、2.4系では実装がかわり、REMOTE_ADDR
にはr->useragent_ip
をセットするようになっています。つまり、mod_extract_forwardedを改修する際には、IPアドレスやホスト名でのアクセス制御が適切にできるようにr->connection->client_ip
あたりを対応するだけでなく、2.4系で新たに追加されたr->useragent_ip
にも本来のクライアントIPアドレスを入れておくようにしないと、アプリケーションからはリバースプロキシのIPアドレスとして見えたままになってしまいます。
まとめ
というわけで、長々とApacheにおけるクライアントIPアドレスの扱いや2.2系と2.4系での違いを述べましたが、Apache2.4用にそれらを考慮したクライアントIPアドレス変換モジュールを実装したので、お困りの際は是非お使いください。