Home > ブログ > nftablesによるファイアウォール設定

ブログ

nftablesによるファイアウォール設定

CentOS8やRedHat Enterprise Linux8ではiptablesは後継のnftablesに置き換えられました。iptables系のコマンドは依然として存在していますが、xtables-nft-multiという別のコマンドにリンクされています。

iptablesの実体

# ls -l /sbin/iptables
lrwxrwxrwx 1 root root 17  1月 29  2021 /sbin/iptables -> xtables-nft-multi
# ls -l /sbin/ip6tables
lrwxrwxrwx 1 root root 17  1月 29  2021 /sbin/ip6tables -> xtables-nft-multi
# ls -l /sbin/ebtables
lrwxrwxrwx 1 root root 17  1月 29  2021 /sbin/ebtables -> xtables-nft-multi
# /sbin/iptables -V
iptables v1.8.4 (nf_tables)

xtables-nft-multi は nftables のAPIを使うiptables互換のコマンドになります(*1)。ただnftables環境においてはあまり役に立ちません(後述)。nftables用のnftコマンドを使って管理することになります。

OSデフォルトのファイアウォールサービスであるfirewalldはBackEndにiptablesを使うかnftablesを使うか指定できるようになっていますが、これもnftablesを使うように設定されています(*2)。

iptablesとnftables
図1 CentOS8におけるiptablesとnftables

nftablesに変更されたといっても、firewalldを使っているのなら、iptables -> nftablesへの変更を意識する必要は基本的にありません。firewall-cmdを使って設定をすれば、firewalldがBackEndに合わせて設定を行ってくれるからです。

RedHat系でのファイアウォールの変遷

iptables,nftables,firewalldといくつか用語が出て来たので、整理のためにRedHat系の各バージョンでのファイアウォールの変遷を振り返ってみます。

・〜CentOS6/RHEL6

CentOS6/RHEL6まではファイアウォールといえばiptablesのみでした。iptablesコマンドを使ってカーネルに対して直接、ルールのエントリを登録していく形です。

設定ファイルも/etc/sysconfig/iptables, ip6tablesに以下のようにiptablesのエントリ情報を書いておけば起動時に読み込まれて設定されるので、管理は非常にシンプルに行えました。

iptablesでの設定ファイル例

*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT

・CentOS7/RHEL7

firewalldというデーモンが導入され、デーモンがファイアウォールの機能を管理する形になりました。Kernel内のファイアウォール実装としてはiptablesのままなので、firewalldがiptablesを使ってKernelに設定を行います。

ファイアウォールをサービスとして動作させることで、WAFのような他のプロセスとも連携させやすくしたい等の狙いがあったようです。

ただ、firewalld.serviceをdisableしてiptables.serviceをenableにすればCentOS6/RHEL6同様、iptablesで管理することはできました。

個人的な考えですが、firewalldはデスクトップPCとして利用している場合は楽でいいのですが、サーバーのfirewallとして使おうとするとあまり使い勝手が良くなく(*3)、firewalldはdisableして従来通りiptablesで管理する方が好みでした。設定ファイルは/etc/sysconfig/iptablesにまとまっていますし、現在の動作を確認したければ /sbin/iptables -L -vn で網羅できたからです。IPv6も使っていると別途設定する必要はありましたが。

・CentOS8/RHEL8

カーネルにiptablesの後継のnftablesが実装されたのに合わせてnftablesを使うようになりました。iptablesコマンドの実体はxtables-nft-multiに差し替えられています。

デフォルトのファイアウォールサービスはCentOS7/RHEL7と同じfirewalldですが、BackEndにはnftablesを使うようになっています。

CentOS8/RHEL8でもfirewalld.serviceをdisableしてnftables.serviceでiptablesに近い使い勝手で管理できるようになっています。

本題

やっと本題ですが、CentOS8/RHEL8においてfirewalldではなくnftablesでファイアウォール管理をするための手順と設定方法をまとめます。

nftablesを使えば、iptablesでの管理と同様、設定ファイルを直接編集してシンプルに管理することができます。また、nftablesではiptables, ip6tables, arptables, ebtables, ipsetの機能が統合されているので、これらをまとめて設定できるようになり、iptablesよりも楽になります。

