nginxでIPフィルタを設定した上で無許可IPにはステータスコードを返さない

こんにちは。構築担当の下地です。

現在稼動しているnginxのサーバで、お客様より

「IPフィルタをかけつつ無許可IPからのアクセスにはステータスコードを返さないようにしたい」

というご要望を頂きました。

この設定についてnginxで色々試した話をします。

nginxのステータスコード444について

nginxでは独自のステータスコードとして「444」があります。

444は nginx にコネクションを閉じさせる特別なコードで、

return 444;

が評価されるとNGINXは何のレスポンスも返さずにコネクションを閉じます。

試しに444を設定したnginxサーバにブラウザからアクセスすると、

20180910_pageerror.jpg

このような表示になりました。

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モジュールなどは今回初めて触ったので、依頼作業は余り知らない分野を触るいいきっかけになります。

今回もお読み頂きありがとうございました。

返信を残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA