インターネットから利用するサーバでは、ネットワークサービスのアクセス制限が必須となります。Linuxで一般的なネットワークサービスのアクセス制限の仕組み、firewalldについて解説しようと思います。
firewalldには多くの機能が包含されている
実は前回、firewalldによるルーティングとNATの話しを解説してしまって、本来のファイヤーウォール=ネットワークサービスのアクセス制限の話しが後回しになってしまいました。今回がその「ネットワークサービスのアクセス制限」の話しです。
Linuxサーバ上では様々なネットワークサービスが運用されており、それぞれが固有のport番号を開けてサービスを提供しています。家庭や会社の中だけで運用するならばあまり問題にはなりませんが、インターネットに接続してサービスを提供するのであれば、本当に必要なportだけアクセスを許可して、必要のないportへのアクセスは許可しないのが適切です(もちろん、不要なサービスは停止しておくということも必要です)。
firewalldはゾーンでアクセスを管理する
firewalldは「ゾーン」という単位でアクセスを管理することができます。ネットワークインターフェースは、管理したいゾーンに所属させて、ゾーンに対してどのサービスのアクセスを許可するかを定義します。
Rocky9を例にとると、OSをインストールした直後からfirewalldは稼働しており、全てのネットワークインターフェースは「public」というゾーンに所属しています。そして「public」というゾーンのデフォルト設定は以下の通りになっています(設定は「firewall-cmd --list-all-zones」の出力で確認します)。以下のウチのミニPC base0におけるゾーン「public」の設定情報です。
public (active)
target: default
icmp-block-inversion: no
interfaces: bond2 br1 br2 enp0s21f0u2c2 enp2s0 enp3s0
sources:
services: cockpit dhcpv6-client ssh
ports:
protocols:
forward: yes
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
| 属性 | 説明 |
| target | そのゾーンにマッチしたパケットに対するデフォルトの処理(ポリシー)を定義する。但し、ルールが定義されていればそのルールに従った処理となるので、ルールにマッチしないパケットのデフォルト処理を定義する。 default:デフォルトのターゲット(通常はREJECTまたはDROP)に従う。 DROP: デフォルトでパケットを破棄する ACCEPT: デフォルトでパケットを許可する |
| interfaces | ゾーンに所属するネットワークインターフェースを定義する。 |
| services | アクセスを許可するサービスを定義する。サービス名で指定できるのでportとプロトコルで指定するよりも分かりやすい。 |
| ports | アクセスを許可するportを定義する。プロトコル(TCPまたはUDP)も指定することができる。 |
| sources | IPアドレスやサブネットを指定することで、ゾーンが適用されるIP範囲を制御することができる。 |
| icmp-block | 特定のICMPタイプ(例: echo-request)を許可または拒否することができる。 |
| rich-rules | 高度なルール設定を行う。 例) 特定の送信元IPアドレス |
| forward-ports | あるport番号のパケットを別のport番号に転送する。 |
| masquerade | NAT手段のひとつ、IPマスカレードを有効にする。 |
先ず最初にインターフェースを適切なゾーンに所属させる
ゾーンに対するアクセス制限を行う前に、各ネットワークインターフェースを適切なゾーンに所属させましょう。なぜなら、デフォルトでは全てのネットワークインターフェースがゾーン「public」に所属しているからです。
例えば、家庭内や会社内からしかアクセスしないネットワークインターフェースなら、ゾーン「trusted」に所属させると良いでしょう。ゾーン「trusted」はtarget属性がACCEPTになっており、ネットワークサービスのアクセス制限はいっさいありません。
また、「firewall-cmd --list-all-zones」の出力でservicesに設定されたサービスを確認し、設定したい状態に近いゾーンを選ぶのが良いと思います。あとは、ゾーンの名前と用途のイメージが合っているものを選択するほうが分かりやすい、といったところでしょうか。
インターフェースが所属するゾーンを変更するにはnmcliコマンドを使います。以下は、インターフェースbond2 ,br2, enp2s0, enp3s0のゾーンをtrustedに設定する例です。尚、インターフェースに対する設定ではありますが、指定するのはコネクション名のほうなので、各インターフェースに対応するコネクション名を確認しておいてください。
# nmcli connection modify br2 connection.zone trusted
# nmcli connection modify br-slave-bond2 connection.zone trusted
# nmcli connection modify bond-slave-enp2s0 connection.zone trusted
# nmcli connection modify bond-slave-enp3s0 connection.zone trusted
ちなみに、ウチのミニPC base0では、インターフェースbond2 ,br2, enp2s0, enp3s0は管理ネットワークに接続していて、様々なテストのために、あらゆるネットワークサービスを利用する可能性があるので、このような設定にしています。ホストbase0では、ネットワークインターフェースとゾーンの関係は以下の通りとしています。

