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

isdはじめに

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

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

続いてCentOS 7でもこの方法で、と試してみたのですが、CentOS 7のipsetは(2015年2月時点では)systemdに対応しておらず、OS起動時にipsetセットがロードされません。
このためCentOS 7での設定はあきらめていたのですが、先、Fedora Projectのipset RPMパッケージがsystemdに対応していることがわかり、試しにCentOS 7で適用してみると問題なく動作しているので、ここでまとめておきます。

※自己責任でお試しください。

isdipsetの設定

Fedora 21のipset RPMパッケージをダウンロードします。
‘ipset-service’ がipsetのsystemd向けのサービス管理パッケージです。

※Fedora 20, Fedora 22のipsetもsystemdに対応しているので、そのRPMパッケージでもよいと思います。

 # cd /usr/local/src/
 # wget http://ftp.riken.jp/Linux/fedora/releases/21/Everything/x86_64/os/Packages/i/ipset-6.21.1-4.fc21.x86_64.rpm
 # wget http://ftp.riken.jp/Linux/fedora/releases/21/Everything/x86_64/os/Packages/i/ipset-libs-6.21.1-4.fc21.x86_64.rpm
 # wget http://ftp.riken.jp/Linux/fedora/releases/21/Everything/x86_64/os/Packages/i/ipset-service-6.21.1-4.fc21.noarch.rpm

インストールします。

 # rpm -ivh ipset-6.21.1-4.fc21.x86_64.rpm \
      ipset-libs-6.21.1-4.fc21.x86_64.rpm \
      ipset-service-6.21.1-4.fc21.noarch.rpm

・ホワイトリストセットの作成
接続を許可したいネットワークのアドレスを保持するセット「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/ipset/ipset に保存し、次回ipsetが起動するときに自動的にWHITELISTセットをロードするようにします。

※起動停止スクリプト /usr/libexec/ipset/ipset.start-stop において、ipsetのデータファイルは /etc/sysconfig/ipset ではなく /etc/ipset/ipset と定義されていることに注意してください。

 # view /usr/libexec/ipset/ipset.start-stop

IPSET=ipset
IPSET_BIN=/usr/sbin/${IPSET}
IPSET_DATA=/etc/${IPSET}/${IPSET}
...

ipsetセットを保存し、内容を確認します。

 # ipset save > /etc/ipset/ipset

 # less /etc/ipset/ipset

create WHITELIST hash:net family inet hashsize 1024 maxelem 65536
add WHITELIST 103.8.88.0/21
add WHITELIST 120.72.64.0/20
add WHITELIST 59.190.0.0/16
...

・ipsetの起動
ステータスを確認します。

 # systemctl status ipset

ipset.service - IP sets for iptables
   Loaded: loaded (/usr/lib/systemd/system/ipset.service; disabled)
   Active: inactive (dead)

起動します。

 # systemctl start ipset
 # systemctl status ipset

ipset.service - IP sets for iptables
   Loaded: loaded (/usr/lib/systemd/system/ipset.service; disabled)
   Active: active (exited) since 土 2015-02-07 15:42:44 JST; 3s ago
  Process: 28826 ExecStart=/usr/libexec/ipset/ipset.start-stop start (code=exited, status=0/SUCCESS)
 Main PID: 28826 (code=exited, status=0/SUCCESS)

 2月 07 15:42:44 hostname systemd[1]: Starting IP sets for iptables...
 2月 07 15:42:44 hostname ipset.start-stop[28826]: Loaded with no configuration
 2月 07 15:42:44 hostname systemd[1]: Started IP sets for iptables.
Hint: Some lines were ellipsized, use -l to show in full.

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

 # systemctl enable ipset

ln -s '/usr/lib/systemd/system/ipset.service' '/etc/systemd/system/basic.target.wants/ipset.service'

 # systemctl status ipset

ipset.service - IP sets for iptables
   Loaded: loaded (/usr/lib/systemd/system/ipset.service; enabled)
   Active: active (exited) since 土 2015-02-07 15:42:44 JST; 57s ago
 Main PID: 28826 (code=exited, status=0/SUCCESS)

 2月 07 15:42:44 hostname systemd[1]: Starting IP sets for iptables...
 2月 07 15:42:44 hostname ipset.start-stop[28826]: Loaded with no configuration
 2月 07 15:42:44 hostname systemd[1]: Started IP sets for iptables.
Hint: Some lines were ellipsized, use -l to show in full.

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ルールを保存するのをお忘れなく。

 # iptables-save > /etc/sysconfig/iptables

 # 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まとめ

CentOS 7で、国別の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 6)
https://inaba-serverdesign.jp/blog/20150209/ipset_iptables_country_centos6.html

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