2010年4月18日日曜日

ServersMan@VPSでのiptables設定

DTIの月額490円のVPSサービス『ServersMan@VPS』 に申し込んでみた。このVPSでiptablesを使うときのTIPSをメモががわりに残しておく。

(注意: 現在は state を使えるようになったので、こちらの新しい解説のほうがおすすめです)



このサービスは安価にroot権限つきサーバ(CentOS5系)を運用できるので、非常に魅力的なんだけど、ひとつ気になる制限がある。

それは iptables で state モジュールを利用できないことだ(2010/04/21追記: state モジュールを利用可能になったそうです。stateモジュールを利用できない前提で書かれた以下の内容は、現在では特に必要ない内容となっていますので、注意してください。2010/04/27追記: state の文法を受け付けるようになってはいますが、実際は動いていないように見えます。とりあえずは以下を参考に state に依存しないルールを設定しておくのが無難です。2010/05/15追記: 一旦reboot すれば state が正常に動作するようになります)。これは、「自分から出したDNS問い合わせの返答パケットを許可する」といった動的なルールを設定できないことを意味する(専用機ではこの機能を「ステートフルインスペクション」と呼んでいたりする)。近代的なファイアウォール機能で動的なルールを設定できないものはほとんどない。

state モジュールによる動的なフィルタリングは、自分がクライアントとして外部のサーバにアクセスするときのルールを明示的に設定する必要がないので大変便利だ。静的なルールでもある程度模倣可能だが、まったく同じ挙動を実現することはできない。「自分がクライアントになる」とは、例えばDNS問い合わせを出す場合などのことだ。このDNS問い合わせは当然ながら、「自身からDNSサーバへの問い合わせ」というアウトバウンドなパケットと、「DNSサーバから自身への返事」というインバウンドなパケットの2方向通信からなるが、動的なルールを利用できる場合には、外部へのDNS問い合わせを許可してさえいれば(普通、ローカルユーザを信頼するなら全てのアウトバウンドパケットを許可するだけですむし、実際そうしていることが多いはずだ)、インバウンドパケットは自動的に許可される。しかし、動的なルールを利用できない場合は想定される通信のインバウンドパケットを明示的に許可する必要がある。例えばこの場合、単純に考えると「送信元port番号が53のパケットはすべて許可する」といったルールで許可することになる。これは攻撃者が送信元portとして53を使えばファイアウォールが存在しないこととほぼ同じになってしまうことを意味する。

@serversman_vps によれば「(state モジュールの有効化について)検討する」とのことなので、しばらく待つというのも手だが、iptables をまったく設定しないのは気持ち悪いのでstateモジュールを使わないルールを書くときのポイントをふたつ挙げる。

1. なるべくクライアントにならない
自分がクライアントになる、ということは、相手のサービス提供ポートからのアクセスをINPUTチェインで無条件に許可しないといけない、ということを意味する。初めから、なるべくクライアントになるような運用は避ける。例えばVPSサーバから別の場所にsshしたくなる場合もあるかもしれないが、手元のマシンからsshすれば良いのであれば、VPSサーバから外部へのsshを禁止してもよいはずだ。

2. どうしてもクライアントとなる必要がある場合、可能な限り条件を厳しく設定する。
たとえばDNSの返答なら送信元portが53でかつ送信元IPアドレスが /etc/resolv.conf に書いてあるサーバからの場合のみ許可する、送信先portを net.ipv4.ip_local_port_range の範囲に限定する、といった条件を設定すれば、無条件に許可するよりもいくらか安全になる。

具体的な例は以下のとおり。上記のふたつのポイント以外にもいくつかのTIPSを含んでいる。

-A INPUT -p icmp -j ACCEPT
-A INPUT -s 127.0.0.0/8 -d 127.0.0.0/8 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 25 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 443 -j ACCEPT
# reverse
-A INPUT -s DNS.SRV.IP.ADDR -p udp -m udp --sport 53 --dport 32768:61000 -j ACCEPT
-A INPUT -p tcp -m tcp --sport 25 --dport 32768:61000 -j ACCEPT
-A INPUT -p tcp -m tcp --sport 80 --dport 32768:61000 -j ACCEPT
-A INPUT -p tcp -m tcp --sport 443 --dport 32768:61000 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 113 -j REJECT --reject-with tcp-reset
-A INPUT -j DROP

これは /etc/sysconfig/iptables の INPUT チェインに設定する部分を抜き出したものだ。VPSサーバが外部に提供するサービスとしてSSH, SMTP, HTTP, HTTPSを、VPSサーバが利用する(外部にクライアントとしてアクセスしにいく)サービスとしてDNS, SMTP, HTTP, HTTPS を、それぞれ想定した設定になっている。

1行目は icmp をすべて許可している。pingに反応するのを嫌がってicmpを許可したがらない人もいるが、icmp で伝達される情報には有用なものも多くあり、無条件に禁止することはあまりおすすめできない。どうせ攻撃者はIPアドレス帯をスキャンしていくのだから、pingに反応する/しないで大して安全になったりしない、というのもある。

2行目はローカル通信を全部許可している。

3行目〜6行目は提供サービスの許可だ。この例では外部から SSH, SMTP, HTTP, HTTPS への接続を許可している。

8行目〜11行目はVPSサーバがクライアントとして動作するために必要なルールだ。

8行目は DNS の返答パケットを許可している。DNS.SRV.IP.ADDR は自分が /etc/resolv.conf に書いている DNS サーバの IP アドレスだ。 -s で送信元IPアドレスを、--sportで送信元portを、--dportで宛先ポートを絞っている。

9, 10, 11 行目はそれぞれ SMTP, HTTP, HTTPS クライアントとして動作する場合を考慮したルールだ。HTTPはyumでしか使わないのであれば、-sオプションで近くの yum リポジトリミラーのIPアドレスに限定するのも効果的だ。

12行目は ident サービスに対するおまじないだ。SMTPサーバには接続をうけるときに送信元の ident サービスに問い合わせを出すタイプのプログラムが存在する。ここではすべてを拒否するルールとして13行目のDROPでパケットを破棄しているので、外部のSMTPサーバにアクセスする場合はこのルールをいれておかないと無駄なタイムアウト待ちが発生する場合がある(RESETが返るとidentにアクセスしにきている外部SMTPサーバはすぐ諦めるが、DROPするとタイムアウトまで待ってしまう)。"SMTP, ident" などのキーワードでググるといろいろ出てくると思う。

13行目はすでに書いたが、その他のすべてを拒否するルールだ。

あ、あと一番大事なことを忘れてた。ルールのロードは「iptables設定をリモートで行う危険性」について、充分理解してから実施しよう。
間違えてSSHのパケットをドロップするようなルールをロードすると、二度とSSHでサーバにログインできなくなる(当然だが)。手元のマシンなどで擬似環境を構築し、充分検証したうえでロードするように注意しよう。

0 件のコメント:

コメントを投稿