こんにちは。構築担当の下地です。
現在稼動しているnginxのサーバで、お客様より
「IPフィルタをかけつつ無許可IPからのアクセスにはステータスコードを返さないようにしたい」
というご要望を頂きました。
この設定についてnginxで色々試した話をします。
nginxのステータスコード444について
nginxでは独自のステータスコードとして「444」があります。
444は nginx にコネクションを閉じさせる特別なコードで、
return 444;
が評価されるとNGINXは何のレスポンスも返さずにコネクションを閉じます。
試しに444を設定したnginxサーバにブラウザからアクセスすると、
このような表示になりました。
allowとdenyを使うIP制限ですと403 Forbiddenが返りますが、444にするとステータスコード自体が返りません。
geoモジュールについて
nginxでは、geoモジュールを使用することで、クライアントのIPアドレスに応じた値を持つ変数を作成します。
文章だけでは分かりにくいので、設定例を記載すると以下のようになります。
http {
...
geo $geo {
192.168.10.100 NG;
default OK;
}
...
server {
listen 80;
server_name denet.co.jp;
...
if ($geo = 'NG') {
return 403;
}
...
}
...
}
...
このように書くと、「192.168.10.100」からアクセスがあると、変数geoにNGが代入されます。
するとserverコンテキスト内のif文でgeoに格納されている値が判定されて、NGの場合は403が返されます。
つまりこれはブラックリスト形式のIPフィルタとして機能します。
なお、geoモジュールはhttpコンテキスト内でしか使用できないのでご注意下さい。
シンプルに組み合わせて使う
この444ステータスコードとgeoモジュールを組み合わせることで、IPフィルタリングと無許可IPに対するステータスコード無応答の設定が行えます。
検証としてnginxで簡単なリバースプロキシを設定してみましょう。
自分のIPから対象サーバにアクセスするとyahoo.co.jpにリクエストが送られるようにします。
合わせて無応答版のIPフィルタを設定し、自分以外のIPからアクセスが来るとステータスコードを返さず接続を切るようにします。
[root@testserver ~]# cat /etc/nginx/conf.d/reverse_proxy.conf
geo $access_filter {
default NG;
xxx.xxx.xxx.xxx OK;
}
server {
listen 80;
server_name denet.sample;
location / {
if ($access_filter = "NG")
{
return 444;
}
proxy_pass http://yahoo.co.jp;
}
}
[root@testserver ~]#
この設定で$access_filterの「xxx.xxx.xxx.xxx」部分に自分のIPを入れます。
すると指定したIPからアクセスがあった場合のみ変数access_filterにOKが代入されて、serverコンテキストで評価されます。
値がOKだとif文がスルーされて、yahoo.co.jpにプロキシします。
指定IP以外だとNGが入るため、ifに引っかかり444が返されます。
また、この設定だとホワイトリストとして機能します。
許可IPリストを外だしする
先ほどの書き方でも設定は問題ありませんが、許可したいIPが数十~数百個ある場合、全て同じファイルに書くと可読性が悪くなってしまいます。
そこで許可IPリスト部分を外だしファイルにしてみます。
まず先ほどと同じ設定ファイルreverse_proxy.confにincludeを使って読み込むファイルを指定します。
[root@testserver ~]# cat /etc/nginx/conf.d/reverse_proxy.conf
geo $access_filter {
default NG;
include /etc/nginx/extra/ip_allow_list.conf;
}
server {
listen 80;
server_name denet.sample;
location / {
if ($access_filter = "NG")
{
return 444;
}
proxy_pass http://yahoo.co.jp;
}
}
[root@testserver ~]#
そして外だしファイルを新規作成して、許可したいIPを列記します。
[root@testserver ~]# cat /etc/nginx/extra/ip_allow_list.conf
111.111.111.111 OK;
222.222.222.222 OK;
333.333.333.333 OK;
[root@testserver ~]#
こんな感じにすると、reverse_proxy.confは可読性が保てますし、将来許可したいIPが増えた場合もip_allow_list.confに追記するだけで済みます。
まとめ
普段IPフィルタを設定する場合は、クラウド側のサービス(awsならセキュリティグループなど)で行うことが多いですが、今回は事情がありnginx側でフィルタ設定を行いました。
geoモジュールなどは今回初めて触ったので、依頼作業は余り知らない分野を触るいいきっかけになります。
今回もお読み頂きありがとうございました。