nftablesでLinuxファイアウォールを固める:iptables移行からFail2Ban連携まで実践ガイド

nftablesによるLinuxファイアウォールのハードニングを実践的に解説。iptablesからの移行手順、deny-allベースライン構築、レート制限によるDDoS対策、Fail2BanとのネイティブIPS連携、ログ監視設定まで、本番環境ですぐ使えるコード例付きです。

はじめに:なぜ今nftablesなのか

2026年現在、Linuxのパケットフィルタリング基盤が大きく変わりつつあります。長年Linuxファイアウォールの代名詞だったiptables、正直もう「レガシー」と呼んでも差し支えない状況です。後継のnftablesがRHEL 8以降、Debian 10以降、Ubuntu 20.04以降、Fedora 18以降といった主要ディストリビューションすべてでデフォルトになっており、新規でiptablesベースのファイアウォールを組むのは公式にも推奨されていません。

そして2025年には、Kubernetes 1.29でkube-proxyのnftablesモードがアルファとして登場し、現在はベータに到達しています。30,000サービス規模のクラスタで、nftablesのp99レイテンシがiptablesのp01レイテンシを上回ったという報告もあります。ちょっと衝撃的な数字ですよね。

さらにAzure Linux 3.0がAppArmorサポートを廃止してSELinuxを推奨するなど、Linux基盤全体でモダンなセキュリティツールへの切り替えが加速しています。

この記事では、nftablesの基本からセキュリティハードニング、iptablesからの移行、レート制限によるDDoS対策、Fail2Ban連携、ログ監視設定まで、本番サーバーですぐ使える実践的な設定を一通りカバーします。では、さっそく見ていきましょう。

nftables vs iptables:何が違うのか

アーキテクチャの根本的な違い

iptablesとnftablesの最大の違いは、パケット処理のアーキテクチャにあります。iptablesは線形処理(O(n))でルールを順番に評価していくのに対し、nftablesは最適化されたルックアップ(O(log n))を使います。ルール数が数百、数千と増えていくと、この差は無視できません。

主要な違いをざっとまとめます。

  • 統一フレームワーク:iptablesではiptables、ip6tables、arptables、ebtablesと別々のツールが必要でしたが、nftablesならnftコマンド1つでIPv4/IPv6/ARP/ブリッジすべてを管理できます
  • テーブルとチェーンの柔軟性:iptablesには事前定義されたテーブルとチェーンがありましたが、nftablesでは必要なものだけを明示的に定義します。未使用のベースチェーンがパフォーマンスに悪影響を与える問題も解消されました
  • 1ルールで複数アクション:iptablesでは2つのルールが必要だった「ログ記録+ドロップ」が、nftablesではlog dropの1行で完結します(地味にうれしい)
  • アトミックな更新:Netlinkトランザクションによるアトミックなルール更新をサポート。大規模なルールセット変更時の競合状態を防げます
  • 組み込みセット・マップ:iptablesでは外部ツールipsetが必要でしたが、nftablesはセットとマップをネイティブに持っています

iptablesからの移行手順

既存のiptablesルールをnftablesに移行するなら、iptables-translateツールがかなり役立ちます。

# 個別ルールの変換
iptables-translate -A INPUT -p tcp --dport 22 -j ACCEPT

# 出力例:
# nft add rule ip filter INPUT tcp dport 22 counter accept

# ルールセット全体の変換
iptables-save | iptables-restore-translate -f /etc/nftables-migrated.conf

注意点:iptables-legacyとnftablesを同時に使うと、ルールセットがおかしくなります。移行期間中はiptables-nft互換レイヤーを使うか、nftablesに完全に切り替えてください。混在は本当にトラブルの元です。

nftablesのインストールと基本設定

インストール

まずはインストールから。主要ディストリビューション別に示します。

# Debian / Ubuntu
sudo apt update && sudo apt install nftables
sudo systemctl enable --now nftables.service

# RHEL / AlmaLinux / Rocky Linux
sudo dnf install nftables
sudo systemctl enable --now nftables.service

# Arch Linux
sudo pacman -S nftables
sudo systemctl enable --now nftables.service

基本概念:テーブル・チェーン・ルール

