[Apache] 非VPCのELBでX-Forwarded-Forを利用したアクセス制限

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

こんにちは植木和樹です。本日は過去にこのサイトでも取り上げられている内容を組み合わせ、Apacheのアクセス制限設定しました。

解決したい問題

非VPC環境で、ELB配下のWebサーバがインターネットからのDoS攻撃にさらされた場合に、特定のIPアドレスからのアクセスを拒否(403)します。

VPC環境であればNetworkACLやSecurityGroupで制限をかけることができますが、非VPCではELBへのアクセスを制限することができません。この場合httpdレベルで制限する必要があります。

参考にした記事

解決方法

ELBにアクセスしてくる端末のIPアドレスはX-Forwarded-Forリクエストヘッダーに格納されています。X-Forwarded-Forが特定のIPアドレスの場合にアクセスを拒否(DENY)します。なおhttpdサーバにはApache httpd(2.2)を使用しています。

AmazonLinux(というか一般的にrpmでインストールしたapache)の場合、DocumentRootが /var/www/html になっていますので、Directoryコンテキストでアクセス制限の設定を行います。下記に設定例を示します。非VPCなのでELBを介さず直接PublicDNSへアクセスされることも想定しています。

Order alllow,denyは、まずすべてのアクセスを許可(Allow from all)してから、条件に該当するアクセスは拒否する(Deny from env=deny_ip)という動きになります。当初「DENYして、残りはALLOW」のつもりでOrder deny,allowしたら、うまくいかずにハマりました。【参考】Apache モジュール mod_authz_host

httpd.conf

$ sudo vi /etc/httpd/conf/httpd.conf
<Directory "/var/www/html">
    Options Indexes FollowSymLinks
    AllowOverride None
    SetEnvIf X-Forwarded-For "11\.22\.33\.44" deny_ip
    SetEnvIf REMOTE_ADDR "11\.22\.33\.44" deny_ip
    Order allow,deny
    Allow from all
    Deny from env=deny_ip
</Directory>

設定したら設定ファイルを再読み込みします。

$ sudo service httpd reload

DENYしたログは出力しない

URLに非常に長い文字列を指定してGETされた場合、大量のアクセスログに記録されてしまいます。アクセスを拒否したIPアドレスについては、ログ出力も止めてしまいましょう。

SetEnvIf X-Forwarded-For "11\.22\.33\.44" nolog
SetEnvIf REMOTE_ADDR "11\.22\.33\.44" nolog
CustomLog logs/access_log combined env=!nolog

結論

本来は環境をVPCに移行してNetworkACL等で制限するのが良いのでしょうが、いろいろな事情でVPCへ移行できないサーバもあります。Apacheを使っているのであれば数行設定を追加して、設定を再読み込みするだけでサービスを止めずに対応することが可能です。