firewalldからnftablesへの切り替え

iptablesを使っている時もでしたが、私はコマンドでちまちまルールを追加、削除するより設定ファイルを直接編集してreloadする形で運用していく方が好きなので、先にconfigファイルを作成します。

起動時に読み込まれる設定ファイルは /etc/sysconfig/nftables.conf なので、以下の例のようにファイルを作成します。

/etc/sysconfig/nftables.confの例

flush ruleset

table ip filter {
        set safeip {
                type ipv4_addr
                flags interval
                elements = {
                        XX.XX.0.0/16,
                        XX.YY.0.0/16,
                }
        }

        chain INPUT {
                type filter hook input priority filter; policy accept;

                ct state related,established counter packets 0 bytes 0 accept
                ip protocol icmp counter packets 0 bytes 0 accept
                iifname "lo" counter packets 0 bytes 0 accept

                # ssh
                ip saddr XX.XX.XX.XX tcp dport 22 ct state new counter packets 0 bytes 0 accept
                #ip saddr @safeip tcp dport 22 ct state new counter packets 0 bytes 0 accept

                # web
                tcp dport { http, https } ct state new counter packets 0 bytes 0 accept
                #meta l4proto tcp ct state new tcp dport 80 counter packets 0 bytes 0 accept
                #meta l4proto tcp ct state new tcp dport 443 counter packets 0 bytes 0 accept

                # smtp
                tcp dport 25 ct state new counter packets 0 bytes 0 accept

                # dns
                tcp dport 53 ct state new accept
                udp dport 53 ct state new accept

                # pop3
                ip saddr @safeip tcp dport 110 ct state new counter packets 0 bytes 0 accept

                # submission port
                ip saddr @safeip tcp dport 587 ct state new counter packets 0 bytes 0 accept

                counter packets 0 bytes 0 reject with icmp type host-prohibited
        }

        chain FORWARD {
                type filter hook forward priority filter; policy accept;
        }

        chain OUTPUT {
                type filter hook output priority filter; policy accept;
        }
}

これはIPv4のみの設定です。IPv6も使っているならtableのAddress FamilyをinetにしてIPv6の設定もまとめて書けます。

少し設定ファイルの内容について説明します。

flush ruleset

nft -f でファイルを読み込んだ際、既存の設定をクリアするようにします。nft -fは使わず systemctl reload nftables.service しか使わないなら無くても問題ありません。

