mod_rpaf よりも mod_extract_forwarded

リバースプロキシな環境では mod_rpaf 使ったりすることが多いと思いますが、バックエンドの apache でアクセス制限かける場合には、mod_extract_forwarded を使ったほうが良いよ、というお話。

バックエンドの apache 2.0 + mod_rpaf な環境で .htaccess によるアクセス制限をかけようとしても、接続元の IP アドレスではなく、pound の IP アドレスで制限がかかってしまう、という現象に悩まされました。で、ソースを眺めてみると mod_rpaf は ap_hook_post_read_request で実行されているのに対し、mod_access は ap_hook_access_checker で実行されています。おそらく、ap_hook_post_read_request よりも ap_hook_access_checker が先に実行されてしまい、mod_rpaf によるアドレス書き換え前にアクセス制限が実行されてしまう、ということなのでしょう、たぶん。(「モジュールの Apache 1.3 から Apache 2.0 への移植」 にモジュールのフックステージ一覧があるのですが、実行される順番は不明。apache のソース軽く眺めても、いくつかのファイルに分散しててよくわからんかった。)

で、mod_rpaf のソース書き換えて、フックする場所変えればいいんじゃね、と思いつつ試してみるも、思った通りの動作をせずに悩んでいたところ、弊社のサーバエンジニアの方が、mod_extract_forwarded を見つけてきてくれました。

これを試してみたところ、ちゃんと pound ではなく接続元の IP アドレスで制限がかかってくれました。

mod_extract_forwarded のソースを眺めてみると、ap_hook_post_read_request, ap_hook_translate_name, ap_hook_access_checker の3つのフックステージで何やらごにょごにょやっている様子。特に、mod_access の場合は、

ap_hook_access_checker(check_dir_access,NULL,NULL,APR_HOOK_MIDDLE);

と同じ ap_hook_access_checker の APR_HOOK_MIDDLE で実行されてるのに対し、mod_extract_forwarded では

ap_hook_access_checker(mef_access_check, NULL, NULL, APR_HOOK_FIRST);

といった感じで APR_HOOK_FIRST で実行されてたりするので、この辺がポイントなのかな、とあまりソース読めないなりに理解しました。

ためしたのは .htaccess だけですが、おそらく httpd.conf でアクセス制限かける場合でも同じなのではないかと。

また、 apache 2.2 では mod_access ではなく mod_authz_host ですが、フックしているところは mod_access と全く同じなので、たぶん 2.2 でも同じことでしょう。 2.2 ではそのままでは動かないそうです。 その他にも色々注意点があり大変参考になります。id:dayflower さん、ありがとうございます。