Linuxのファイアウォール「iptables」について入門から実践まで解説
数回に分けてLinuxのファイアウォール「iptables(アイピーテーブルズ)」について解説します。
ネット上に有益な設定が溢れているので、あまり理解しないままコピーペーストで運用している方も多いはず。
しかしそれでは実際に攻撃された際に対処できません。
そこでこのページでは、初めてファイアーウォールについて学ぶ方でも理解できるように、全体像と細かな設定の意味について解説します。
目次
ファイアーウォールの種類
NATについて
パケットフィルタリングの概要と書式
テーブルについて
チェインについて
オプションについて
パラメータについて
拡張パラメータについて
iptablesの記述順序とルールの適用順について
ポリシーについて
ファイアーウォールの種類
ファイアウォールと聞いて、まず何を思い浮かべるでしょうか?
ほとんどの場合、通信の許可・不許可を設定する、パケットフィルタリングを思い浮かべる方が多いのではないでしょうか?
実はファイアーウォールにはパケットフィルタリングだけでなく、さまざまな機能があります。
ファイアーウォールは大別して「パケットフィルタリング型」と「プロキシ型」があります。パケットフィルタリングは名前の通り、アクセスを制御します。今回解説するiptablesはパケットフィルタリング型です。
そのためプロキシ型については今回は掘り下げません。簡単にいえば、プロキシ型は「Webサーバやメールサーバの代理として応答する」といった用途に利用します。
iptablesはLinuxのKernel 2.4移行で標準インストールされています。そのためLinux標準のファイアーウォールといえます。
それではiptablesの各機能について解説していきます。
NATについて
NAT(Network Address Translation)とはパケットフィルタリング型のファイアーウォールに搭載されている「ネットワークアドレス変換機能」のことです。
内部ネットワークの構成を知られたくない場合や、1つのグローバルIPを複数の内部サーバに割り振る際に利用します。
つまり、ファイアーウォールで通信の制御をするルーターの役割を担うという仕組みです。
今回はNATについては詳しく解説しませんが「こちらのページ」で詳しく解説されています。興味のある方は調べてみてください。
パケットフィルタリングの概要と書式
それでは本題のパケットフィルタリングについて解説します。まずは基本的な書式を確認していきましょう。
それぞれのパラメータについては後ほど解説します。まずは概要だけ理解しておいてください。
設定ファイルは「/etc/sysconfig/iptables」に保存されています。この設定ファイルを直接編集することも可能ですが、コマンドやシェルスクリプトを利用した編集が一般的です。このページではシェルスクリプトを利用して編集する方法を解説します。
iptablesの書式
iptables [-t テーブル] コマンド [マッチ] [ターゲット/ジャンプ]
例)tcp接続の受信データを破棄するというルールを追加する
iptables -A INPUT -p tcp -j DROP
テーブルについて
iptablesではパケットを、4つのテーブルに分けて、それぞれのタイミングで制御します。テーブルには「filterテーブル」「natテーブル」「mangleテーブル」「rawテーブル」があります。
filterテーブル
filterテーブルではパケットの通過や遮断といった制御をします。通常ほとんどの設定はこのテーブルに記述します。
下の例にあるように、設定ファイルを直接編集する際は、行頭に「*(アスタリスク)」を付けて、最後は「COMMIT」で指定。その間に書かれた設定がfilterテーブルのルールとなります。
例)設定ファイル(/etc/sysconfig/iptables)にあるfilterテーブルの例
*filter #ここにfilter関係の記述 COMMIT
例)コマンドでfilterテーブルにポート80のパケットを破棄するルールを追加する
iptables -t filter -p tcp --dport 80 -j -DROP
iptablesでは、ほとんどの設定をこのテーブルで行うため、特にテーブルの指定をしないと、自動でfilterテーブルにルールが追加されます。
例)上と同じルールの追加
iptables -p tcp --dport 80 -j -DROP
natテーブル
上で解説した、NAT(ネットワークアドレス変換機能)を担当します。送信先や送信元といったパケットの中身を書き換える際に利用します。各通信をローカルネットワーク上のサーバへ振り分けるルーターとして機能させることができます。
例)natテーブルの例
*nat #ここにnat関係の記述 COMMIT
例)IP マスカレードの指定
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -j MASQUERADE
例)インターフェイスeth0から受信したポート80のTCPパケットをローカルのApacheサーバ(172.31.0.1:80)へフォワーディング
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to 172.31.0.1:80
mangleテーブル
TOS(Type Of Service)フィールド等の値を書き換えます。TOSはパケット処理の優先度付けを行い、通信品質を制御する際に利用されます。
また特定の通信マークを置き換える事もできます。
例)mangleテーブルの例
*mangle #ここにmangle関係の記述 COMMIT
例)ポート80の通信のTOSを高スループットのものへ書き換え
iptables -t mangle -A PREROUTING -p tcp --dport 80 -j TOS --set-tos Maximize-Throughput
例)ポート443の通信マークをポート80のものと合わせ、マークマッチを使って通信を破棄
iptables -t mangle -A PREROUTING -p tcp --dport 80 -j MARK --set-mark 80 iptables -t mangle -A PREROUTING -p tcp --dport 443 -j MARK --set-mark 80 iptables -t mangle -A PREROUTING -m mark --mark 80 -j DROP
Rawテーブル
あまり解説されることはありませんが、特殊なテーブルとしてRawテーブルというものも存在します。用途はmangleテーブルのように特定のパケットにマークを付けることですが、Rawテーブルでは追跡を除外するようマークを付けます。つまり、特定の通信をファイアウォールで処理せずに他の機材へ通したりといった経路制御する場合に利用します。
例えば通信が1秒間に数千といった高負荷の場合、全ての通信を1台のサーバで扱うことが難しくなります。
高負荷の原因がDNSサーバへの問い合わせだったと仮定します。
負荷分散のために「DNSのパケットに関しては、別サーバで処理させたい」そのような際に、ポート53の通信にNOTRACKマークを付けます。
するとiptablesはNOTRACKマークの付いたパケットを、記録したり処理をせずに、別のサーバへ通します。
そうすることで、DNSの問い合わせを行うサーバと、それ以外の通信を処理するサーバに分けることができます。
*raw #ここにraw関係の記述 COMMIT
例)ポート53のUDPを通ったパケットの受信時と送信時にNOTRACKマークを付ける
iptables -t raw -I PREROUTING -p udp --dport 53 -j NOTRACK iptables -t raw -I OUTPUT -p udp --dport 53 -j NOTRACK
この他にもSELinuxで利用するSecurityテーブルというものもあります。 特殊なテーブルのため、このページでは詳しく解説しません。
チェインについて
それぞれのテーブルの中で、どのタイミングでフィルタリングするかを決めるのがチェインです。例えば受信時についてはINPUT、送信時についてはOUTPUTといった具合です。
チェインの種類
チェインには以下の種類があります
INPUT | 入力(受信)に対するチェイン |
---|---|
OUTPUT | 出力(送信)に対するチェイン |
FORWARD | フォアード(転送)に対するチェイン |
PREROUTING | 受信時に宛先アドレスを変換するチェイン。タイミングとしてはfilterで適用されるルールより手前 |
POSTROUTING | 送信時に送信元アドレスを変換するチェイン。これもfilterの後でパケットが送信される直前 |
上記のチェインを各テーブルに記述してパケットを制御しますが、それぞれのテーブルで使えるチェインは以下のように決まっています。
filterテーブル | INPUT、OUTPUT、FORWARD |
---|---|
natテーブル | POSTROUTING、PREROUTING、OUTPUT |
mangleテーブル | POSTROUTING、PREROUTING、INPUT、OUTPUT、FORWARD |
Rawテーブル | PREROUTING、OUTPUT |
ユーザー定義チェイン
ユーザーが自分でチェインを定義することもできます。
よく使う処理などをあらかじめ登録しておくことで、設定の見通しが良くなります。
定義する際には「-N userchain」と記述します。そのチェインを使う際には標準で用意されたチェインと同じように、「-j userchain」と記述する。
例)通信を破棄するdropchainを作成。ポート80のパケットを作成したdropchainにジャンプさせる。(結果としてポート80のパケットは破棄)
iptables -N dropchain iptables -A dropchain -j DROP iptables -A INPUT --dport 80 -j dropchain
各テーブルとチェインの関係を図にすると以下のようになります。思わぬ失敗を避けるため、実際に設定する際はどこにルールを追加しているか意識しながら作業を行うようにしてください。
オプションについて
オプションで設定できるのは、「コマンド」と「パラメータ」です。「コマンド」でチェインの扱いを決めて、「パラメータ」で細かな指定をするという流れになります。
コマンドについて
コマンドはチェインをどのように扱うかを指定します。下の一覧にあるように「-A INPUT」とすれば新しい受信時のルールを追加。「-D INPUT」とすれば受信時のルールを削除という指定ができます。
よく使うコマンドの一覧
指定方法 | 内容 |
---|---|
-A(--append) | 指定チェインに1つ以上の新しいルールを追加 |
-D(--delete) | 指定チェインから1つ以上のルールを削除 |
-P(--policy) | 指定チェインのポリシーを指定したターゲットに設定 |
-N(--new-chain) | 新しいユーザー定義チェインを作成 |
-X(--delete-chain) | 指定ユーザー定義チェインを削除 |
-I(--insert) | 指定したチェーンにルール番号を指定してルールを挿入する。(ルール番号を省略した際にはルール番号は1に設定され、チェーンの先頭に挿入される。) |
例)filterテーブルのINPUTに登録されたルール番号3番のルールを削除
iptables -t filter -D INPUT 3
パラメータについて
受信や送信はチェインで指定できますが、特定のIPだけ遮断、プロトコルによって遮断といった細かい制御をしたい場合はパラメータで指定します。
よく使うパラメータの一覧
指定方法 | 内容 |
---|---|
-s (--source) | パケットの送信元を指定。特定のIP(192.168.0.1)や範囲(192.168.0.0/24)を指定する |
-d (--destination) | パケットの宛先を指定。指定方法は-sと同じ。 |
-p (--protocol) | チェックされるパケットのプロトコル。 指定できるプロトコルは、 tcp、udp、icmp、allのいずれか1つか、数値。 |
-i (--in-interface) | パケットを受信することになるインターフェース名。eth0、eth1など |
-o (--out-interface) | 送信先インターフェース名を指定 |
-j (--jump) | ターゲット(ACCEPT、DROP、REJECT)を指定 |
例)224.0.0.1宛の受信パケットを破棄
iptables -A INPUT -d 224.0.0.1 -j DROP
「-j」で指定するターゲットについて
書式のtargetに当たる部分です。ターゲットは指定したパケットをどのように扱うかを指定します。ACCEPTであれば許可、DROPであれば破棄といった具合です。この他にユーザー定義チェインも指定することができます。
ターゲットの一覧
指定方法 | 内容 |
---|---|
ACCEPT | パケットの通過を許可 |
DROP | パケットを破棄。応答を返さない。 |
REJECT | パケットを拒否し、ICMPメッセージを返信 |
REDIRECT | 特定ポートにリダイレクト |
LOG | マッチしたパケットのログを記録 |
拡張パラメータについて
上記のパラメータに加え、一致する条件を更に細かく指定をする際に利用します。パケットマッチングモジュールとも呼ばれます。
拡張であることを明示することなく利用できる「-p」の後に追記するタイプと、「-m」で拡張を明示してから追記するタイプがあります。
「-p」オプションによって(暗示的に)呼び出されるタイプ
指定方法 | 内容 |
---|---|
--sport | Source Port。送信側(クライアント側)のポート番号を指定。-p tcp か -p udp の後に指定します。 |
--dport | Destination Port。受信側(サーバ側)のポート番号を指定-p tcp か -p udp の後に指定します。 |
--tcp-flags | TCP のときだけ指定することができる。第1引数に評価されるTCPフラグを指定し、第2引数に設定されていなければならないフラグを指定します。指定可能なフラグは、SYN、ACK、FIN、RST、URG、PSH、ALL、NONE です。複数指定する場合はカンマで区切り、引数の間は半角スペースで区切ります。(--tcp-flags SYN,RST,ACK SYN) |
--syn | TCP のときだけ指定することができる。SYNビットがセットされた、いわゆるTCPの接続確立時に、正規のスリーハンドシェイク手順を踏んだ通信を指定します。上記のSYN,RST,ACK SYNの省略形。 |
--icmp-type | ICMP のタイプを指定。pingに限定した指定をする際などに指定します。 |
例)ポート80で受信したTCPの受信パケットを破棄
iptables -A INPUT -p tcp --dport 80 -j DROP
例)ポート80で受信したTCPかつ、SYN、RST、ACKのうちSYNフラグだけを持った受信パケットを許可
iptables -A INPUT -p --tcp-flags SYN,RST,ACK SYN --dport 80 -j ACCEPT
「-m」オプションを付けることで(明示的に)呼び出されるタイプ
リミット拡張モジュール
limit | リミット拡張モジュールを読み込み。 |
---|---|
--limit | 時間あたりに何パケットまで許可するかを指定する。second(秒)、minute(分)、hour(時)、day(日)を指定することができます。--limit の初期値は 3/hour |
--limit-burst | 上記のリミットが有効になる通信の回数を指定。「○回受信したら1時間に1回に制限」という際の「○回」の部分を指定する。初期値は5。 |
例)TCPのポート80宛の受信パケットを、ハッシュリミットで5回まで無条件で受け入れ、それ以上のパケットを1分間に1度だけ許可する
バーストしても1分経つごとに1アクセスだけ受け入れるパケットが増える。つまり5分経てば再び5パケットまで受け入れる
iptables -A INPUT -p tcp --dport 80 -m hashlimit --hashlimit-burst 5 --hashlimit 1/m --hashlimit-mode srcip -j ACCEPT
length拡張モジュール
length | length拡張モジュールを読み込み。パケットのサイズをフラグとしてマッチさせることができる。 |
---|---|
--length | 「○:○」という書式で「前半の○から、後半の○サイズまで」と指定する。後半の指定を外せば○以上、前半の指定を外せば○以下という指定も可能。 |
例)85から65535バイトまでに一致。
iptables -A INPUT -p tcp --dport 80 -m length --length 85:65535
例)85バイト以下に一致。
iptables -A INPUT -p tcp --dport 80 -m length --length :85
state拡張モジュール
state | state拡張モジュールを読み込み。パケットを追跡することでステートフル・パケットインスペクションが可能になります。詳細は後述 |
---|---|
--state | 追跡しているパケットの状態を指定。新規か、既に許可をしたものか、などを指定する。 |
state拡張で指定可能なパラメータ
NEW | 全くの新参の接続 |
---|---|
ESTABLISHED | 既に許可された接続 |
RELATED | 新参ではあるが許可された接続 |
INVALID | パラメータの不明な無効な接続 |
例)TCPの受信パケットの内、新規の接続に関しては破棄
iptables -A INPUT -p tcp -m state --state NEW -j DROP
この他にも多くの拡張モジュールが存在します。
「こちらのページ」で詳しく解説しているので興味のある方は調べてみてください。
iptablesの記述順序とルールの適用順について
指定方法がわかったので早速設定といきたいところですが、iptablesの設定を理解する上でもう1つ重要な要素があります。それが記述順序です。
基本として、設定ファイルの先頭からルールが適用されます。条件にマッチしてパケットの扱いを設定した場合、そのパケットについての設定はそこで終了します。
よくある間違いの例です。
iptables -A INPUT -p tcp -m --dport 80 -j ACCEPT iptables -A INPUT -p tcp -m --dport 80 -j DROP
まずポート80の通信を「許可」しています。その設定の下に何度ポート80を「拒否」する設定を書いても「許可」されます。このように適用後に進行が停止するルールの代表がACCEPTやDROPです。
継続するルール
上の例ではパケットに関するルールが停止しましたが、継続してルールが適用されるものもあります。それがLOGやTOSなどです。
ポート80の通信をログファイルに書き出してから破棄する場合は以下のように記述します。
iptables -A INPUT -p tcp -m --dport 80 -j LOG iptables -A INPUT -p tcp -m --dport 80 -j DROP
注意点としては、先に破棄(DROP)を記述してしまうと、DROP移行はルールが停止するため、ログファイルには何も書き出されません。
上の例からわかるように、適用後に進行が停止するルールと、適用後も進行するルールを意識して使用する必要があります。
順序を間違えることでよくある間違い
TCP通信を全て許可してから、ポート80のTCP通信を破棄という設定です。すでにTCP通信全体を許可しているので、それ移行TCP通信についてのルールは適用されません。
iptables -A INPUT -p tcp -j ACCEPT iptables -A INPUT -p tcp -m --dport 80 -j DROP
ポート80のTCP通信を破棄して、それ以外のTCP通信を全て許可したい場合は、以下の順序で記述してください。
iptables -A INPUT -p tcp -m --dport 80 -j DROP iptables -A INPUT -p tcp -j ACCEPT
はじめにポート80のTCP通信を破棄しているので、それより後にTCP通信全体を許可しても、ポート80のTCP通信は破棄されます。
このようにルールの記述順で全く違った設定になってしまいます。特に設定の例をコピー・ペーストして利用していると、間違えやすいので注意してください。
ポリシーについて
ポリシーとはチェイン全体に適用されるルールのことです。ポリシーの設定は「-P」オプションを使って記述します。
ポリシーでは2つのパターンが考えられます。
- 1.全て拒否してから特定の通信だけ許可する場合。許可するポートが少ない場合に向いています。
- 2.全て許可してから特定の通信だけ拒否する場合。拒否するポートが少ない場合に向いています。
ほとんどの場合、INPUTチェインに関しては安全性を考えて1番の「拒否してから許可」で運用します。
例)filterテーブルの受信はすべて破棄。送信はすべて許可
iptables -t filter -P INPUT DROP iptables -t filter -P OUTPUT ACCEPT
上で設定後にパケットの扱いが停止するルールと、停止しないルールについて解説しましたが、ポリシーは停止しません。そのため、後に記述するルールで上書きすることができます。
例)ポリシーでINPUT全体を破棄した後に、ポート80を許可する
iptables -P INPUT DROP iptables -A INPUT -m --dport 80 -j ACCEPT
以上でiptablesの仕組みと設定方法についての基本は終了です。
初めてiptablesについて学んだ方は「規制が多くて敷居が高そう」と感じてるのではないでしょうか。しかし安心してください、実際に設定してみると意外に簡単で、それらの規制が逆に便利に感じられます。
次は実践編として、シェルスクリプトを利用して設定ファイルを編集します。
「iptablesの設定ファイルをシェルスクリプトを利用して動的に作成」
このページでiptablesを学んだ者です。
このテーブルとチェインの絵はスマホの待受にしてますwすごくわかりやすいです。
で、わたしも最近気がついたのですが
iptablesには、SELinuxとの関連付けができる「security」テーブルがあります。
このテーブルを扱い始めると、SELinuxを取り扱う必要があるので詳細は不要かと思いますが、
「Securityテーブルというのもある。ただしかなり複雑なのでこのページでは割愛」レベルで記載頂けると幸いです。
参考にしていただきありがとうございます。
Securityテーブルについて追記させていただきました。
わかりやすくてためになる記事、ありがとうございます。
一つ質問させてください。
「Rawテーブル」のNOTRACKの利用シーンに関する説明なんですが、もう少し前提というか構成を知りたいと感じました。
こんな感じでしょうか?
DNS問い合わせサーバ・・・Aサーバ
それ以外の処理をするサーバ・・・Bサーバ
Bサーバに下記のiptablesの設定をする。
“`
iptables -t raw -I PREROUTING -p udp –dport 53 -j NOTRACK
iptables -t raw -I OUTPUT -p udp –dport 53 -j NOTRACK
“`
おそらくこれに加えて、下記を実現するために、さらにiptablesのnatテーブルでAサーバにポートフォワード設定がされているというイメージでしょうか?
「するとiptablesはNOTRACKマークの付いたパケットを、記録したり処理をせずに、別のサーバへ通します。」
ちょっと疑問に感じたのは、別サーバにDNS解決処理を移譲することに対して、NOTRACKする意味がそれほどあるのか微妙な気がしてますがどうなんでしょうか。
問い合わせ負荷が高いDNSサーバ上のiptablesでDNS通信に対してNOTRACKをつけて、負荷を下げるというのはわかるのですが、上記の例はちょっとピンとこなかったです。
DNSとしたのはあくまで例です。
また、DNSはほとんどの場合サーバに影響を与えることはありませんが、DNS Amp攻撃などの場合にはこうした対策が有効です。
こんにちは、最近ラズベリーパイを始めて、iptablesを使い始めたのですが、ファイヤーウォールで守られたLAN内で運用しているため、基本開放で外部に開放しているポートのみ回数制限する様な使い方をしたいです。
ポリシーのパターン2つ目の設定の仕方になると思うのですが、設定例などご紹介頂けませんか?
iptables -P INPUT DROP
iptables -A INPUT -p tcp –dport 80 -m hashlimit –hashlimit-burst 5 –hashlimit 1/m –hashlimit-mode srcip -j ACCEPT
の様な設定で合っているのか不安で。
間違えました。逆ですよね。
基本的に内部だけならプライベートIPアドレスだけ許可して後は閉じてしまうのが一番簡単かと思います。