nftablesの設定は3つの階層で構成されています。

  • テーブル(Table):チェーンやルールを格納する名前空間です。アドレスファミリー(ip、ip6、inet、arp、bridge)を指定します
  • チェーン(Chain):ルールのリスト。「ベースチェーン」はネットワークスタックからのエントリポイント、「レギュラーチェーン」はジャンプターゲットとして使います
  • ルール(Rule):マッチ条件とアクション(accept、drop、reject等)を定義するものです

とくに覚えておきたいのがinetファミリー。これを使えばIPv4とIPv6の両方を1つのテーブルで管理でき、ルールの重複を避けられます。個人的に、これだけでもnftablesに乗り換える価値があると思っています。

基本コマンド一覧

# 現在のルールセット全体を表示
sudo nft list ruleset

# 特定テーブルの表示
sudo nft list table inet filter

# 特定チェーンの表示
sudo nft list chain inet filter input

# ルールセット全体をクリア
sudo nft flush ruleset

# 設定ファイルからルールを読み込み
sudo nft -f /etc/nftables.conf

# 設定を適用せずにバリデーションのみ実行
sudo nft -c -f /etc/nftables.conf

セキュアなファイアウォール設計:deny-allベースライン

完全なハードニング設定例

ファイアウォール設計の鉄則は「デフォルト拒否(deny-all)」です。すべてのトラフィックをドロップし、必要な通信だけを明示的に許可する。これに尽きます。

以下に本番サーバー向けの設定例を示します。長いですが、そのままコピーして使える内容にしています。

#!/usr/sbin/nft -f

# 既存ルールのフラッシュ
flush ruleset

table inet filter {

    # === 信頼済みIPセット ===
    set trusted_ssh {
        type ipv4_addr
        flags interval
        elements = {
            192.168.1.0/24,       # 管理ネットワーク
            10.0.0.0/8            # VPNネットワーク
        }
    }

    # === INPUTチェーン(受信トラフィック) ===
    chain input {
        type filter hook input priority filter; policy drop;

        # ループバックインターフェースを許可
        iif "lo" accept

        # 確立済み・関連コネクションを許可
        ct state established,related accept

        # 無効なパケットをドロップ
        ct state invalid counter drop

        # ICMP(ping)をレート制限付きで許可
        ip protocol icmp icmp type {
            echo-request,
            destination-unreachable,
            time-exceeded
        } limit rate 10/second burst 20 packets accept

        # ICMPv6 を許可(IPv6環境で必須)
        ip6 nexthdr icmpv6 icmpv6 type {
            echo-request,
            destination-unreachable,
            nd-neighbor-solicit,
            nd-neighbor-advert,
            nd-router-solicit,
            nd-router-advert
        } accept

        # SSH:信頼済みIPからのみ許可 + レート制限
        tcp dport 22 ip saddr @trusted_ssh ct state new limit rate 5/minute burst 3 packets accept

        # HTTP/HTTPS を許可
        tcp dport { 80, 443 } ct state new accept

        # その他のドロップされたパケットをログ記録
        counter log prefix "[nft-drop-input] " level warn drop
    }

    # === FORWARDチェーン(転送トラフィック) ===
    chain forward {
        type filter hook forward priority filter; policy drop;

        # 明示的に転送を許可する場合のみルールを追加
        counter log prefix "[nft-drop-forward] " level warn drop
    }

    # === OUTPUTチェーン(送信トラフィック) ===
    chain output {
        type filter hook output priority filter; policy accept;

        # ループバック許可
        oif "lo" accept

        # 確立済みコネクション許可
        ct state established,related accept

        # DNS、HTTP/S、NTP、SMTP を許可
        tcp dport { 53, 80, 443, 25, 587 } accept
        udp dport { 53, 123 } accept
    }
}

設定のポイント

上記の設定で押さえておきたいポイントをまとめます。

  • inetファミリーでIPv4/IPv6の両方をカバー
  • conntrack(ct state)で確立済みコネクションを自動許可。ステートフルフィルタリングの基本です
  • 名前付きセット(trusted_ssh)でSSHアクセス元を一元管理。IPの追加・削除が楽になります
  • ICMPはレート制限付きで許可し、Flood攻撃を防止
  • ドロップしたパケットはログ記録。何が拒否されているか見えないと、トラブルシューティングが地獄になります
  • policy dropで、明示的に許可していないトラフィックはすべて拒否