アクセスを許可するサービスを追加/削除する
ゾーン「public」に設定されているservices属性には、デフォルトで「cockpit dhcpv6-client ssh」が設定されています。cockpitもIPv6も使わないので、以下の通りcockpitとdhcpv6-clientは削除しましょう。
# firewall-cmd --zone=public --remove-service=cockpit --permanent
success
# firewall-cmd --zone=public --remove-service=dhcpv6-client --permanent
success
# firewall-cmd --reload
success
「--permanent」オプションを付けると永続的な設定として保存しますが、ランタイムには反映されていません。なので、最後に「firewall-cmd --reload」を実行してランタイムにも反映します。
一方で、https, nfsは追加したいと思います。以下の通りコマンドを実行します。
# firewall-cmd --zone=public --add-service=https --permanent
success
# firewall-cmd --zone=public --add-service=nfs --permanent
success
# firewall-cmd --reload
success
サービス設定は以下のコマンドで確認することができます。
# firewall-cmd --list-services --zone=public
https nfs ssh
また、サービス名として指定可能な文字列は、以下のコマンドで確認することができます。
# firewall-cmd --get-services
このように、文字通りfirewalldの防護壁(ファイヤーウォール)によって、システムは脅威から守られることになるわけですが、今回の設定のイメージを図示すると以下のようになります。

アクセス制限の詳細仕様
今回紹介した方法でアクセス制限ができるのは、inboundに対するアクセス制限となります。すなわち、外からホストbase0に対して入ってくるパケットを制限するものとなります。
outboundに対するアクセス制限(ホストbase0から外に出ていくパケットの制限)は、ダイレクトルールで設定するようです。
それと、最初は気がつかなかったことを書きます。
ホストbase0のインターフェース br1に対するアクセスを制限しているのだから、br1に接続している仮想マシン(上記の図では192.168.1.204)へのアクセスも制限されると思っていたのですが、仮想マシンへのアクセス制限は有効になりませんでした。仮想ブリッジbr1にアクセス制限をしても、その先の仮想マシンへのアクセス制限には有効にならないということです。なので、仮想マシン自身でfirewalldを稼働させて適切な設定を行うようにしましょう。
firewalldの設定をバックアップするのはどうする?
firewalldの設定をいろいろといじっていて、うまくいかないときに初期の状態に戻したいことがあるかと思います。そんなときは、設定前に /etc/firewalld/ 配下をまるごとバックアップしておいて、失敗したら元に戻す、というのが良さそうです。もそうすれば、失敗したら元に戻すことができますので(もちろん戻した後で、firewalldを再起動する必要があります)。
設定に自信がない場合は「--permanent」オプションは付けずに設定を行って、動作を確認した後に「firewall-cmd --runtime-to-permanent」で永続化(保存)するという手順のほうが良さそうに思います。永続化していなければ、「systemctl restart firewalld」でfirewalldを再起動するだけで設計変更前の状態に戻ります。
例えば、先程行った、ゾーン「public」のservices属性からcockpitとdhcpv6-clientを削除する操作は、「--permanent」オプションを付けずに以下のように実施することもできます。
# firewall-cmd --zone=public --remove-service=cockpit
success
# firewall-cmd --zone=public --remove-service=dhcpv6-client
success
「--permanent」を付けないとランタイムのほうに設定が反映されまするので、この状態で設定が有効かどうかのテストを行います。設定が有効であることを確認してから、以下のコマンドでランタイムの設定を永続化(保存)するのが良いでしょう。
# firewall-cmd –runtime-to-permanent
success
ところで、ネットワークインターフェースをどのゾーンに所属させるかという設定は、/etc/firewalld配下きファイルには記録されておらず、/etc/NetworkManager/system-connections/<コネクション名>.nmconnection のほうに記録されます。
広告主へのリンク
オイラが今回のテストに使っているのは、高価なサーバではなくて、安価なミニPC MINISFORUM GK41 というマシンです。LANポートが2つ付いているので、PXEブートのテストにも便利です。
更に、このMINISFORUM GK41のUSBポートに以下のUSB-LAN変換アダプタを付けて、LANポートを合計3つにして運用しています。
このブログにおける関連リンク
犬でも分かるLinuxネットワーク
・犬でも分かるLinuxネットワーク設定(1): nmcliコマンドの使い方
・犬でも分かるLinuxネットワーク設定(2): ボンディング(bonding)
・犬でも分かるLinuxネットワーク設定(3): 仮想ブリッジ
・犬でも分かるLinuxネットワーク設定(4): ボンディング+仮想ブリッジ
・犬でも分かるLinuxネットワーク設定(5):定義ファイルの修正
・犬でも分かるLinuxネットワーク設定(6): ルーティングとNAT
・犬でも分かるLinuxネットワーク設定(7):firewalldによるアクセス制限
・犬でも分かるLinuxネットワーク設定(8):VLAN
・犬でも分かるLinuxネットワーク設定(9):IPエイリアス
・犬でも分かるLinuxネットワーク設定(10):outboundのアクセス制限
・犬でも分かるLinuxネットワーク設定(11):NATポリシーにアクセス制限を設定する


コメント