ipsetとiptablesでSSHを日本国内からの接続に限定する (CentOS 6)

isdはじめに

サーバー構築・運用において、固定IPアドレスを持っていないユーザーからのSSH接続を許可する必要があるために、SSHのアクセス元IPアドレスを限定できないケースはわりとよくあると思います。

公開鍵認証を必須とする、ポート番号を変更する、ブルートフォース攻撃対策としてFail2BanやDenyHostsでBanする、などの方法でセキュリティ強化はできますが、そもそも不正アクセスのチャレンジ自体をできるだけ少なくしたいですね。
自宅の鍵穴を知らない人にガチャガチャされるのは、安全だとわかっていても気持ち悪いものです。

以前、国別のIPアドレスリストを使って、特定の国からのWebアクセスをブロックする対処を行ったことがありました。

・Nginxで海外からのアクセスを拒否する
https://inaba-serverdesign.jp/blog/20140616/nginx_deny_ipaddress.html

そこで、国別のIPアドレスリストを利用して、iptablesでSSHを日本国内からの接続に限定すればよいのでは、と考えて試してみました。
ところが、単純にIPアドレスの分だけフィルタリングルールを追加すると、、、

iptables -A OUTPUT -m state --state NEW -s <IPアドレス> -p tcp --dport 22 -j ACCEPT

それだけで2,000件以上のフィルタリングルール追加処理が発生します。
iptablesのフィルタリングルールを追加する処理は少し重いようで、すべてのiptablesエントリーを登録するまでに数十秒かかるようになってしまいました。
iptablesルールを適用する間、ルールの順序にもよりますが、一時的にサーバーへアクセスできなくなってしまいます。
また、iptablesのフィルタリングルールには上限があるようで、「いくつかの国からのSSHアクセスを拒否する」というような設定を試してみたところ、ルール数が多すぎて、iptalbesのフィルタリングルール追加が途中で止まってしまいました。

ということで困っていたのですが、こういう場合は「ipsetを利用してIPアドレスの集合として管理し、iptablesで参照する」という方法があることがわかりました。

前置きが長くなりましたが、以下、CentOS 6で「ipsetとiptablesでSSHを日本国内からの接続に限定する」方法をまとめます。

ipsetの詳しい説明は、以下の記事がとてもわかりやすいのでそちらを参照してください。

・ipsetを使ってスマートにiptablesを設定する
http://equj65.net/tech/ipset/

※CentOS 7での設定方法は少し違うので、別の記事にまとめました。

・ipsetとiptablesでSSHを日本国内からの接続に限定する (CentOS 7)
https://inaba-serverdesign.jp/blog/20150209/ipset_iptables_country_centos7.html

isdipsetの設定

・ipsetのインストール

 # yum install ipset

インストール:
  ipset.x86_64 0:6.11-3.el6

依存性関連をインストールしました:

・ホワイトリストセットの作成
接続を許可したいネットワークのアドレスを保持するセット「WHITELIST」を作成し、国別コードリストからWHITELISTのエントリーを登録します。

定期的に最新の国別コードリストの情報を反映できるよう、スクリプトを用意しました。


 # vi mk_ipwhitelist.sh

#!/bin/bash

# 国別コードリストをダウンロード
cd /root/bin/
if [ -s cidr.txt ]; then
	mv cidr.txt cidr.txt.old
fi

wget http://nami.jp/ipv4bycc/cidr.txt.gz
gunzip cidr.txt.gz

# ホワイトリストセットを作成
ipset create -exist WHITELIST hash:net

# ホワイトリストセットに日本のIPアドレスを登録
sed -n 's/^JP\t//p' cidr.txt | while read ADDRESS; do
    ipset add WHITELIST $ADDRESS
done

スクリプトを実行します。

 # chmod 700 ./mk_ipwhitelist.sh
 # ./mk_ipwhitelist.sh

WHITELISTを確認します。

 # ipset list WHITELIST | less

Name: WHITELIST
Type: hash:net
Header: family inet hashsize 1024 maxelem 65536
Size in memory: 48176
References: 0
Members:
112.138.0.0/15
138.212.0.0/16
192.42.104.0/22
202.177.48.0/20
...