レート制限とDDoS対策

接続レート制限の実装

nftablesのレート制限は、ブルートフォース攻撃やDDoSの緩和にかなり効果的です。とくに動的ブラックリストの仕組みは、iptables時代にはipsetと組み合わせないと実現できなかったことがネイティブにできるようになりました。

table inet rate_limiter {

    # 動的ブラックリストセット(5分後に自動削除)
    set blacklist_v4 {
        type ipv4_addr
        flags dynamic, timeout
        timeout 5m
    }

    set blacklist_v6 {
        type ipv6_addr
        flags dynamic, timeout
        timeout 5m
    }

    chain input {
        type filter hook input priority filter - 10; policy accept;

        # ブラックリストに登録されたIPからのトラフィックをドロップ
        ip saddr @blacklist_v4 counter drop
        ip6 saddr @blacklist_v6 counter drop

        # 1分間に10接続以上の新規TCP接続をブラックリストに追加
        ct state new tcp flags syn limit rate over 10/minute burst 20 packets add @blacklist_v4 { ip saddr } counter drop
    }
}

SYN Flood対策:Synproxyの活用

SYN Flood攻撃に対しては、nftablesのsynproxy機能が有効です。synproxyはTCPの3ウェイハンドシェイクをカーネルレベルで処理し、conntrackリソースの枯渇を防ぎます。まずはカーネルパラメータの設定から。

# カーネルパラメータの設定
sudo sysctl -w net.ipv4.tcp_syncookies=1
sudo sysctl -w net.ipv4.tcp_timestamps=1

# /etc/sysctl.d/99-synproxy.conf に永続化
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_timestamps = 1
# synproxy設定例
table ip synproxy_table {
    chain prerouting {
        type filter hook prerouting priority raw; policy accept;
        tcp dport 80 tcp flags syn notrack
    }

    chain input {
        type filter hook input priority filter; policy accept;
        tcp dport 80 ct state invalid,untracked synproxy mss 1460 wscale 7 timestamp sack-perm
        ct state invalid drop
    }
}

サービス別レート制限

サービスごとに適切なレート制限を設定しておくと安心です。以下は目安となる設定例です。

# SSH:1分間に3回まで(ブルートフォース対策)
tcp dport 22 ct state new limit rate 3/minute burst 5 packets accept

# HTTP/HTTPS:1秒間に50リクエストまで
tcp dport { 80, 443 } ct state new limit rate 50/second burst 100 packets accept

# DNS:UDPフラッド対策
udp dport 53 limit rate 20/second burst 40 packets accept

Fail2BanとnftablesのネイティブIPS連携

なぜFail2Ban + nftablesなのか

Fail2Banはログファイルを監視し、不正アクセスを検知するとファイアウォールルールを動的に追加して攻撃元IPをブロックする侵入防止ツールです。従来はiptablesと組み合わせるのが定番でしたが、nftablesネイティブの連携にすることで、セットの動的更新が効率的に動作します。

設定は5ステップで完了します。

ステップ1:nftables用テーブルの作成

# /etc/nftables/fail2ban.conf
#!/usr/sbin/nft -f
table ip fail2ban {
    chain input {
        type filter hook input priority filter - 1; policy accept;
    }
}

ポイントは優先度をfilter - 1にすること。これにより、メインのファイアウォールルールよりも先にFail2Banのルールが評価されます。

ステップ2:メイン設定にインクルード

# /etc/nftables.conf に以下を追加
include "/etc/nftables/fail2ban.conf"

ステップ3:Fail2Banのjail設定

# /etc/fail2ban/jail.local
[DEFAULT]
banaction = nftables
banaction_allports = nftables[type=allports]

[sshd]
enabled = true
backend = systemd
maxretry = 3
bantime = 3600
findtime = 600

[recidive]
enabled = true
backend = auto
logpath = /var/log/fail2ban.log
maxretry = 2
bantime = 86400
banaction = nftables-allports

ステップ4:nftablesアクション設定のカスタマイズ

# /etc/fail2ban/action.d/nftables-common.local
[Init]
nftables_family = ip
nftables_table  = fail2ban
blocktype       = drop
nftables_set_prefix =

ステップ5:systemdによるサービス連携

