Linux のパケットフィルタリングは、ネットワークスタックにフックを公開するカーネルフレームワーク Netfilter によって実装されています。iptables と nftables は独立したファイアウォールではありません。これらは、各フックでパケットの分類とアクションをプログラミングするためのユーザー空間インターフェースです。
iptables は歴史的なインターフェースです。nft コマンドで設定するネイティブな nftables は、個別に存在していた iptables、ip6tables、arptables、ebtables のルール管理モデルを、1 つの言語と 1 つの Netlink API に置き換えます。互換ツールは、iptables 構文を受け付けながら nftables カーネルバックエンドへ書き込むこともできるため、コマンド名だけでは実際に有効な実装を判別できません。
Netfilter のパケットフロー #
パケットがネットワークスタックを通過すると、Netfilter は登録済みの処理を呼び出します。
ルーティングの判断によって、パケットが通る経路が決まります。
- ローカルソケット宛てのパケットは
preroutingとinputを通過します。 - ホストを経由してルーティングされるパケットは、
prerouting、forward、postroutingを通過します。 - ローカルで生成されたパケットは
outputとpostroutingを通過します。 - オプションのデバイス固有
ingressフックは、preroutingより前に実行されます。
ingress フックは、後続のネットワーク処理が行われる前にトラフィックを拒否できますが、この時点では IP フラグメントはまだ再構成されていません。したがって、TCP または UDP ヘッダーを読み取るルールは、この時点で初期フラグメント以外を分類できません。
フック名はパケット処理上の位置を表すものであり、組み込みルールを表すものではありません。nftables はデフォルトではチェーンを作成しないため、ルールセットは必要な各フックにベースチェーンを明示的にアタッチする必要があります。
3 つのインターフェースと 2 つのカーネル API #
現在のシステムでは、2 種類の異なるカーネルルール API を基盤とする 3 つのコマンドインターフェースを利用できます。
iptables-legacyは、歴史的なx_tablesカーネル API をプログラミングします。iptables-nftは iptables 構文を受け付けますが、互換レイヤーとnft_compatを介してnf_tablesをプログラミングします。nftはネイティブの nftables 言語とnf_tablesNetlink API を使用します。
nftables バックエンドは、ルールをカーネル内のネットワーク固有仮想マシン向け命令にコンパイルします。既存の Netfilter フック、コネクショントラッキング、NAT、ロギング、キューイング、その他のサポート基盤を再利用します。
バイナリ名から推測せず、選択されている iptables バックエンドを確認してください。
iptables --version
readlink -f "$(command -v iptables)"(nf_tables) を含むバージョン文字列は、nftables バックエンドを示します。ディストリビューションの alternatives やシンボリックリンクによって選択が変わることがあります。
iptables のモデル #
iptables は、事前定義されたテーブルと組み込みチェーンにルールを整理します。主な IPv4 テーブルは次のとおりです。
| Table | Primary Purpose |
|---|---|
filter | INPUT、FORWARD、OUTPUT を通過するパケットを受け入れるか拒否する。 |
nat | 新しい接続に対するアドレスまたはポートの変換を作成する。 |
mangle | 特殊な処理のためにパケットフィールドとマークを変更する。 |
raw | コネクショントラッキングの前に実行し、NOTRACK の判断などを行う。 |
security | Linux セキュリティモジュールが使用するセキュリティマークを適用する。 |
チェーン内のルールは順番に評価されます。マッチ条件は、インターフェース、アドレス、プロトコル、ポート、接続状態、マーク、または拡張固有のプロパティによってパケットを選択します。ターゲットは、パケットを受け入れ、破棄し、拒否し、ログに記録し、変換し、または別のチェーンへ制御を移します。
IPv4 と IPv6 では、別々のコマンドとルールセットを使用します。
iptables -A INPUT -p tcp --dport 22 \
-m conntrack --ctstate NEW -j ACCEPT
ip6tables -A INPUT -p tcp --dport 22 \
-m conntrack --ctstate NEW -j ACCEPTiptables-legacy の増分変更では、テーブルの読み取り、変更、置換が必要です。そのため、同時に書き込むプロセスは xtables ロックを介して調整されます。多数の独立した iptables -A コマンドを含むシェルスクリプトよりも、iptables-restore が適しています。完全なテーブルを置き換えるため、部分的なポリシーが順次露出することを防げます。
nftables のモデル #
nftables は、ファミリー、テーブル、チェーン、ルール、ステートフルオブジェクトの階層を使用します。
- ファミリーはパケットドメインを選択します。
ip、ip6、inet、arp、bridge、netdevがあります。 - テーブルは、チェーン、セット、マップ、カウンター、フローテーブルの名前空間です。
- ベースチェーンは Netfilter フックにアタッチされ、チェーンタイプ、優先度、オプションのデフォルトポリシーを宣言します。
- 通常チェーンにはフックがなく、
jumpまたはgotoを通じて到達します。 - ルールは式を左から右へ評価し、式が一致した場合にステートメントを実行します。
inet ファミリーを使用すると、1 つのルールセットで IPv4 と IPv6 のトラフィックを処理できます。プロトコル固有の式は、依然として一方のプロトコルファミリーだけを選択します。たとえば、ip saddr は IPv4 アドレスに一致し、ip6 saddr は IPv6 アドレスに一致します。
デュアルスタックホストのファイアウォール #
次のファイルは、ループバックトラフィック、応答、診断用 ICMP、および IPv4 管理ネットワークからの SSH を許可しつつ、ステートフルなデフォルト拒否入力ポリシーを定義します。
#!/usr/sbin/nft -f
flush ruleset
table inet firewall {
set admin_ipv4 {
type ipv4_addr
flags interval
elements = { 192.0.2.0/24 }
}
chain input {
type filter hook input priority filter
policy drop
ct state invalid drop
ct state established,related accept
iifname "lo" accept
meta l4proto { icmp, ipv6-icmp } accept
ip saddr @admin_ipv4 tcp dport 22 accept
}
chain forward {
type filter hook forward priority filter
policy drop
}
chain output {
type filter hook output priority filter
policy accept
}
}ファイルを単一トランザクションとして検証してロードします。
nft --check --file /etc/nftables.conf
nft --file /etc/nftables.conf
nft list rulesetnft --file は完全なバッチを解析し、1 つのカーネルトランザクションとして送信します。いずれかのコマンドが失敗した場合、トランザクションは部分的にコミットされません。同じファイルに flush ruleset を置くと、管理対象のルールセットをアトミックに置き換えられます。追加型のファイルを繰り返しロードする際に flush を省略すると、ルールが重複する可能性があります。
別のサービスが無関係な nftables テーブルを管理している場合は、flush ruleset を使用しないでください。その場合は、現在のコンポーネントに割り当てられたテーブルだけを置き換えます。
フック、優先度、判定 #
ベースチェーンの宣言によって、チェーンが実行されるタイミングが決まります。
type filter hook input priority filter; policy drop;type filterは通常のパケットフィルタリングを選択します。hook inputはチェーンをローカル配送トラフィックにアタッチします。priority filterは標準のフィルタリング優先度に配置します。数値は 0 です。policy dropは、別の判定を行わずに評価が末尾へ到達した場合に適用されます。
同じフックには複数のベースチェーンをアタッチできます。Netfilter は、デフラグ、コネクショントラッキング、宛先 NAT、送信元 NAT などの内部処理を含め、数値の小さい優先度から順番に評価します。
accept 判定は現在のチェーンを終了しますが、同じフックにある後続のベースチェーンは、パケットを引き続き破棄できます。drop 判定は直ちにパケットを破棄します。したがって、ファイアウォールを分析する際は、accept を返す最初のチェーンだけでなく、そのフックにあるすべてのベースチェーンを含める必要があります。
通常チェーンの制御フローも異なります。
jump service_checksは別のチェーンに入り、そのチェーンが末尾に到達すると戻ります。goto service_checksは呼び出し元チェーンに戻らずに制御を移します。returnは呼び出し元チェーンを再開します。ベースチェーンから戻る場合は、ベースチェーンのポリシーを適用します。
コネクショントラッキング #
nf_conntrack サブシステムは、パケットをフローに関連付けます。iptables と nftables は、ステートフルフィルタリングと NAT にこれを使用します。一般的な状態は次のとおりです。
| State | Meaning |
|---|---|
new | 有効なパケットが、双方向のトラフィック交換をまだ行っていないフローを開始するか、そのフローに属する。 |
established | Conntrack が双方向の有効なトラフィックを確認している。 |
related | 新しいフローが既存の追跡対象接続に関連付けられている。 |
invalid | パケットを有効な追跡対象フローに関連付けられない。 |
untracked | 以前のポリシーがパケットを追跡対象から明示的に除外した。 |
ステートフルルールを使用すると、すべての一時的な宛先ポートを開放せずに応答トラフィックを許可できます。
ct state established,related accept
ct state invalid dropConntrack は有限なカーネルメモリを消費します。テーブルが nf_conntrack_max に達すると、カーネルは追加のフローを追跡できず、新しいトラフィックを破棄することがあります。両方の値を監視してください。
sysctl net.netfilter.nf_conntrack_count
sysctl net.netfilter.nf_conntrack_maxメモリ使用量を計算せずに最大値を引き上げても、リソース制限を移動するだけです。大量のフローを扱うシステムでは、タイムアウトの見直し、トラフィックの検証、容量監視も必要です。
ネットワークアドレス変換 #
ステートフル NAT は、追跡対象フローの最初のパケットから変換バインディングを作成します。後続のパケットは、すべての NAT ルールを再評価するのではなく、conntrack の状態を使用します。したがって、フィルタリングは NAT チェーンではなく filter チェーンに配置します。
ルーターでは、次のように宛先 NAT と送信元 NAT を定義できます。
table inet nat {
chain prerouting {
type nat hook prerouting priority dstnat
tcp dport 443 dnat ip to 192.0.2.20:8443
}
chain postrouting {
type nat hook postrouting priority srcnat
oifname "wan0" masquerade
}
}inet ファミリーでの NAT には Linux 5.2 以降が必要です。古いカーネルでは、ip と ip6 の NAT テーブルを分ける必要があります。
- DNAT は通常、転送ルートが選択される前の
preroutingで実行されます。 - SNAT と masquerade は通常、ルート選択後の
postroutingで実行されます。 redirectはトラフィックをローカルマシンへ送ります。masqueradeは出力インターフェースから送信元アドレスを導出します。そのアドレスが変化する可能性がある場合に適しています。
NAT はセキュリティポリシーではありません。変換されたパケットも、該当する input または forward フィルタリングポリシーを通過する必要があります。
セット、マップ、連結 #
iptables ルールセットでは、反復する値を線形ルールとして表現するか、別の ipset 機能に依存することがよくあります。nftables は型付きデータ構造を統合します。
set web_ports {
type inet_service
elements = { 80, 443 }
}
map service_targets {
type inet_service : ipv4_addr
elements = {
80 : 192.0.2.10,
443 : 192.0.2.20
}
}- セットはキーが存在するかを返します。
- マップはキーに対応する値を返します。
- 判定マップは
accept、drop、jump chainなどの判定を返します。 - 連結は、送信元アドレスと宛先ポートなどのフィールドを 1 つの複合キーに結合します。
名前付きセットは、それを参照するすべてのルールを再構築せずに更新できます。インターバルセットは、アドレス範囲とポート範囲を効率よく表現します。マップと連結は、ほぼ同一のルールが長く連続する状態を減らします。検索によってデータまたは制御フローを直接選択できるためです。
カウンター、ロギング、トレース #
ルールは、カウンターステートメントを含むか、名前付きカウンターを参照する場合にのみトラフィックをカウントします。
tcp dport 22 counter acceptログは終端しないステートメントであるため、1 つのルールでログ記録と判定を同時に行えます。
ct state invalid log prefix "invalid: " limit rate 10/second dropパケットをトリガーとするロギングは CPU、ストレージ、ロギングサービスの容量を消費する可能性があるため、レート制限が必要です。
nftables のトレースは、選択したパケットについてルールの通過を記録します。範囲を限定したルールでトレースを有効にします。
meta l4proto tcp tcp dport 443 meta nftrace set 1その後、イベントを監視します。
nft monitor trace診断後はトレースルールを削除してください。広範なトレースは大量のイベントストリームを生成する可能性があります。
iptables からの移行 #
移行には、異なる 2 つの目標があります。
- 互換性移行は、iptables 構文を維持したままカーネルバックエンドを変更します。
iptables-nft-restoreは iptables-save ファイルをnf_tablesにロードします。 - ネイティブ移行は、ポリシーを変換した後、nftables 構文で再設計します。
いずれかのバックエンドを変更する前に、アクティブなルール所有者をすべて調査してください。
iptables --version
iptables-legacy-save
ip6tables-legacy-save
nft list ruleset変換ツールは、ライブのルールセットを変更しません。
iptables-legacy-save > iptables-v4.save
ip6tables-legacy-save > iptables-v6.save
iptables-restore-translate -f iptables-v4.save > rules-v4.nft
ip6tables-restore-translate -f iptables-v6.save > rules-v6.nft変換は出発点にすぎません。古い構造を保持するため、出力を次の観点で確認してください。
- サポートされていない、または部分的にしかサポートされない xtables 拡張。
- 1 つの
inetルールに統合できる、重複した IPv4 と IPv6 のルール。 - セット、マップ、判定マップにすべき反復ルール。
- チェーンポリシー、カウンター、ログのレート、NAT の動作。
- マーク、ルーティングポリシー、インターフェース、名前空間、コネクショントラッキングヘルパーへの依存。
- コンテナエンジン、仮想マシンマネージャー、侵入防止ツール、ファイアウォールフロントエンドが動的に挿入するルール。
iptables-nft は、変更がアトミックで nft list ruleset を通じて確認できるため、移行インターフェースとして有用です。ただし、xtables のセマンティクスを表現しており、一部の拡張はネイティブな nftables 式になるのではなく、nft_compat 経由でラップされたままになることがあります。
共存とルール所有権 #
iptables-legacy と nftables を、同じトラフィックの独立した管理者として運用しないでください。レガシーの x_tables ルールと nf_tables ルールは、カーネル内で別々のルールセットです。どちらのコマンドビューも完全なポリシーを表示しません。パケットが両方を通過することで、ルールの欠落や矛盾に見える障害が発生する可能性があります。
iptables-nft と nft は nf_tables バックエンドを共有しますが、ストレージの共有は所有権の共有を意味しません。ネイティブコマンドで互換性生成チェーンを編集すると、それを作成したツールの前提に違反する可能性があります。
所有権を明示的に割り当ててください。
- ホストファイアウォールをロードするサービスを 1 つにする。
- 対応している場合は、オーケストレーションシステムに個別のテーブルを割り当てる。
- firewalld、コンテナエンジン、Kubernetes コンポーネント、仮想マシンマネージャー、VPN ソフトウェア、ban ツールがルールを追加するか確認する。
- 別のコンポーネントが所有するテーブルを flush しない。
- 競合するブートスクリプトではなく、ディストリビューションの nftables サービスまたは選択したファイアウォールマネージャーを通じてルールを永続化する。
バックエンドのサポートは、ソフトウェアのバージョンとディストリビューションのパッケージングによって異なります。ツール名からレガシーまたはネイティブ nftables の動作を仮定せず、デプロイされたシステムを確認してください。
プロジェクトの状況 #
nftables は、Linux のアップストリームカーネルでバージョン 3.13 以降から利用できます。Netfilter プロジェクトは、2018 年 6 月以降、元の xtables/setsockopt ツールをレガシーと見なしていますが、nftables バックエンド上で iptables 互換ツールを提供し続けています。
したがって、現在の iptables パッケージには、既存のレガシーデプロイメントを維持する役割と、nf_tables への互換性パスを提供する役割があります。カーネル、nftables、iptables のバージョンはディストリビューション固有のままです。ディストリビューションのリリース名に依存せず、デプロイされたバックエンドと必要な機能のバージョンを確認してください。
運用チェックリスト #
- リモートホストの input ポリシーを変更する前に、帯域外コンソールを利用できるようにする。
- 適用前に
nft --check --fileでファイルを検証する。 - 順序付けられたシェルシーケンスを実行するのではなく、
nft --fileで完全な変更をロードする。 - デフォルト拒否ポリシーを適用する前に、ループバックと管理アクセスを確立する。
- 各フックにあるすべてのベースチェーンと優先度を確認する。
- カウンター、ログ、conntrack 容量、ルールセットの変更を監視する。
- NAT、パケットフィルタリング、ルーティング、トラフィック制御は、互いに置き換えられない別々のポリシーとして扱う。
- 各テーブルに対して権威を持つ所有者を 1 つにし、動的に管理されるテーブルを文書化する。
新しい Linux ファイアウォールを設計する場合、ネイティブ nftables は、明確なモデル、デュアルスタックの inet ルール、統合されたセットとマップ、トランザクション更新を提供します。iptables 互換性は既存アプリケーションにとって有用ですが、新しいルールセットのアーキテクチャではなく、移行メカニズムとして扱うべきです。
参考資料 #
- Netfilter: nftables Project
- nftables Wiki: Netfilter Hooks
- nftables Wiki: Configuring Tables
- nftables Wiki: Configuring Chains
- nftables Wiki: nftables Families
- nftables Wiki: Connection Tracking
- nftables Wiki: Network Address Translation
- nftables Wiki: Sets
- nftables Wiki: Maps
- nftables Wiki: Verdict Maps
- nftables Wiki: Concatenations
- nftables Wiki: Atomic Rule Replacement
- nftables Wiki: Ruleset Tracing
- nftables Wiki: Moving from iptables to nftables
xtables-nft(8)xtables-translate(8)
コメント
GitHub で閲覧・コメントする(投稿にはログインが必要です)