table ip filter {

iptablesと異なり、nftablesではテーブルは自分で作成する必要があります。テーブルはチェーンを格納するコンテナの役割を持ちます。ここではIPv4(Address Family: ip)用にfilterという名前でテーブルを作成しています。名前はfilterでなくてもいいのですが、iptablesのテーブルに合わせています。

set safeip {

iptablesでいうipsetと同等の機能であるsetsの定義をしています。複数のIPアドレスをまとめてマッチングに使用したい場合に使用します。nftablesではipsetの機能も統合され、同じconfigファイルで設定できるようになりました。

        chain INPUT {
                type filter hook input priority filter; policy accept;

INPUTという名前のチェーンの定義をしています。チェーンの名前もテーブル名と同様なんでもいいのですが、iptablesのチェーン名に合わせてINPUTとしています。type行でチェーンの種類を定義しています。"type filter"でfiltering用、"hook input"でパケット入力時に呼び出されるチェーンを定義しています。"priority filter"は"priority 0"と同義です(*4)。

policyはacceptになっていますが、チェーン最後に"counter packets 0 bytes 0 reject with icmp type host-prohibited"のルールがあるので、どのルールにもマッチしなかった場合はrejectされます(Rejectのカウンタが残る)。

ct state related,established counter packets 0 bytes 0 accept

確立済みの接続は通します。

ip saddr XX.XX.XX.XX tcp dport 22 ct state new counter packets 0 bytes 0 accept

特定のIPv4アドレスからのみssh接続を許可します。nftablesではマッチしたパケットのカウント有無も指定できるので、カウントが不要なら"counter packets 0 bytes 0"の指定は不要です。

ip saddr XX.XX.XX.XX tcp dport 22 ct state new accept
ip saddr @safeip tcp dport 22 ct state new counter packets 0 bytes 0 accept

複数のIPv4アドレスから許可したい場合はsetsが使えます(safeipがset名)。

tcp dport { http, https } ct state new counter packets 0 bytes 0 accept

http, httpsへの接続を許可します。{}で複数のポートをまとめて指定できます。カウンタはhttp,https共通になります。

meta l4proto tcp ct state new tcp dport 80 counter packets 0 bytes 0 accept

TCPポートはmeta l4protoを使っても指定できます。

このような感じで各サービスごとのポートを指定していきます。

設定ファイルの作成が完了したらnftablesに切り替えます。

nftablesへの切り替え

# systemctl stop firewalld.service
# systemctl disable firewalld.service
# systemctl start nftables.service
# systemctl enable nftables.service

問題なければ nft list ruleset で先程作成した設定ファイルと同じ内容が出力されるはずです。

運用

これでnftablesに切り替わりましたが、運用する上でよく使うコマンドをまとめておきます。

現在設定されているルールの表示。

# nft list ruleset

出力内容はそのまま設定ファイルとして使えます。コマンドで設定を変更した内容を保存したい場合は、出力内容を /etc/sysconfig/nftables.conf に書き込みます。

# nft list ruleset > /etc/sysconfig/nftables.conf

起動時には/etc/sysconfig/nftables.confから設定が読み込まれます。

テーブルを指定してルールを表示したい場合。

# nft list table ip filter

現在登録されているテーブル/チェーン/ルールの全クリア。

# nft flush ruleset

設定ファイルの読み込み。

# nft -f /etc/sysconfig/nftables.conf

systemctl経由なら以下でも同じです。

# systemctl reload nftables.service

nftables環境でiptablesコマンドを使うとどうなるか

最初にiptables(xtables-nft-multi)コマンドはnftables環境においてはあまり役に立たないと書きましたので、最後に補足しておきます。

firewalldで運用していたとして、実際にカーネルに設定されているエントリを確認したいケースもあると思います。このような時、CentOS7/RHEL7では iptables -L -vn で確認できました。

CentOS8/RHEL8では nft list ruleset で確認する必要があります。 iptables -L -vn でもそれっぽい情報が表示されるので一見問題なさそうなのですが、一部の情報しか表示されていません。これは、iptables(xtables-nft-multi)は ip filter テーブルの内容しか表示していないためです。firewalldが独自に作成したテーブルとそこに登録したルールは表示されません。

また iptables(xtables-nft-multi) が未対応のエントリが登録されていると

iptables v1.8.4 (nf_tables): table `filter' is incompatible, use 'nft' tool.

のようにエラーになったりしますので、xtables-nft が nftables 対応だから使えると期待せず、nftコマンドに慣れていく必要があります。

CentOS8/RHEL8でもiptables-servicesのrpmは提供されているようなので、iptables.serviceを有効にした場合には使えるのかもしれません。

(*1) man xtables-nft。xtablesとはLinuxカーネル内におけるiptables,ip6tables,arptables,ebtablesのiptables系機能の総称です。

(*2) /etc/firewalld/firewalld.confのFirewallBackend項目。

(*3) 少し複雑な設定をしようとするとrich ruleやdirect ruleを設定しないといけなかったり、設定ファイルが一つにまとまっていなかったり、現在の設定を確認する際も全体を見通し辛かったり。

(*4) man nft(8)の"Table 6. Standard priority names, family and hook compatibility matrix"参照。

投稿日:2021/10/06 11:35

タグ: Server

Top

アーカイブ

タグ

Server (18) プログラミング (15) 作業実績 (15) PHP (11) ネットワーク (9) C (7) C++ (7) Webアプリ (6) EC-CUBE (6) Nginx (5) OpenSSL (5) laravel (4) Linux (4) 書籍 (4) JavaScript (3) AWS (3) Rust (3) Vue.js (3) Golang (2) Symfony (2) Apache (1) デモ (1) お知らせ (1) MySQL (1) CreateJS (1) OSS (1)