nftablesが再起動した際にFail2Banのルールが自動的に再適用されるようにします。これを忘れると、サーバー再起動後にFail2Banのブロックが無効になるので要注意。

# systemdオーバーライドの作成
sudo mkdir -p /etc/systemd/system/fail2ban.service.d

cat << EOF | sudo tee /etc/systemd/system/fail2ban.service.d/override.conf
[Unit]
Requires=nftables.service
PartOf=nftables.service

[Install]
WantedBy=multi-user.target nftables.service
EOF

sudo systemctl daemon-reload
sudo systemctl restart fail2ban

動作確認

設定が完了したら、以下のコマンドで動作を確認しましょう。

# Fail2Banのステータス確認
sudo fail2ban-client status sshd

# nftablesでFail2Banのルールを確認
sudo nft list table ip fail2ban

# バンされたIPの確認
sudo nft list set ip fail2ban f2b-sshd

ログ監視と可視化

nftablesのログ設定

nftablesのログはlogキーワードでパケット情報をカーネルログに出力します。デフォルトではsyslog(/var/log/kern.log/var/log/messages)に混在するので、専用のログファイルに分離しておくことを強くおすすめします。他のカーネルログに埋もれると、いざという時に探すのが大変です。

rsyslogによるログ分離

# /etc/rsyslog.d/10-nftables.conf
:msg,contains,"[nft-drop-input]" -/var/log/nftables/input-drop.log
:msg,contains,"[nft-drop-forward]" -/var/log/nftables/forward-drop.log
:msg,contains,"[nft-drop-input]" stop
:msg,contains,"[nft-drop-forward]" stop
# ログディレクトリの作成
sudo mkdir -p /var/log/nftables
sudo systemctl restart rsyslog

logrotateによるログローテーション

ファイアウォールログは放っておくとあっという間にディスクを圧迫します。logrotateの設定を忘れずに。