・ipsetセットの保存
ipsetはサービスを再起動すると削除されるため、/etc/sysconfig/ipset に保存し、次回ipsetが起動するときに自動的にWHITELISTセットをロードするようにします。

 # /etc/init.d/ipset save

  確認します。

 # less /etc/sysconfig/ipset

create WHITELIST hash:net family inet hashsize 1024 maxelem 65536
add WHITELIST 112.138.0.0/15
add WHITELIST 138.212.0.0/16
add WHITELIST 192.42.104.0/22
add WHITELIST 202.177.48.0/20
...

・自動起動設定
OS起動時にipsetセットをロードするよう自動起動設定を行います。

念のため、ipset起動スクリプトを確認します。
→ chkconfig: 2345 07 93 となっているので、iptablesより前に起動し、iptablesの後で終了することがわかります。

 # view /etc/init.d/ipset

...
# chkconfig: 2345 07 93
# description:  Starts, stops and saves IP sets
...

 # view /etc/init.d/iptables

...
# chkconfig: 2345 08 92
# description:  Starts, stops and saves iptables firewall
...

自動起動設定を行います。

 # chkconfig ipset on
 # chkconfig --list ipset

ipset           0:off   1:off   2:on    3:on    4:on    5:on    6:off

isdiptablesの設定

iptablesコマンドでオプション -m set –match-set <セット名=WHITELIST> src を指定して、ホワイトリストのIPアドレスからのみSSH接続を許可します。
(デフォルトポリシーがDROP、SSHポートはTCP/22を想定。)

 # iptables -I INPUT -m state --state NEW -p tcp --dport 22 -m set --match-set WHITELIST src -j ACCEPT

これで、iptables 1行のエントリーで、大量のIPアドレスからのアクセス許可ルールを表現できました。
iptablesコマンドでは source 0.0.0.0/0 と出力されますが、ホワイトリストにマッチしないIPアドレスからはSSHポートにアクセスできません。

 # iptables -L -n

Chain INPUT (policy DROP)
target     prot opt source               destination
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0           state NEW tcp dpt:22 match-set WHITELIST src

ルールを追加したので、iptablesルールを保存するのをお忘れなく。

 # /etc/init.d/iptables save

 # less /etc/sysconfig/iptables

*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT DROP [16000:1808000]
-A INPUT -p tcp -m state --state NEW -m tcp --dport 10022 -m set --match-set WHITELIST src -j ACCEPT
...

isd動作確認

以下を確認します。

  • 自分のPCやサーバーからSSHログインできる。
  • 海外のサーバー環境からSSHログインできない。

また、可能であれば、OSを再起動してipsetルールやiptablesルールが正しくロードされることも確認するとよいでしょう。

「海外のサーバー環境」は、例えばAWS EC2のサーバーを使うとよいと思います。
なお、EC2サーバーのIPアドレスは、東京リージョンのサーバーでも国名コードとしては’US’です。
つまり、この国名コードは、必ずしも該当のIPアドレスを使用するサーバーの地理的な位置を表すとは限らないことに注意しましょう。

isdまとめ

国別のIPアドレスリストを利用して、ipsetとiptablesでSSHを日本国内からの接続に限定する設定方法をまとめました。

この方法で、FTP等ほかのポートのアクセス制限を行うこともできますし、ipsetでブラックリストのセットを作成しDROPルールを登録することで、特定の国からのアクセスを防ぐこともできます。

 # iptables -I INPUT -m state --state NEW -p tcp --dport 22 -m set --match-set BLACKLIST src -j DROP

iptablesで取り扱うIPアドレスが多い場合は、ipsetを使いましょう。

(関連記事)
・ipsetとiptablesでSSHを日本国内からの接続に限定する (CentOS 7)
https://inaba-serverdesign.jp/blog/20150209/ipset_iptables_country_centos7.html

・Nginxで海外からのアクセスを拒否する
https://inaba-serverdesign.jp/blog/20140616/nginx_deny_ipaddress.html