Raspberry Pi4 : firewalld

Raspberry Pi4, openSUSEでfirewalldを設定していく。

まずはsshの設定。ポート番号の変更を反映する必要がある。

# cp /usr/lib/firewalld/services/ssh.xml /etc/firewalld/services/
# vi /etc/firewalld/services/ssh.xml
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<port protocol="tcp" port="22"/> -> <port protocol="tcp" port="hogehoge"/>
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Raspberry Pi4はopenvpn構築予定。当面、動的に接続する場合は日本からになるので、海外からのアクセスはdenyしても構わない。

次で公開いただいているCIDRよりipset向けのリストを作成する。

http://nami.jp/ipv4bycc/cidr.txt

ipset使うのでfirewalldの起動前にipsetの設定を読み込むようにする。firewalld.serviceにスクリプトを追加する。

# vi /usr/lib/systemd/system/firewalld.service
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[Service]
ExecStartPre=/~~~~/FW_preload.sh
ExecStopPost=/~~~~/FW_postexe.sh
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# chmod +x FW_preload.sh
# chmod +x FW_postexe.sh

ExecStartPreではipset restore -exist -f ipset.confでipsetの設定を読み込む。ExecStopPostではipset save > ipset.confでipsetの設定を保存する。ipsetのもとにしているcidrリストは1日1回更新されているのでcronなどで定期更新している場合は設定しておくといい。

FWの設定は簡単にはyastから行えるが、iptables同等にダイレクトルールを設定することもできる。forward, nat, logの設定や、ipsetで作ったリストの活用などはダイレクトルールで作ることができる。ダイレクトルールはiptablesと違ってdirect.xmlに保存され、firewalldを再起動しても読み込まれるので便利。

# vi set_firewalld.sh
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#!/bin/bash
perm=" --permanent "
add_chain_v4F="firewall-cmd ${perm} --direct --add-chain ipv4 filter "
add_rule_v4F="firewall-cmd  ${perm} --direct --add-rule ipv4 filter "

rm /etc/firewalld/direct.xml
set -eux

${add_chain_v4F} IP_ACCEPT_MYNET
${add_rule_v4F}  IP_ACCEPT_MYNET 10 -s 127.0.0.0/8    -j  ACCEPT
${add_rule_v4F}  IP_ACCEPT_MYNET 20 -s 10.0.0.0/8     -j  ACCEPT
${add_rule_v4F}  IP_ACCEPT_MYNET 30 -s 172.16.0.0/12  -j  ACCEPT
${add_rule_v4F}  IP_ACCEPT_MYNET 40 -s 192.168.0.0/16 -j  ACCEPT
${add_rule_v4F}  IP_ACCEPT_MYNET 9999 -j DROP

${add_chain_v4F} IP_ACCEPT_GROUP
${add_rule_v4F}  IP_ACCEPT_GROUP 10 -m set --match-set WHITE_LIST src -j ACCEPT
${add_rule_v4F}  IP_ACCEPT_GROUP 30 -m set --match-set ACCEPT_COUNTRY_LIST src -j ACCEPT
${add_rule_v4F}  IP_ACCEPT_GROUP 9999 -j IP_ACCEPT_MYNET

${add_rule_v4F}  INPUT 100 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
${add_rule_v4F}  INPUT 200 -j TCP_CHAIN
${add_rule_v4F}  INPUT 300 -j UDP_CHAIN
${add_rule_v4F}  INPUT 400 -j ICMP_CHAIN 
${add_chain_v4F} TCP_CHAIN
${add_rule_v4F}  TCP_CHAIN 9999 -j DROP
${add_chain_v4F} UDP_CHAIN
${add_rule_v4F}  UDP_CHAIN 9999 -j DROP
${add_chain_v4F} ICMP_CHAIN
${add_rule_v4F}  ICMP_CHAIN 9999 -j DROP

# SSH (TCP:22)
${add_rule_v4F}  TCP_CHAIN 10 -p tcp --syn --dport 22 -j IP_ACCEPT_GROUP
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# chmod +x set_firewalld.sh

firewalldを起動して設定を始める。firewall-cmd –reloadで設定が適用されるので、SSHで外部からログインできることを確認しなおす。

# systemctl daemon-reload
# systemctl start firewalld
# systemctl status firewalld
# sh set_firewalld.sh
# firewall-cmd --reload
success

一応、firewalldのデフォルトゾーンも確認しておく。自分は基本的にはダイレクトルールで設定を完了してしまうのでゾーンはあまり関係がない。ダイレクトルールではACCEPTせずにDROPやRETURNのみするようにすればゾーン設定と組み合わせて使っていくことができる。ただし、ダイレクトルールでも独自にゾーンを定義してルール適用できるので組み合わせる必要性は基本無い。

# firewall-cmd --get-default-zone
public

ゾーンの変更はyastのnetwork Settingsから行える。初期設定はpublicになっていた。※yast -> Firewallからでも変えられるっぽい

FirewallのZONEに対する設定はyastのFirewallから行える。IPv6, IPv4で関係なくサービス単位で設定されるのでIPv6だけsshは止めたい場合などはダイレクトルールでIPv6をDROPしてZONEでsshを許可。あるいはダイレクトルールでIPv4をACCEPTしてZONEではsshを許可対象から外せばよい。もちろん、ダイレクトルール側でIPv4とIPv6の両方に関するルールを書いてもよい。

再起動した場合にfirewalldが自動起動するようにStart-Upから設定を行う。

当然ながらコマンドでも制御は可能。

# systemctl enable firewalld

念のためfirewalldをリスタートした場合にダイレクトルールが適用されるかを確認しておく。ログイン中のSSHセッションが切れる場合があるので事前にログイン確認等はしておく。

# systemctl restart firewalld
# firewall-cmd --permanent --direct --get-all-rules
ipv4 filter INPUT 100 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
~(略)