はじめに:なぜ今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接続が切れてサーバーにアクセスできなくなる悲劇を防げます。
nft -c -fで構文チェック- 別のSSHセッションを開いた状態で変更を適用(ロックアウト防止)
- タイムアウト付きのルール適用を検討(
atコマンドで一定時間後にルールをリセット) - 変更後、すべてのサービスへの接続を確認
# 安全なテスト方法: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}")
実践チェックリスト:本番環境への展開
最後に、本番環境にデプロイする前のチェックリストです。全部チェックが入ってから公開する、くらいの気持ちで使ってください。
- デフォルトポリシーがdropになっていること(input/forwardチェーン)
- ループバックインターフェースが許可されていること
- 確立済みコネクション(ct state established,related)が許可されていること
- 無効なパケット(ct state invalid)がドロップされていること
- SSHが信頼済みIPからのみアクセス可能で、レート制限が適用されていること
- ICMPがレート制限付きで許可されていること
- 不要なポートがすべて閉じていること
- Fail2Banがnftablesネイティブモードで動作していること
- ドロップされたパケットのログが専用ファイルに記録されていること
- ログローテーションが設定されていること
- ルールが永続化され、再起動後も維持されること
- 設定のバックアップが取得されていること
よくある質問(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を確認する運用を確立しておくと安心です。