クライアント用とで使っているWindowsですらWindowsファイアウォールでパケットフィルタしている時代です。Linuxサーバがパケットフィルタしていないという事実が許されるはずは無いと言うことで、きっちりとiptablesによるファイアウォールの設定をします。
この記事で対象としている環境は下記のとおりです。NETGEARのGS116E、GS108Eと連携したタグVLANを利用していますが、タグVLANが無く、物理的にeth1がある場合には、eth0.2をeth1と読み替えてください。
eth0 物理的に存在するM/BオンボードNIC。ローカルセグメント用 eth0.2 eth0上のタグVLAN用インターフェース。DMZセグメント用 br0 172.20.1.30/24 br0.2 172.20.2.30 lo ループバック
iptablesの設定内容を事前確認
iptablesコマンドの設定中にいちいちsudoするのは面倒なので、ここでは例外的にrootになって作業します。
iptablesのルールセットの自動読み込みに必要なパッケージの導入
sudo apt-get install iptables-persistent
事前に既に設定されているルールセットを確認しておきます。もしも設定されていたとしても削除しますが・・・
iptables -L Chain INPUT (policy ACCEPT) target prot opt source destination Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination
何もルールが設定されていませんね。各々のChainが使われるタイミングは下記の通り。
- INPUT ・・・ このサーバへ入ってくる時
- OUTPUT ・・・ このサーバから出ていく時
- FORWARD ・・・ このサーバの中には入らず、中継していく時。(Linuxでルータを作る時や、KVMのブリッジ等で関係する)
対策前サーバに対しての事前セキュリティ評価試験
※この事前セキュリティ評価試験はやるべきですが、環境が無い場合には無理して実施する必要はありません。
対策実施前のサーバの状態を把握しておかないといけないので、nmapによるポートスキャンを行っておきます。こういう時にLinuxだけが入ったノートPC等があると楽ですね。さっとセキュリティ評価用のノートPCを出すような人がいたら憧れます。
# DMZ側のポートスキャン結果 nmap -P0 -p 0-65535 172.20.2.30 Starting Nmap 6.00 ( http://nmap.org ) at 2013-09-18 17:00 JST Nmap scan report for 172.20.2.30 Host is up (0.00014s latency). Not shown: 65531 closed ports PORT STATE SERVICE 22/tcp open ssh 80/tcp open http 139/tcp open netbios-ssn 445/tcp open microsoft-ds 5916/tcp open unknown MAC Address: D4:3D:7E:9D:00:01 (Unknown) Nmap done: 1 IP address (1 host up) scanned in 1.00 seconds
#LAN側のポートスキャン結果 nmap -P0 -p 0-65535 172.20.1.30 Starting Nmap 6.00 ( http://nmap.org ) at 2013-09-18 17:28 JST Nmap scan report for 172.20.1.30 Host is up (0.00012s latency). Not shown: 65531 closed ports PORT STATE SERVICE 22/tcp open ssh 80/tcp open http 139/tcp open netbios-ssn 445/tcp open microsoft-ds 5916/tcp open unknown MAC Address: D4:3D:7E:9D:01:01 (Unknown) Nmap done: 1 IP address (1 host up) scanned in 0.81 seconds
ポートの22(ssh)、80(http)、139、445(samba)が空いているようです。この評価は同一LAN内から行っている為、DMZセグメントからも同様に評価をしておくべきです。
実際にiptablesによるファイアウォールを設定する
ここからが実際の設定作業です。今回は単純なサーバではなく、ブリッジインターフェースを用いたKVMサーバを動作させるサーバのルール設定なので、FOWARDチェインがキモとなります。
#kvmサーバでのiptablesの設定 #!/bin/sh ## 変数の定義 # ローカルネットワーク(安全なLANセグメント) LOCAL_ETH='br0' # LOCAL_NETWORK='172.20.1.128/25' LOCAL_MY_IP='172.20.1.30/32' # DMZネットワーク(KVMサーバ公開用のセグメント) KVM_DMZ_ETH='br0.2' DMZ_NETWORK='172.20.2.0/24' # iptablesのプログラム IPTABLES='/sbin/iptables' # ルールの設定中だけは全部許可 # 本当は、管理用PCからのSSHのみアクセスするフィルタを暫定的に入れるのが望ましいのですが、 # iptablesの設定がすべて完了してから公開セグメントに持っていくことを想定している事と、 # 単純にコピペでスクリプトを流し込むので、リスクは極小と判断しています。 $IPTABLES -P INPUT ACCEPT $IPTABLES -P OUTPUT ACCEPT # ルールの初期化 $IPTABLES -F # ローカルループバックを許可 $IPTABLES -A INPUT -i lo -j ACCEPT $IPTABLES -A OUTPUT -o lo -j ACCEPT # 明らかにおかしいパケットは拒否 $IPTABLES -A INPUT -p tcp -m state --state INVALID -j DROP $IPTABLES -A OUTPUT -p tcp -m state --state INVALID -j DROP $IPTABLES -A FORWARD -p tcp -m state --state INVALID -j DROP # ホストのIP設定されていないインターフェース宛は無条件で拒否 $IPTABLES -A INPUT -i eth0 -j DROP $IPTABLES -A INPUT -i $KVM_DMZ_ETH -j DROP $IPTABLES -A OUTPUT -o eth0 -j DROP $IPTABLES -A OUTPUT -o $KVM_DMZ_ETH -j DROP # サーバとして提供しているサービスへのアクセス許可 $IPTABLES -N LOCAL_SERVICE_IN $IPTABLES -A LOCAL_SERVICE_IN -p udp --sport 1024:65535 --dport 137 -j ACCEPT $IPTABLES -A LOCAL_SERVICE_IN -p udp --sport 1024:65535 --dport 139 -j ACCEPT $IPTABLES -A LOCAL_SERVICE_IN -p tcp --sport 1024:65535 --dport 22 -j ACCEPT $IPTABLES -A LOCAL_SERVICE_IN -p tcp --sport 1024:65535 --dport 80 -j ACCEPT $IPTABLES -A LOCAL_SERVICE_IN -p tcp --sport 1024:65535 --dport 123 -j ACCEPT $IPTABLES -A LOCAL_SERVICE_IN -p tcp --sport 1024:65535 --dport 139 -j ACCEPT $IPTABLES -A LOCAL_SERVICE_IN -p tcp --sport 1024:65535 --dport 445 -j ACCEPT $IPTABLES -A LOCAL_SERVICE_IN -p tcp --sport 1024:65535 --dport 5900:5950 -j ACCEPT $IPTABLES -A LOCAL_SERVICE_IN -j DROP $IPTABLES -N LOCAL_SERVICE_OUT $IPTABLES -A LOCAL_SERVICE_OUT -p udp --sport 137 --dport 1024:65535 -j ACCEPT $IPTABLES -A LOCAL_SERVICE_OUT -p udp --sport 139 --dport 1024:65535 -j ACCEPT $IPTABLES -A LOCAL_SERVICE_OUT -p tcp --sport 22 --dport 1024:65535 -j ACCEPT $IPTABLES -A LOCAL_SERVICE_OUT -p tcp --sport 80 --dport 1024:65535 -j ACCEPT $IPTABLES -A LOCAL_SERVICE_OUT -p tcp --sport 123 --dport 1024:65535 -j ACCEPT $IPTABLES -A LOCAL_SERVICE_OUT -p tcp --sport 139 --dport 1024:65535 -j ACCEPT $IPTABLES -A LOCAL_SERVICE_OUT -p tcp --sport 445 --dport 1024:65535 -j ACCEPT $IPTABLES -A LOCAL_SERVICE_OUT -p tcp --sport 5900:5950 --dport 1024:65535 -j ACCEPT $IPTABLES -A INPUT -i $LOCAL_ETH -s $LOCAL_NETWORK -j LOCAL_SERVICE_IN $IPTABLES -A OUTPUT -o $LOCAL_ETH -d $LOCAL_NETWORK -j LOCAL_SERVICE_OUT # サーバから外部サーバへのアクセス許可(パッケージアップデート等の為) $IPTABLES -N CLIENT_RULES_IN $IPTABLES -A CLIENT_RULES_IN -p udp --sport 53 --dport 1024:65535 -j ACCEPT $IPTABLES -A CLIENT_RULES_IN -p tcp --sport 22 --dport 1024:65535 -j ACCEPT $IPTABLES -A CLIENT_RULES_IN -p tcp --sport 25 --dport 1024:65535 -j ACCEPT $IPTABLES -A CLIENT_RULES_IN -p tcp --sport 53 --dport 1024:65535 -j ACCEPT $IPTABLES -A CLIENT_RULES_IN -p tcp --sport 80 --dport 1024:65535 -j ACCEPT $IPTABLES -A CLIENT_RULES_IN -p tcp --sport 443 --dport 1024:65535 -j ACCEPT $IPTABLES -A CLIENT_RULES_IN -p tcp --sport 587 --dport 1024:65535 -j ACCEPT $IPTABLES -N CLIENT_RULES_OUT $IPTABLES -A CLIENT_RULES_OUT -p udp --sport 1024:65535 --dport 53 -j ACCEPT $IPTABLES -A CLIENT_RULES_OUT -p tcp --sport 1024:65535 --dport 22 -j ACCEPT $IPTABLES -A CLIENT_RULES_OUT -p tcp --sport 1024:65535 --dport 25 -j ACCEPT $IPTABLES -A CLIENT_RULES_OUT -p tcp --sport 1024:65535 --dport 53 -j ACCEPT $IPTABLES -A CLIENT_RULES_OUT -p tcp --sport 1024:65535 --dport 80 -j ACCEPT $IPTABLES -A CLIENT_RULES_OUT -p tcp --sport 1024:65535 --dport 443 -j ACCEPT $IPTABLES -A CLIENT_RULES_OUT -p tcp --sport 1024:65535 --dport 587 -j ACCEPT $IPTABLES -A INPUT -i $LOCAL_ETH -d $LOCAL_MY_IP -j CLIENT_RULES_IN $IPTABLES -A OUTPUT -o $LOCAL_ETH -s $LOCAL_MY_IP -j CLIENT_RULES_OUT # 許可した通信以外は全て拒否するようにする。 # 所謂原則拒否(デフォルトDROP)のファイアウォールですね。 $IPTABLES -P INPUT DROP $IPTABLES -P OUTPUT DROP ## KVMのゲスト用に転送するパケット # KVMのゲストOSのファイアウォールはインストール直後に未設定となっている最悪の状態を想定し、 # ホスト側のFORWARDで、最低限必要なパケットのみを通すようにしておく。 # DMZ上のKVMゲストから外部サーバへのアクセス許可(パッケージアップデート等の為) # sshはゲストOSがクラックされた場合に、DMZ内にssh出来ないようにわざと通していない。 $IPTABLES -N FORWARD_CLIENT_RULES_IN $IPTABLES -A FORWARD_CLIENT_RULES_IN -p udp --sport 53 --dport 1024:65535 -j ACCEPT $IPTABLES -A FORWARD_CLIENT_RULES_IN -p tcp --sport 53 --dport 1024:65535 -j ACCEPT $IPTABLES -A FORWARD_CLIENT_RULES_IN -p tcp --sport 80 --dport 1024:65535 -j ACCEPT $IPTABLES -A FORWARD_CLIENT_RULES_IN -p tcp --sport 443 --dport 1024:65535 -j ACCEPT $IPTABLES -N FORWARD_CLIENT_RULES_OUT $IPTABLES -A FORWARD_CLIENT_RULES_OUT -p udp --sport 1024:65535 --dport 53 -j ACCEPT $IPTABLES -A FORWARD_CLIENT_RULES_OUT -p tcp --sport 1024:65535 --dport 53 -j ACCEPT $IPTABLES -A FORWARD_CLIENT_RULES_OUT -p tcp --sport 1024:65535 --dport 80 -j ACCEPT $IPTABLES -A FORWARD_CLIENT_RULES_OUT -p tcp --sport 1024:65535 --dport 443 -j ACCEPT # ローカルネットワーク側は少し許可するパケットを多くしている。 $IPTABLES -A FORWARD -i $LOCAL_ETH -d $LOCAL_NETWORK -m physdev --physdev-is-bridged -j CLIENT_RULES_IN $IPTABLES -A FORWARD -o $LOCAL_ETH -s $LOCAL_NETWORK -m physdev --physdev-is-bridged -j CLIENT_RULES_OUT # DMZ側は必要最低限のみ通す。 # DHCPやWindowsのファイル共有も通す必要はない。 $IPTABLES -A FORWARD -i $KVM_DMZ_ETH -d $DMZ_NETWORK -m physdev --physdev-is-bridged -j FORWARD_CLIENT_RULES_IN $IPTABLES -A FORWARD -o $KVM_DMZ_ETH -s $DMZ_NETWORK -m physdev --physdev-is-bridged -j FORWARD_CLIENT_RULES_OUT # ICMPのPINGは通すようにする。 $IPTABLES -A FORWARD -p icmp --icmp-type 0 -m physdev --physdev-is-bridged -j ACCEPT $IPTABLES -A FORWARD -p icmp --icmp-type 8 -m physdev --physdev-is-bridged -j ACCEPT # KVMゲスト用にDHCPは通すようにする $IPTABLES -A FORWARD -i $LOCAL_ETH -p udp --sport 67:68 --dport 67:68 -m physdev --physdev-is-bridged -j ACCEPT $IPTABLES -A FORWARD -o $LOCAL_ETH -p udp --sport 67:68 --dport 67:68 -m physdev --physdev-is-bridged -j ACCEPT # サーバを公開しているのならば下記のように公開の設定をする。 # ここでは、172.20.2.10のサーバが80番ポートでHTTPのみサービスを提供している事にして設定例を出しています。 $IPTABLES -N DMZ_SERVICE_IN $IPTABLES -A DMZ_SERVICE_IN -p tcp --sport 1024:65535 --dport 80 -j ACCEPT $IPTABLES -N DMZ_SERVICE_OUT $IPTABLES -A DMZ_SERVICE_OUT -p tcp --sport 80 --dport 1024:65535 -j ACCEPT $IPTABLES -A FORWARD -i $KVM_DMZ_ETH -d 172.20.2.10 -m physdev --physdev-is-bridged -j DMZ_SERVICE_IN $IPTABLES -A FORWARD -o $KVM_DMZ_ETH -s 172.20.2.10 -m physdev --physdev-is-bridged -j DMZ_SERVICE_OUT # 管理用のssh接続を受け付ける $IPTABLES -A FORWARD -i $KVM_DMZ_ETH -d $DMZ_NETWORK -s $LOCAL_NETWORK -p tcp --dport 22 --sport 1024:65535 -m physdev --physdev-is-bridged -j ACCEPT $IPTABLES -A FORWARD -o $KVM_DMZ_ETH -s $DMZ_NETWORK -d $LOCAL_NETWORK -p tcp --sport 22 --dport 1024:65535 -m physdev --physdev-is-bridged -j ACCEPT # 最後にFORWARDチェインもデフォルトDROPにする $IPTABLES -P FORWARD DROP
上記のiptablesの設定を行って、問題なく通信が出来る事と、nmapによるセキュリティスキャンが完了したならば、ルールを保存し、OS起動時にiptablesのファイアウォールが有効になるようにします。
#iptablesのルールを保存する IPTABLES_SAVE='/sbin/iptables-save' IPTABLES_RULES='/etc/iptables/rules.v4' $IPTABLES_SAVE > $IPTABLES_RULES
ここまでで一通りの設定を終えました。
再度ポートスキャンを実施し、結果を確認する
DMZ側のインターフェースに対してポートスキャンを実施します。iptablesのフィルタの設定前には、LAN側同様に待ち受けてしまっていましたが、全部のポートが塞がっているのが確認できました。
# DMZ側のポートスキャン結果 nmap -P0 -p 0-65535 172.20.2.30 Nmap scan report for 172.20.2.30 Host is up (0.00025s latency). All 65536 scanned ports on 172.20.2.30 are filtered MAC Address: D4:3D:7E:9D:00:00 (Unknown) Nmap done: 1 IP address (1 host up) scanned in 1313.81 seconds
続いてLAN側のポートスキャン結果です。こちらは必要なパケットは通しているので、修正前後で特に変わりはありません。tcpの5916番は評価用に作成したKVMゲストマシンのVNC待ち受けポートです。
# LAN側のポートスキャン結果 nmap -P0 -p 0-65535 172.20.1.30 Starting Nmap 6.00 ( http://nmap.org ) at 2013-09-18 17:28 JST Nmap scan report for 172.20.1.30 Host is up (0.00012s latency). Not shown: 65531 closed ports PORT STATE SERVICE 22/tcp open ssh 80/tcp open http 139/tcp open netbios-ssn 445/tcp open microsoft-ds 5916/tcp open unknown MAC Address: D4:3D:7E:9D:01:01 (Unknown) Nmap done: 1 IP address (1 host up) scanned in 0.81 seconds
仮想マシンから、必要な処理が出来ているか確認する
あまりにも長くなったのでここには記載しませんが、KVMで仮想マシンを作成し、仮想マシンからのpingや、apt-get等が問題なく出来る事と、余計なポートにアクセスできない事を確認しておきます。
最後に・・・
iptablesによるパケットフィルタをタグVLANとブリッジインターフェースのある環境で設定する設定例が見つからなかったため、試行錯誤して記事をまとめました。その為にnmapによる確認や、仮想マシン上からのping試験等もあり、なんだかんだで1日かかってしまいました。もしも、記載内容にミスがあった場合には、コメント頂けると嬉しい限りです。