彷徨えるフジワラ

年がら年中さまよってます

IP Filter で ssh 以外の接続を禁止

新しいサーバは当面、SSH 以外の接続要求は全て拒否する方向に振っておいて、必要になったら都度穴を開けるということに。

ちなみに、デフォルトで IP Filter が無効で、仮に有効にしたとしても設定記述が空=無効と同じ状態、ってのは、今時のセキュリティ設定としてどうなのよ? > OpenSolaris

サーバ利用が想定ターゲットなテキストインストーラでの導入なら兎も角、デスクトップ利用が想定ターゲットである GUI インストーラの場合、最近の Linuxディストリビューションのように「SSH のみ受け付ける」ぐらいの設定は有効になっていた方が良い気がするんだけどなぁ。

というわけで、とりあえずは IP Filter を有効にしておく必要が。

$ svcs svc:/network/ipfilter:default
STATE          STIME    FMRI
disabled       16:44:47 svc:/network/ipfilter:default
$ svcadm enable network/ipfilter
$ svcs svc:/network/ipfilter:default
STATE          STIME    FMRI
online         17:24:42 svc:/network/ipfilter:default
$

まずは設定の第一歩として、別ホストへの送信の全許可と、別ホストからの受信の全遮断を /etc/ipf/ipf.conf に記述。

pass out all
block in all

当面の運用では、サーバにはルーティングをさせない=パケット中継を考えなくて良いことから、宛先アドレス(to 記述)は指定しないことに。アドレス変更の際の修正範囲を狭めたい、という理由がメインなのだけど(w)。

但し、この単純な遮断設定では、別ホストからの応答パケットも遮断されてしまうことから、セキュリティ云々どころではなく、外部との通信が一切出来なくなってしまう羽目に。

試しに、パケットの破棄をログ記録する設定にして:

pass out all
block in log all

ルールを差し替えてから、ipmon でログ記録を監視しつつ、他のホストへ telnet(192.168.0.129 → 192.168.0.2) してみると:

$ ipmon
09/10/2010 17:40:29.150311 rge0 @0:1 b 192.168.0.2,23 \
    -> 192.168.0.129,38869 PR tcp len 20 52 -AS IN
....

という具合にパケットが破棄されてしまう("b" はパケットのブロック、"IN" は受信パケットを表す)。

さて、当然このままでは使い物にならないので、応答パケットを受理できるように設定を変更。

「応答受理」に関する変更なのだけど、"in" の設定は追加せずに、"out" の設定を以下のように書き換える。

pass out all keep state
block in all

"keep state" 指定は:

このルールによってパケット授受の可否が決定された場合、それ以後の、その通信と同じアソシエーションを持つパケットに関しては、その際の可否が採用され、ルールチェックは省略される

という働きがある。つまり上記の設定の場合、自ホスト契機で開始された通信に関しては、以後のパケット授受は全て許可される、という按配。

状態判定とルール検証の順序に関しては、SUN のドキュメント中に掲載されているダイアグラムがわかりやすい。

アソシエーション毎に状態管理が必要+状態管理テーブルによる合致判定が生じるわけなので、決して「オーバヘッド無し」というわけではないけれど、まぁ、これぐらいは良いでしょう。HPC 系でカーネルモジュール開発の仕事をやっているせいか、キャッシュ引き当てすらオーバヘッドが気になってしまう体質に.... orz

クライアントとして稼動=自ホスト契機の通信の許可で十分なら、以上の設定で十分なのだけど、サーバとして振舞う場合、他ホスト契機の接続要求を受け付ける必要がある。

サーバとしてクライアントからの通信を受理する場合:

  • 接続要求=SYN フラグ付きのパケットを受理する
  • 受理した接続要求と同じアソシエーションのパケットは受理し続ける

とすれば良いわけなので、ここでも "keep state" の出番となる。

SUN のドキュメントによると、ルール記述は最後に成立したものが採用されるらしいので、接続要求パケット受理のルールは後ろに書く必要があることから、例えば SSH サーバ(ポート番号 22)として要求を受理するのであれば:

pass out all keep state
block in all
pass in proto tcp to port = 22 flags S/SA keep state

といったように、受信パケットを全ブロックするルール記述の後ろに追加する。

ルール検証の効率とかを考えると、quick とか head/group の指定や、種別(tcp/udp/icmp)毎での記述分離等が必要なのだが、まぁ、解説記事でも無いので、ここでの説明は省略(笑)。

Symantec で公開している解説(英語)は、いきなり完成形を提示するのではなく、順序立てて設定を組み上げているので、結構わかりやすくてお勧め。

ちなみに、ルールの差し替え(= ルール記述変更の反映)の際には、既存ルールの破棄を伴う -Fa オプション指定を忘れないようにする必要がある(以下の例は、全ルールの総入れ替え)。

$ ipf -Fa -f /etc/ipf/ipf.conf

これを忘れると、後から指定したルールが順次蓄積されてしまうことで、想定外のパケット受理/破棄が生じてしまう罠が。っていうか、僕は一度ひっかかりました .... orz

運用中の差し替えの場合、遮断設定が機能しない途中状態が生じてしまうため、「総入れ替え」が危険なケースもある点に注意が必要。