# /etc/logrotate.d/nftables
/var/log/nftables/*.log {
    daily
    rotate 90
    compress
    delaycompress
    missingok
    notifempty
    create 0640 root adm
    postrotate
        /usr/lib/rsyslog/rsyslog-rotate
    endscript
}

高度なログ:ulogd2によるNFLOGの活用

より詳細なパケットログが必要な場合は、ulogd2とNFLOGの組み合わせを検討してください。ulogd2はユーザー空間のログデーモンで、パケットログをJSON形式やPostgreSQLに出力できるのが魅力です。

# nftablesルールでNFLOGを使用
nft add rule inet filter input tcp dport 22 ct state new log prefix "[nft-ssh] " group 0 accept

# ulogd2のインストール
sudo apt install ulogd2        # Debian/Ubuntu
sudo dnf install ulogd          # RHEL系

Grafanaでの可視化

モダンな監視環境では、nftablesのログをPromtail → Loki → Grafanaのパイプラインで可視化するのがおすすめです。ドロップされたパケットの送信元IP、ポート、プロトコルをダッシュボードで一覧表示すれば、攻撃の傾向をリアルタイムで把握できます。実際に導入してみると、「こんなにスキャンされてたのか」と驚くはずです。

設定の永続化とバックアップ

ルールの永続化

nftablesのルールは/etc/nftables.confに保存すれば永続化されます。nftables.serviceが起動時にこのファイルからルールを読み込む仕組みです。シンプルでわかりやすいですね。

# 現在のルールセットを設定ファイルに保存
sudo nft list ruleset | sudo tee /etc/nftables.conf

# 設定ファイルのバリデーション
sudo nft -c -f /etc/nftables.conf

# サービスの有効化
sudo systemctl enable nftables.service

バックアップとバージョン管理

ファイアウォール設定は重要なインフラ設定です。バックアップは必須ですし、できればGitで管理しておきたいところです。「あのとき何を変えたっけ?」を後から追えるのは、障害対応時に本当に助かります。

# バックアップの作成
sudo nft list ruleset > /root/nftables-backup-$(date +%Y%m%d).conf

# Git管理の例
sudo git -C /etc init 2>/dev/null
sudo git -C /etc add nftables.conf nftables/
sudo git -C /etc commit -m "nftables: update firewall rules"

変更前のテスト手順

本番サーバーでファイアウォールルールを変更するときは、慎重にやりましょう。以下の手順を守れば、SSH接続が切れてサーバーにアクセスできなくなる悲劇を防げます。

  1. nft -c -fで構文チェック
  2. 別のSSHセッションを開いた状態で変更を適用(ロックアウト防止)
  3. タイムアウト付きのルール適用を検討(atコマンドで一定時間後にルールをリセット)
  4. 変更後、すべてのサービスへの接続を確認
# 安全なテスト方法:5分後に元のルールを復元するフェイルセーフ
sudo cp /etc/nftables.conf /tmp/nftables-rollback.conf
echo "sudo nft -f /tmp/nftables-rollback.conf" | sudo at now + 5 minutes

# 新しいルールを適用
sudo nft -f /etc/nftables-new.conf

# 問題なければ、atジョブをキャンセル
sudo atrm $(atq | awk "{print $1}")

実践チェックリスト:本番環境への展開

最後に、本番環境にデプロイする前のチェックリストです。全部チェックが入ってから公開する、くらいの気持ちで使ってください。

  1. デフォルトポリシーがdropになっていること(input/forwardチェーン)
  2. ループバックインターフェースが許可されていること
  3. 確立済みコネクション(ct state established,related)が許可されていること
  4. 無効なパケット(ct state invalid)がドロップされていること
  5. SSHが信頼済みIPからのみアクセス可能で、レート制限が適用されていること
  6. ICMPがレート制限付きで許可されていること
  7. 不要なポートがすべて閉じていること
  8. Fail2Banがnftablesネイティブモードで動作していること
  9. ドロップされたパケットのログが専用ファイルに記録されていること
  10. ログローテーションが設定されていること
  11. ルールが永続化され、再起動後も維持されること
  12. 設定のバックアップが取得されていること

よくある質問(FAQ)

Q1. iptablesからnftablesへの移行は必須ですか?

今すぐ必須ではありませんが、強く推奨します。主要ディストリビューションはすべてnftablesをデフォルトにしていますし、iptablesコマンドを叩いても内部的にはnftablesに変換されているケースがほとんどです。新規構築ではnftables一択で、既存環境も計画的に移行を進めるべきです。iptablesの開発は事実上止まっており、新機能はnftablesにしか追加されません。

Q2. firewalldとnftablesはどう使い分けますか?

firewalldはゾーンベースの動的ファイアウォール管理デーモンで、バックエンドにnftablesを使っています。一般的なサーバー管理ならfirewalldで十分ですが、ルールを細かく制御したい場合やパフォーマンスチューニングが必要なら、nftablesを直接使った方がいいでしょう。RHEL/CentOS/Fedora系ではfirewalldがデフォルトですが、直接nftablesを使うことも問題ありません。

Q3. SSHがロックアウトされた場合の復旧方法は?

一番確実なのは、本記事で紹介したatコマンドによるフェイルセーフを事前に仕込んでおくことです。すでにロックアウトされてしまった場合は、(1)VPSプロバイダーのコンソールアクセスからログイン、(2)物理サーバーならKVM/IPMIコンソールからアクセス、(3)レスキューモードで起動して/etc/nftables.confを修正、という方法があります。予防策として、ルール変更時は必ず別のSSHセッションを維持しておいてください。

Q4. DockerやKubernetesとの共存は可能ですか?

可能ですが、注意が必要です。Dockerはデフォルトでiptables(iptables-nft互換レイヤー)を使ってネットワークを操作します。Kubernetes 1.29以降ではkube-proxyのnftablesモード(ベータ)が利用でき、カーネル5.13以上で大幅なパフォーマンス向上が見込めます。Docker環境でnftablesを使う場合は、Dockerが作成するチェーンとの競合に気をつけて、ユーザー定義ネットワークを活用するようにしましょう。

Q5. リモートで安全にテストする方法はありますか?

あります。nft -c -fで構文チェックを行い、atコマンドでフェイルセーフを仕込んでから適用する、という手順が鉄板です。AnsibleやTerraformなどの構成管理ツールを使う場合は、ロールバック機構を組み込むことをおすすめします。nft list rulesetの出力を定期的にバージョン管理して、変更のdiffを確認する運用を確立しておくと安心です。

著者について Editorial Team

Our team of expert writers and editors.