CentOS6.3ではiptablesはデフォルトで有効になっており、カーネル再構築などは不要で1す。今、どういった内容でパケットフィルタが設定されているのか以下のコマンドで確認可能です。デフォルトではsshサービスへの接続しか許可されていません。
# iptables -L Chain INPUT (policy ACCEPT) target prot opt source destination ACCEPT all -- anywhere anywhere state RELATED,ESTABLISHED ACCEPT icmp -- anywhere anywhere ACCEPT all -- anywhere anywhere ACCEPT tcp -- anywhere anywhere state NEW tcp dpt:ssh REJECT all -- anywhere anywhere reject-with icmp-host-prohibited Chain FORWARD (policy ACCEPT) target prot opt source destination REJECT all -- anywhere anywhere reject-with icmp-host-prohibited Chain OUTPUT (policy ACCEPT) target prot opt source destination |
■テーブル
実際にiptableを設定するのですがiptablesを使うには、テーブルやチェインなどの概念を理解しておく必要があります。iptablesには、以下の3つの「テーブル」が用意されています。
テーブル一覧 | |
filter | パケットフィルタリングを参照するテーブルを指定する。 |
nat | 新しいセッションを開くパケットが参照するテーブルを指定する。 |
mangle | 特別なパケットが参照するテーブルを指定する。 |
■チェーン
iptablesでは特定条件に当てはまるパケットに対して処理ルールを定義します。この条件のグループをチェーンと呼びます。チェーンには最初から定義されている組み込みチェーンと後からユーザが定義するユーザ定義チェーンの2種類あります。冒頭で紹介した各ステップは組み込みチェーンとして利用できます。下記のようにテーブルによって利用できる組み込みチェーンに制限があります。
チェーン一覧 | テーブル | |
INPUT | 入力(受信)パケット | filter , mangle |
OUTPUT | 出力(送信)パケット | filter , nat , mangle |
FORWARD | フォワードするパケット | filter |
PREROUTING | 受信時を宛先アドレスを変換するチェイン | nat , mangle |
POSTROUTING | 送信時に送信元アドレスを変換するチェイン | nat |
■ターゲット
-jパラメータでは、「ターゲット」を指定する必要があります。これは、パケットがマッチした際のアクション(何を行うか)のことです。主なものは次の通りです。
ターゲット一覧 | |
ACCEPT | パケットの通過を許可 |
DROP | パケットを破棄 |
RETRUN | チェーン内のルール評価を終了する |
MASQUERADE | 「-t nat」と「-A POSTROUTING」と同時に用いて 送信元IPとポート番号を書き換える |
REJECT | パケットを拒否し、ICMPメッセージを返信 |
PREROUTING | 特定ポートにリダイレクト |
LOG | Logを採取する |
SNAT | パケットの送信元アドレスを修正する。 natテーブルでpostroutingチェーンでのみ利用できる。 |
DNAT | パケットの送信先アドレスを修正する。 natテーブルでpostroutingチェーンでのみ利用できる。 |
■ルール
ルールはパケットの内容との比較条件です。条件に合致したパケットは別のチェーンのルールに照らし合わせたりターゲットを指定して処理を行うことができます。iptablesに対してルールを設定する場合にはオプションの形式で指定します。以下、代表的なルールのオプションです。
オプション一覧 | |
-p [!] <protocol> | ルールで使うプロトコル(tcp、udp、icmp、all)を指定 |
-s [!] <address> [/<netmask>] | 送信元アドレス。IPアドレスのほかにホスト名などでも指定できる |
-d [!] <address> [/<netmask>] | 接続先アドレス。IPアドレスのほかにホスト名などでも指定できる |
–sport <port> | 送信元ポートを指定する。 |
–dport <port> | 送信先ポートを指定する。 |
-i <interface> | パケットが入ってくるインターフェイス(eth0、eth1など)を指定 |
-o <interface> | パケットが出ていくインターフェイスを指定 |
-j <target> | パケットがマッチしたときのアクション(ターゲット)を指定 |
-t <table> | テーブル(filter、nat、mangle)を指定 |
-m <module> | モジュールを指定する。-pで暗黙に指定されるので省略することも可。 |
–icmp-type [!] <type> | ICMPでタイプ名を指定する。( iptables -p icmp -hで表示されるタイプを指定。 |
! | -p、-s、-dなどで、条件を反転する。「! 192.168.0.1」とすると、「192.168.0.1以外」という意味になる |
■ヘルパーモジュール
CentOSの標準設定で使われているstateモジュールはアクティブモードのFTPやamandaなどの特殊なコネクションの通信を追跡する機能をもっています。但し、これらのプロトコルの通信を追跡するにはプロトコルごとのヘルパーモジュールを読み込む必要があります。下記はそのヘルパーモジュールの一覧です。
モジュール | 対応プロトコル |
nf_conntrack_amanda | Amanda |
nf_conntrack_ftp | FTP |
nf_conntrack_netbios_ns | NetBIOS Name Service |
nf_conntrack_pptp | PPTP |
nf_conntrack_tftp | TFTP |
これらのモジュールを読み込むには/etc/sysconfig/iptables-configのIPTABLES_MODULESのIPTABLES_MODULEに該当モジュールを追記します。
# Load additional iptables modules (nat helpers) # Default: -none- # Space separated list of nat helpers (e.g. 'ip_nat_ftp ip_nat_irc'), which # are loaded after the firewall rules are applied. Options for the helpers are # stored in /etc/modprobe.conf. IPTABLES_MODULES="nf_conntrack_netbios_ns" |
■stateモジュール
stateモジュールを利用することで通信の段階に応じた制限をかけることが可能です。一般的には一旦接続を受け付けた通信は全て許可し、接続の可否だけを制御します。書式は下記のようになります。
-m state [!] --state <state> |
–stateで指定可能なものは以下があります。
名称 | 状態 |
INVALID | 既存のコネクションとは関係のないパケット |
NEW | 新しいコネクションの接続に関するパケット |
ESTABLISHED | 接続済みコネクションのパケット |
RELATED | 接続済みコネクションに関連して発生した新たなコネクションパケット |
■iptablesコマンド
iptablesコマンドで設定を実施していきます。iptablesの主なコマンドとして以下があります。全ての操作でテーブルの指定は省略することができ、省略した場合はfilterテーブルに対して操作が行われます。
コマンド一覧 | |
iptables [ -t <table>] -A | append。最後尾に追加。 |
iptables [ -t <table> ] -L | line-numbers。設定内容表示。 |
iptables [ -t <table> ] -D | delete。既存のルールの削除。 |
iptables [ -t <table> ] -F | flush。指定したチェーン全てを削除。 |
iptables [ -t <table> ] -I | insert。先頭にチェーンを追加。ルール番号を指定することで任意の場所に挿入。 |
iptables [ -t <table> ] -P | チェーン内全体で有効なポリシーを定義。デフォルトはAccept。 |
iptables [ -t <table> ] -N | new。新しいチェーンを作成。 |
■全体ポリシーとICMPの許可
パケットフィルタリングを設定する前に既存のフィルタリングルールは全て破棄する必要があります。以下のコマンドで実行することにより全てのルールが削除されます。チェーンは特に明記していませんが、省略した場合、全てのチェーンに適用されます。
# /sbin/iptables -t filter -F |
ルールを削除したらポリシーの設定を行います。チェーンにはINPUT, OUTPUT, FORWARDのみ指定できユーザ定義チェーンは指定できません。またtargetにはDROPまたはACCEPTのみ設定できます。以下ではINPUT/OUTPUTチェーンにDROPポリシーを設定しています。
# /sbin/iptables -P INPUT DROP # /sbin/iptables -P OUTPUT DROP # /sbin/iptables -P FORWARD DROP |
続いて許可ルールを追加していくわけですが、まず最初に制御用の通信であるICMPの設定を行います。ICMPのルールを設定する場合にはオプションでプロトコルにicmpを設定します。icmpには以下のタイプがあります。
番号
|
メッセージタイプ
|
0 | Echo Reply |
3 | Destination Unreachable |
4 | Source Quench |
5 | Redirect |
8 | Echo Request |
11 | Time Exceeded |
12 | Parameter Problem |
13 | Timestamp Request |
14 | Timestamp Reply |
15 | Information Request |
16 | Information Reply |
17 | Address Mask Request |
18 | Address Mask Reply |
次の例ではfilterテーブルのINPUT,OUTPUTチェーンにタイプを指定せずにICMPをまるごと許可するルールを追加しています。
# /sbin/iptables -A INPUT -p icmp -j ACCEPT # /sbin/iptables -A OUTPUT -p icmp -j ACCEPT # /sbin/iptables -A FORWARD -p icmp -j ACCEPT |
pingにだけ応答するようにするのであればタイプ0と8のecho requestとecho replayを指定してもOKです。下記はecho requestを受け付けてecho replayを許可するルールになります。
# /sbin/iptables -A INPUT -p icmp --icmp-type 8 -j ACCEPT # /sbin/iptables -A OUTPUT -p icmp --icmp-type 0 -j ACCEPT |
iptablesによる通信の制御はループバックに対しても適用されます。通常はループバックに対しては通信を制限しないため許可ルールを設定しておきます。次のようにオプションでloインターフェイスを指定して通信許可の設定を追加します。
# /sbin/iptables -A INPUT -i lo -j ACCEPT # /sbin/iptables -A OUTPUT -o lo -j ACCEPT |
■TCP/UDPのルール追加
TCPやUDPのルールを追加する場合にはオプションでプロトコルtcp/udpを指定し、さらにポート番号、送信元アドレスやポート、送信先アドレスやポートを指定することで細かな設定をすることができます。またstateモジュールを利用することで通信の段階に応じた制限も可能です。一般的には一旦受け付けた接続は通信は全て許可し、接続の可否だけ制御します。
最初に受け付けた通信を許可する設定を行います。-mオプションでstateモジュールの利用を宣言し、–stateオプションでルールの対象となる状態を指定します。以下ではESTABLISHEDとRELATEDのパケットを許可していますので一旦コネクションを接続した後の全ての通信が許可されます。
# /sbin/iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT # /sbin/iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT # /sbin/iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT |
次に接続を許可する設定を行います。例えば自身で公開しているWWW ( TCP/80 )への接続を全て許可する場合は–dportを使って以下のように設定を行います。-m tcpでTCP用モジュールを指定し、プロトコル、宛先ポートを指定しています。
# /sbin/iptables -A INPUT -m state --state NEW -p tcp --dport 80 -j ACCEPT |
特定の相手からのみ接続を許可するには-sオプションを使用します。以下の例は192.168.12.5からのSSH ( TCP/22 )を許可する場合の例です。
# /sbin/iptables -A INPUT -m state --state NEW -p tcp -s 192.168.12.5 --dport 22 -j ACCEPT |
UDPの場合も同様です。例えばDNS ( UDP/53 )への通信を全て許可する場合には次のように設定を行います。
# /sbin/iptables -A INPUT -m state --state NEW -p udp --dport 53 -j ACCEPT |
またサーバ内部から外部への通信の設定はOUTPUTチェーンに対して行います。次はサーバ内部から外部へのSSH ( TCP/22 )とNTP ( UDP/123 )の接続を許可する設定の例です。
# /sbin/iptables -A OUTPUT -m state --state NEW -p tcp --dport 22 -j ACCEPT # /sbin/iptables -A OUTPUT -m state --state NEW -p udp --dport 123 -j ACCEPT |
-dオプションを使えば接続相手のIPアドレスを明示的に指定することもできます。以下は192.168.12.2へのSMTP接続を許可する設定です。
# /sbin/iptables -A OUTPUT -m state --state NEW -p tcp -d 192.168.12.2 --dport 25 -j ACCEPT |
FORWARDチェーンへ同様の設定をすることでルータとして転送する場合の通信許可も同様に行うことができます。
# /sbin/iptables -A FORWARD -m state --state NEW -p tcp -d 192.168.12.2 --dport 25 -j ACCEPT |
■hashlimitによるDoS対策
前述したbrute force attackは既に古い手法であり、これを使うのであればhashlimitモジュールの使用をおすすめします。hashlimitはクライアントのIPアドレスごとに一定期間の接続回数をカウントし、閾値を超えた場合はドロップするといったことが可能となります。ありがちなのはWebメールサーバなどにおいて辞書攻撃を受けて不正にログインされSPAMを送られるということが過去にありました。こういったケースでは短時間に猛烈なアクセスをかけてくるので、こういった類の攻撃を防ぐのにも役立つと思います。
このhashlimitを使ったiptablesのconfigは以下のようになります。
-A INPUT -m state --state NEW -p tcp -s 192.168.12.0/24 --dport 22 \ -m hashlimit --hashlimit-burst 5 --hashlimit 1/m --hashlimit-mode srcip \ --hashlimit-htable-expire 120000 --hashlimit-name ssh-limit -j ACCEPT |
長いので3行にわけて記載しています。各項目の意味は以下のようになります。
項目 | 説明 |
-m hashlimit | hashlimitモジュールを使用する |
-hashlimit-burst 5 | 規定時間内に5パケット受信すればリミットを有効にする |
-hashlimit 1/m | リミット時には1分間に1パケットを上限とする |
-hashlimit-mode srcip | ソースIPを元にアクセスを制限する |
-hashlimit-htable-expire 120000 | リミットの有効期間。単位はmsで120000は2分間。 |
-hashlimit-name ssh-limit | 送信元IPを記録するファイル名。 |
繰り返しますがハッシュリミットは規定時間内にどれだけのパケットを受理するのかを制限するためのものです。-hashlimit-htable-expireでその規定時間を設定します。上では2分という値を設定しており、これが一定の区切りとなります。この2分の間に同一送信元IPから5パケット以上届けばリミットが有効となり、その後は毎分5パケットのみ許可されるようになります。2分が経過すると送信元IPが一旦リフレッシュされ、以降は同様の動きとなります。
hashlimit-nameで指定するファイルは送信元IPアドレスは以下に記録されます。
# tail /proc/net/ipt_hashlimit/ssh-limit 1171 192.168.12.2:0->0.0.0.0:0 1293728 1920000 1920000 |
■実際の設定
これまではINPUT/OUTPUTの両方でフィルタリングを考慮してきましが、実際の現場ではINPUTのみ設定することが多いです。市販のFirewall製品のようにiptablesはセッション情報まで保持しておらずこれまでみてきたように入力/出力パケットの両方を考慮しなければならず机上で設計した内容を適用してみると想定どおりに動かないことがよくあります。そもそもサーバ手前のFirewallでフィルタリングすることが多いのでiptablesではINPUTのみで良いように思います。
起動のたびにiptablesコマンドをうつのは非現実的なので/etc/sysconfig/iptablesに書き込んでいき起動の際に自動的に適用されるよう設定してゆきます。
# vi /etc/sysconfig/iptables # Firewall configuration written by system-config-firewall # Manual customization of this file is not recommended. *filter :INPUT DROP [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] # 任意のIPからは全てを受け付ける -A INPUT -s 192.168.0.0/16 -j ACCEPT # 特定ポートに対しては全てのIPから拒否 -A INPUT -p tcp -m multiport --dports 135,137,138,139,445 -j DROP -A INPUT -p udp -m multiport --dports 135,137,138,139,445 -j DROP # 任意からHTTP/HTTPSアクセスを受け付ける -A INPUT -m state --state NEW -p tcp --dport 80 -j ACCEPT -A INPUT -m state --state NEW -p tcp --dport 443 -j ACCEPT # 規定時間内に192.168.12.0/24からSSHアクセスを受け付ける -A INPUT -m state --state NEW -p tcp -s 192.168.12.0/24 --dport 22 \ -m hashlimit --hashlimit-burst 5 --hashlimit 1/m --hashlimit-mode srcip \ --hashlimit-htable-expire 120000 --hashlimit-name ssh-limit -j ACCEPT # 192.168.12.0/24からFTPアクセスを受け付ける -A INPUT -m state --state NEW -p tcp -s 192.168.12.0/24 --dport 20:21 -j ACCEPT # 任意へのDNS/NTPアクセスの戻りパケットを受け付ける -A INPUT -p udp --sport 53 -j ACCEPT -A INPUT -p udp --sport 123 -j ACCEPT # 192.168.12.0/24からのNTPアクセスを受け付ける -A INPUT -m state --state NEW -p udp -s 192.168.12.0/24 --dport 123 -j ACCEPT # TCP戻りパケットを受け付ける -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT # ICMPパケットは全て許可 -A INPUT -p icmp -j ACCEPT # ループバックインターフェイスに対して全て許可 -A INPUT -i lo -j ACCEPT # ログを取得する。レベルはdebug/info/notice/warning/error/crit/emergから選択可能 -A INPUT -j LOG --log-prefix "iptables:" --log-level=error # 上のルールを実行する COMMIT |
ログに関しては環境によっては膨大な数になるかもしれないので採取しないというのもありだと思います。また、IPアドレスなど明示的に指定しなければそれは任意(全て)という意味になります。これでiptablesを起動します。
# /etc/rc.d/init.d/iptables start |
iptables -Lで確認します。
# iptables -L Chain INPUT (policy DROP) target prot opt source destination ACCEPT tcp -- anywhere anywhere state NEW tcp dpt:http ACCEPT tcp -- anywhere anywhere state NEW tcp dpt:https ACCEPT tcp -- 192.168.12.0/24 anywhere state NEW tcp dpt:ssh \ limit: up to 1/min burst 5 mode srcip htable-expire 120000 ACCEPT tcp -- 192.168.12.0/24 anywhere state NEW tcp dpts:ftp-data:ftp ACCEPT udp -- anywhere anywhere udp spt:domain ACCEPT udp -- anywhere anywhere udp spt:ntp ACCEPT udp -- 192.168.12.0/24 anywhere state NEW udp dpt:ntp ACCEPT all -- anywhere anywhere state RELATED,ESTABLISHED ACCEPT icmp -- anywhere anywhere ACCEPT all -- anywhere anywhere Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination |
■パケットフィルタの状態表示
iptablesによるパケットフィルタの状態を表示するユーティリティとしてiptstateを利用することができます。ログを採取することでもある程度の状態を把握することができますが、大量に出力されるためこういったツールを用いることでも有用に活用できると思います。iptstateを利用するには以下のようにインストールを行います。
# yum install iptstate # rpm -qa | grep iptstate iptstate-2.2.2-4.el6.i686 |
iptstateをrootユーザで起動すると次のような画面が表示されます。
IPTState - IPTables State Top Version: 2.2.2 Sort: SrcIP b: change sorting h: help Source Destination Prt State TTL 192.168.12.1:40501 192.168.12.20:80 tcp TIME_WAIT 0:00:08 192.168.12.1:40509 192.168.12.20:80 tcp TIME_WAIT 0:00:36 192.168.12.1:40521 192.168.12.20:80 tcp TIME_WAIT 0:01:28 192.168.12.20:42143 192.168.12.1:53 udp 0:00:01 192.168.12.20:22 192.168.12.2:54504 tcp ESTABLISHED 119:59:59 192.168.12.20:42958 192.168.12.1:53 udp 0:00:24 192.168.12.20:54388 192.168.12.1:53 udp 0:01:53 192.168.12.20:54379 192.168.12.1:53 udp 0:00:09 192.168.12.20:50001 192.168.12.1:53 udp 0:00:17 192.168.12.20:123 189.211.62.210:123 udp 0:00:26 192.168.12.20:59379 192.168.12.1:53 udp 0:00:06 192.168.12.20:44900 192.168.12.1:53 udp 0:00:52 192.168.12.20:57550 192.168.12.1:53 udp 0:02:55 192.168.12.20:55899 192.168.12.1:53 udp 0:02:39 192.168.12.20:34487 192.168.12.1:53 udp 0:00:52 192.168.12.20:54236 192.168.12.1:53 udp 0:01:53 |