shorewallのルールにipsetのセットを指定する

うちのサーバはiptablesの管理にshorewallというのを使っているのですが、そこにipsetというやつを連携させて、接続を許可するIPアドレスの一覧の管理を外出しにした話です。

簡単に説明しておくと、iptablesってのはTCP/IPレベルの通信を制御するやつで、Linuxのカーネルに組み込まれていて、これを利用するとルータ兼ファイアウォールを構築したり、単体でセキュリティレベルを上げれたりするやつです。

ipsetってのは、これまたLinuxのカーネルに組み込まれている奴で、iptablesのルールにマッチするIPアドレスなどの一覧を別管理にすることができるやつです。IPアドレス一覧だけを管理する奴って思えばいいですね。

で、shorewallってのはiptablesのルールをもう少し噛み砕いた表現で記述できるやつで、都度コンパイルしてiptablesに読み込ませる感じです。

というわけで、SSHサービスへ接続できるIPアドレスを動的に変更したい場合は、iptablesとshorewallだけだと変更のたびにコンパイルしなければならないのですが、ipsetを連携させるとコンパイル不要で接続可能なIPアドレスを変更できるようになるのです。

では早速、ipsetをインストール。

# yum install ipset
Loaded plugins: fastestmirror, security
Setting up Install Process
Loading mirror speeds from cached hostfile
 * base: ftp.tsukuba.wide.ad.jp
 * epel: ftp.kddilabs.jp
 * extras: ftp.tsukuba.wide.ad.jp
 * updates: ftp.tsukuba.wide.ad.jp
Resolving Dependencies
--> Running transaction check
---> Package ipset.x86_64 0:6.11-4.el6 will be installed
--> Processing Dependency: libmnl.so.0(LIBMNL_1.0)(64bit) for package: ipset-6.11-4.el6.x86_64
--> Processing Dependency: libmnl.so.0()(64bit) for package: ipset-6.11-4.el6.x86_64
--> Running transaction check
---> Package libmnl.x86_64 0:1.0.2-3.el6 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

====================================================================================================
 Package               Arch                  Version                      Repository           Size
====================================================================================================
Installing:
 ipset                 x86_64                6.11-4.el6                   base                 63 k
Installing for dependencies:
 libmnl                x86_64                1.0.2-3.el6                  base                 21 k

Transaction Summary
====================================================================================================
Install       2 Package(s)

Total download size: 84 k
Installed size: 210 k
Is this ok [y/N]: y
Downloading Packages:
(1/2): ipset-6.11-4.el6.x86_64.rpm                                           |  63 kB     00:00     
(2/2): libmnl-1.0.2-3.el6.x86_64.rpm                                         |  21 kB     00:00     
----------------------------------------------------------------------------------------------------
Total                                                               396 kB/s |  84 kB     00:00     
Running rpm_check_debug
Running Transaction Test
Transaction Test Succeeded
Running Transaction
  Installing : libmnl-1.0.2-3.el6.x86_64                                                        1/2 
  Installing : ipset-6.11-4.el6.x86_64                                                          2/2 
  Verifying  : libmnl-1.0.2-3.el6.x86_64                                                        1/2 
  Verifying  : ipset-6.11-4.el6.x86_64                                                          2/2 

Installed:
  ipset.x86_64 0:6.11-4.el6                                                                         

Dependency Installed:
  libmnl.x86_64 0:1.0.2-3.el6                                                                       

Complete!

次にipsetを作る。

# ipset create sshok hash:ip timeout 3600

sshokという名前で、IPアドレスのハッシュテーブルで、タイムアウト3600秒のものを作りました。詳しくはman ipsetでも見てね。

出来上がったセットを確認。

# ipset list
Name: sshok
Type: hash:ip
Header: family inet hashsize 1024 maxelem 65536 timeout 3600 
Size in memory: 16504
References: 0
Members:

ちゃんと出来ています。メンバーなし。ハッシュの最大長さが65536でメモリサイズが16504。ビットマップにしたら少しは少なくなるかな。そこまでメモリにシビアではないのでこのまま行きます。

セットにIPアドレスを追加。

# ipset add sshok 202.231.70.100

追加しました。

そして確認。

# ipset list
Name: sshok
Type: hash:ip
Header: family inet hashsize 1024 maxelem 65536 timeout 3600 
Size in memory: 16568
References: 0
Members:
202.231.70.100 timeout 3560

timeoutが3560になっているので追加してから40秒経過しているんですね。消費メモリが64増えています。

これでipsetの準備は完了。

あとはshorewallに設定するだけ。こんな感じ。

# grep sshok /etc/shorewall/rules 
SSH(ACCEPT:info)	net:+sshok	$FW

ドキュメントはちゃんと読んでないけど、「+セット名」でipsetのセットを指定できるらしいです。

makeした後はこんなルールができていました。

# iptables -L -n -v | grep sshok
    0     0 ~log0      tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           [goto] tcp dpt:22 match-set sshok src /* SSH */ 

宛先ポートが22でソースのIPアドレスがsshokのセットにマッチしたら~log0に飛ぶぞ、と。

あとはIPのセットを何かしらの方法でメンテナンスすればいいわけです。何でしましょうね。PHPからsudoでipsetを呼ぶ?CGI?何にせよプログラムが必要になるのかね。なんとかならないかな。