2 分で読了 #devops
このページの目次

nftables 操作マニュアル

nftables は Linux の次世代ファイアウォールフレームワークであり、iptables/ip6tables/arptables/ebtables を置き換えます。nft コマンドを使用して管理し、設定はアトミックにロードできます。Gentoo では、カーネルで CONFIG_NF_TABLES および関連モジュールを有効にする必要があります。

主要な概念: table (namespace, family ごとにグループ化), chain (ルールコンテナ, type/hook/priority に分類), rule (マッチ条件+アクション), set (IP/ポートの集合), verdict (accept/drop/reject/ジャンプ)。

状態の確認

# すべてのルールをリスト表示
nft list ruleset                          # 完全なルールセット (人間が読みやすい形式)
nft -a list ruleset                       # ハンドル番号付き (ルール削除・変更用)

# テーブル/チェーンごとに確認
nft list table inet filter                 # 特定のテーブルを表示
nft list chain inet filter input           # 特定のチェーンを表示
nft list table ip nat                      # IPv4 NAT テーブル

# sets / counters の確認
nft list sets                              # すべての名前付き集合
nft list counters                          # すべてのカウンター

# ルールセットの統計
nft --stateless list ruleset               # ステートオブジェクトを含まない (よりコンパクト)
nft list ruleset | wc -l                   # 規模の大まかな推定

基本ルール管理

# 一時的な変更 (再起動で消失, テスト用)
nft add rule inet filter input tcp dport 22 accept
nft delete rule inet filter input handle 5  # ハンドルで削除
nft flush chain inet filter input           # 1つのチェーンをクリア
nft flush ruleset                           # すべてのルールをクリア (!危険)

# ハンドルの確認
nft -a list chain inet filter input
# 出力例:  tcp dport 22 accept # handle 5

永続化とアトミックロード

# 現在のルールセットを保存
nft list ruleset > /etc/nftables.conf

# アトミックな置換 (推奨)
nft -f /etc/nftables.conf                  # 一括置換, 失敗時はロールバック

# 構文チェック (ロードしない)
nft -c -f /etc/nftables.conf

# systemd による自動ロード
systemctl enable nftables
systemctl restart nftables                  # /etc/nftables.conf からロード

一般的なテーブル/チェーン構造テンプレート

table inet filter {                        # inet = IPv4 + IPv6
    chain input {
        type filter hook input priority 0; policy drop;
        # lo を許可
        iif lo accept
        # 確立済み/関連接続を許可
        ct state established,related accept
        # SSH を許可
        tcp dport 22 accept
        # ICMPv6 を許可 (IPv6 で必須)
        ip6 nexthdr icmpv6 accept
    }
    chain forward {
        type filter hook forward priority 0; policy drop;
        ct state established,related accept
    }
    chain output {
        type filter hook output priority 0; policy accept;
    }
}

ルールの書き方

# マッチ条件
tcp dport {22, 80, 443}                    # ポート集合
ip saddr 192.168.1.0/24                    # ソース IP サブネット
ip daddr != 10.0.0.0/8                     # 宛先サブネット以外
iif eth0                                   # 入力インターフェース
oif wg0                                    # 出力インターフェース
ct state new                               # 新規接続
ct state established,related               # 確立済み/関連
tcp flags syn / syn,ack,rst                # SYN マッチ (新規接続要求)
meta l4proto {tcp, udp}                    # トランスポート層プロトコル
meta hour "09:00"-"18:00"                  # 時間によるマッチ
limit rate 10/second                       # レート制限
counter                                    # カウント (アクションは変更しない)
log prefix "SSH: "                         # ログ記録

# アクション
accept                                     # 許可
drop                                       # 破棄 (応答なし)
reject                                     # 拒否 (ICMP/RST を返す)
jump another_chain                         # カスタムチェーンへジャンプ
return                                     # カスタムチェーンから戻る
dnat to 192.168.1.100                      # 宛先 NAT
snat to 203.0.113.1                        # ソース NAT
masquerade                                 # ダイナミック SNAT (出口 IP が可変)
redirect to :8080                          # ローカルポートのリダイレクト

