Debian stretchからbusterにアップグレードした環境でiptablesからnftablesに乗り換える

Debian 10ではパケットフィルタリングまわりの設定に使用するフレームワークがnftablesに変更されたのだが、この変更が「既に運用中の『iptablesを使用しているDebian 9』」をアップグレードする際にどのような影響を及ぼすのか、メモを残しておく。

Debian LTSでシステムを運用している場合、2022-06-30にDebian 9 LTSのサポートが終了するので、切羽詰まってこれからDebian 10に移行する私みたいな人もいるだろう)

先に要約を書いておく:

  • 前提条件:
    • /etc/iptables直下にrules.v4などの名前でiptablesのルールファイルを置き、netfilter-persistentを使用して起動時にパケットフィルタリングの設定を適用する構成の、Debian 9のシステムを運用している。
    • このシステムにDebian 10をアップグレード・インストールする。
  • 設定ファイルまわりを極力変更したくない人向け:
    • アップグレード時に特に何もする必要はない。
  • アップグレードを機に、パケットフィルタリングの設定管理をiptablesからnftablesに移行したい人向け:
    • おそらくアップグレード完了の時点でnftablesのパッケージはインストール済みのはず。
    • おそらくルールファイルの移行にiptables-restore-translateコマンドは不要。
    • systemdのサービス(netfilter-persistent.servicenftables.service)の切り替えに留意すること。

本題。

Debian 10のリリースノートの記述には、以下のようなことが書かれている。

  • パケットフィルタリングの既定のフレームワークがnftablesに変更された。
  • iptables系のコマンドは、既定では「内部的にnftablesを使用する版」になっている。
    • update-alternativesを使用して「旧来のx_tablesを使用する版」に変更することが可能。

今までiptablesを使用してきた環境をDebian 10にアップグレードした場合、「起動時にnetfilter-persistentiptablesのルールファイルが読み込まれる」という挙動は今まで通りとなる。ただし、使用されるのはiptables系のコマンドだが、内部ではnftablesのフレームワークが用いられている。

つまりパケットフィルタリング設定のフロントエンドはiptablesのまま、内部の処理だけ変更されている訳だ。

だから実用的には、実のところパケットフィルタリングまわりに手を付ける必要はない。今まで通りにiptablesでフィルタリング・ルールを書いておけば、ちゃんと機能する。

一方で、この機会にパケットフィルタリング設定の操作までnftables用のインタフェースに置き換えたいと考える人もいるだろう。

Debian 10にアップグレードして再起動した際、起動時にnetfilter-persistent経由で「内部的にnftablesを使用する版」のiptablesのコマンドにてパケットフィルタリングの設定が適用された状態になっている。

なので、この状態で深く考えずにいきなり以下のような手順で作業することで、nftables用のパケットフィルタリングのルールファイルを生成できる。何しろ元データは起動時にnetfilter-persistent経由で読み込み済みな訳なので……。

# 念のため元のルールファイルを残しておく。
sudo mv /etc/nftables.conf /etc/nftables.conf.old
# nftables用のルールファイルを生成。
printf '%s\n\n%s\n\n' '#!/usr/sbin/nft -f' 'flush ruleset' | sudo tee /etc/nftables.conf >/dev/null
sudo /usr/sbin/nft -s list ruleset | sudo tee -a /etc/nftables.conf >/dev/null
sudo chmod 755 /etc/nftables.conf

Debian管理者ハンドブックnftables wikiのルールファイル移行に関する記述を参考にすると、以下のような手順になりそうな気がするが、これは間違いである。

# iptablesのルールファイルをnft用のコマンドファイルに変換。
sudo /usr/sbin/iptables-restore-translate -f /etc/iptables/rules.v4 >ruleset.nft
# コマンドファイルを適用。
sudo /usr/sbin/nft -f ruleset.nft
# nftables用のルールファイルを保存しておく。
sudo /usr/sbin/nft -s list ruleset | sudo tee /etc/nftables.conf >/dev/null

起動時にnftablesに設定が読み込まれた状態でnft -f ruleset.nftすることになるので、パケットフィルタリングのルールが二重に登録された変な状態のルールファイルになってしまう。

そんなことをしなくても、すでにフィルタリング・ルールは読み込まれているのだから、それをそのままnft -s list rulesetで出力すればよいのだ。

さて、ドキュメント類では微妙に書かれていないが、ルールファイルの移行以外でやるべきことが1つある。それはsystemdのサービスをnetfilter-persistent.serviceからnftables.serviceに切り替えることだ。

切り替えをしないと、せっかくルールファイルを/etc/nftables.confに移行しても、起動時の読み込み元が/etc/iptables/rules.v4のままになってしまう。後日、/etc/nftables.confの内容を変更した際に「再起動するとフィルタリングのルールが元に戻ってしまう」という謎の現象に悩まされることになるかもしれない。

切り替えの手順はこんな感じだろうか?

# netfilter-persistentを停止して無効化。
sudo systemctl stop netfilter-persistent.service
sudo systemctl disable netfilter-persistent.service
# 念のため手動起動も禁止しておく。
sudo systemctl mask netfilter-persistent.service

# nftables.serviceを有効化
sudo systemctl enable nftables.service

これで起動時に/etc/nftables.confのルールが読み込まれるようになる。

余談:iptablesのルールはフラットなので、機械的にnftablesのルールファイルに変換した結果もフラットになる。もしかしたら「よりnftablesらしい」ルールファイルに書き換えたくなるかもしれない。この時、IPアドレスの代わりにFQDNを使ってはならない。手元の環境では、システム起動後にnft -f /etc/nftables.confと手動で読み込ませればFQDNからIPアドレスに変換されるのだが、起動時だとルールの読み込み自体に失敗してしまい、ルール未設定の状態になってしまうようだ。