NAT / ポートフォワーディング

# テーブル定義
table ip nat {
    chain prerouting {
        type nat hook prerouting priority dstnat; policy accept;
    }
    chain postrouting {
        type nat hook postrouting priority srcnat; policy accept;
    }
}

# DNAT (ポートフォワーディング, 外部→内部)
nft add rule ip nat prerouting iif eth0 tcp dport 8443 dnat to 192.168.1.100:443

# SNAT (出口の統一 IP)
nft add rule ip nat postrouting oif eth0 snat to 203.0.113.1

# MASQUERADE (ダイナミック IP 出口, 例: DHCP インターフェース)
nft add rule ip nat postrouting oif eth0 masquerade

# ポートリダイレクト (ローカル 80 → 8080)
nft add rule ip nat prerouting tcp dport 80 redirect to :8080

Sets (集合, 効率的な一括マッチ)

# 名前付き集合の定義
nft add set inet filter blackhole { type ipv4_addr\; }   # シェルではセミコロンをエスケープ必要
# または設定ファイル内で:
#   set blackhole { type ipv4_addr; }

# 要素の動的追加/削除
nft add element inet filter blackhole { 10.10.10.10, 10.10.10.11 }
nft delete element inet filter blackhole { 10.10.10.10 }

# ルールでの使用
# ip saddr @blackhole drop

# タイムアウト付きの集合 (自動期限切れ)
# set ratelimit { type ipv4_addr; timeout 1h; }
# ip saddr @ratelimit counter drop

# 集合のタイプ:
# ipv4_addr / ipv6_addr          IP アドレス
# ipv4_addr . inet_service       IP+ポートの組み合わせ
# ifname                         インターフェース名
# mark                           接続マーク

運用操作

# 指定位置へのルール挿入 (デフォルトは末尾追加)
nft insert rule inet filter input position 3 tcp dport 8080 accept

# ルールの置換
nft replace rule inet filter input handle 7 tcp dport 2222 accept

# ルールのコメント
# ファイル内:  tcp dport 22 accept comment "SSH access"

# カウンターのリセット
nft reset counters

# リアルタイム監視
nft monitor                              # ルールセットの変更を監視

# デバッグ
nft --debug=netlink list ruleset         # netlink メッセージを表示
nft --debug=scanner -f rules.conf        # 字句解析を表示

一般的なシナリオ

# SSH 爆破攻撃対策 (新規接続のレートを制限)
# tcp dport 22 ct state new limit rate 4/minute accept
# tcp dport 22 ct state new drop

# 特定の IP のみポートアクセスを許可
# ip saddr {10.0.0.1, 10.0.0.2} tcp dport 5432 accept
# tcp dport 5432 drop

# 透過プロキシ (TPROXY, mihomo/v2ray と併用必要)
# table ip mangle {
#     chain prerouting { type filter hook prerouting priority mangle; }
# }
# meta l4proto tcp ip daddr != 127.0.0.0/8 tproxy to :12345

# Docker ユーザーへの注意
# Docker は独自の iptables ルールを挿入するため、nftables と混在させると順序が乱れる可能性があります。
# 推奨: iptables のみを使用 (Docker 互換モード)、または nftables ルールが Docker より先にロードされることを確認
# 確認方法: nft list ruleset | grep -i docker
# Docker の nftables サポート: /etc/docker/daemon.json → "iptables": false

移行メモ (iptables → nft)

# 現在の iptables ルールを表示
iptables-save

# 自動翻訳 (完璧ではありませんが参考になります)
iptables-translate -A INPUT -p tcp --dport 22 -j ACCEPT
# 出力: nft add rule ip filter INPUT tcp dport 22 counter accept

# 一括翻訳 (完全なルールセット)
iptables-restore-translate < <(iptables-save)