CentOS7のfirewalldをまじめに使うはじめの一歩(systemdも少し)


基本

デフォルト設定ファイルとユーザー設定ファイルの関係

/usr/lib下のsystemdないしfirewalldにデフォルト設定ファイルがあるので、設定を変更する場合は該当するファイルを同じディレクトリ構成で/etcに置く。

例えばsystem/default.targetというファイルの場合、/usr/libでのgraphical.targetへのシンボリックリンクが、/etcmulti-user.targetへのシンボリックリンクで上書きされているのがわかる。

[root@localhost ~]# ls -l /usr/lib/systemd/system/default.target
lrwxrwxrwx. 1 root root 16 Oct 21 14:26 /usr/lib/systemd/system/default.target -> graphical.target
[root@localhost ~]# ls -l /etc/systemd/system/default.target
lrwxrwxrwx. 1 root root 37 Jul 22 03:38 /etc/systemd/system/default.target -> /lib/systemd/system/multi-user.target

firewalldの設定についても同様で、etcの下にあるzones/public.xml/usr/lib下のデフォルト設定を上書きしている。

[root@localhost ~]# ls -l /etc/firewalld/zones/public.xml
-rw-r--r--. 1 root root 340 Oct 21 15:32 /etc/firewalld/zones/public.xml
[root@localhost ~]# ls -l /usr/lib/firewalld/zones/public.xml 
-rw-r-----. 1 root root 315 Jun 10 07:19 /usr/lib/firewalld/zones/public.xml

NICの確認

ip lでリンク、ip aでアドレス、ip rでルーティング。

[root@localhost ~]# ip l
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT qlen 1000
    link/ether 08:00:27:20:5d:4b brd ff:ff:ff:ff:ff:ff
[root@localhost ~]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 08:00:27:20:5d:4b brd ff:ff:ff:ff:ff:ff
    inet 10.0.2.15/24 brd 10.0.2.255 scope global dynamic enp0s3
       valid_lft 82486sec preferred_lft 82486sec
    inet6 fe80::a00:27ff:fe20:5d4b/64 scope link 
       valid_lft forever preferred_lft forever
[root@localhost ~]# ip r
default via 10.0.2.2 dev enp0s3  proto static  metric 1024 
10.0.2.0/24 dev enp0s3  proto kernel  scope link  src 10.0.2.15 

参考

ケーススタディ1: http通信を許可する

6までならiptablesで操作していたもの。nginxは別途インストール済という前提で。

systemctl status firewalldfirewalldが動いてるか調べて、動いてなかったらsystemctl start firewalldで起動。

現状のゾーン設定を調べる firewall-cmd --list-all

firewalldではゾーンという単位で設定が定義され、ゾーンとNICが紐づくことで設定が有効になる。

[root@localhost ~]# firewall-cmd --list-all
public (default, active)
  interfaces: enp0s3
  sources: 
  services: dhcpv6-client ssh
  ports: 
  masquerade: no
  forward-ports: 
  icmp-blocks: 
  rich rules: 

上記のipコマンドででてきた、enp0s3インタフェースに紐付いていることがわかる。

すべてのゾーンの情報をみる firewall-cmd --list-all-zones

[root@localhost ~]# firewall-cmd --list-all-zones
block
  interfaces: 
  sources: 
...
dmz
  interfaces: 
...
drop
  interfaces: 
  sources: 
...
work
  interfaces: 
  sources: 
...

ゾーンに設定されているサービスを確認する: firewall-cmd --list-services --zone=public --permanent

--permanentについては後述。

[root@localhost ~]# firewall-cmd --list-services --zone=public  --permanent
dhcpv6-client ssh

追加できるサービスを確認する: firewall-cmd --get-services

[root@localhost ~]# firewall-cmd --get-services
amanda-client bacula bacula-client dhcp dhcpv6 dhcpv6-client dns ftp high-availability http https imaps ipp ipp-client ipsec kerberos kpasswd ldap ldaps libvirt libvirt-tls mdns mountd ms-wbt mysql nf
s ntp openvpn pmcd pmproxy pmwebapi pmwebapis pop3s postgresql proxy-dhcp radius rpc-bind samba samba-client smtp ssh telnet tftp tftp-client transmission-client vnc-server wbem-https

各サービスの詳細は設定ファイルをみるのがよいと思う。変更したい場合は上記の通り、/etc/firewalldにコピーして行う。

[root@localhost ~]# cat /usr/lib/firewalld/services/http.xml 
<?xml version="1.0" encoding="utf-8"?>
<service>
  <short>WWW (HTTP)</short>
  <description>HTTP is the protocol used to serve Web pages. If you plan to make your Web server publicly available, enable this option. This option is not required for viewing pages locally or developing Web pages.</description>
  <port protocol="tcp" port="80"/>
</service>

ゾーンにサービスを追加する: firewall-cmd --add-service=http --zone=public --permanent

--permanentをつけないと設定ファイルが更新されないので、サービスをreloadすると元の状態に戻ってしまう。

[root@localhost ~]# firewall-cmd --add-service=http --zone=public --permanent
success

確認。

[root@localhost ~]# firewall-cmd --list-services --zone=public  --permanent
dhcpv6-client http ssh

追加できました。
実際のファイルをみても、/usr/lib/firewalld/zones/public.xmlは変更されてなくて、

[root@localhost ~]# cat /usr/lib/firewalld/zones/public.xml
<?xml version="1.0" encoding="utf-8"?>
<zone>
  <short>Public</short>
  <description>For use in public areas. You do not trust the other computers on networks to not harm your computer. Only selected incoming connections are accepted.</description>
  <service name="ssh"/>
  <service name="dhcpv6-client"/>
</zone>

/etc/firewalld/zones/public.xmlが更新されてます。

[root@localhost ~]# cat /etc/firewalld/zones/public.xml
<?xml version="1.0" encoding="utf-8"?>
<zone>
  <short>Public</short>
  <description>For use in public areas. You do not trust the other computers on networks to not harm your computer. Only selected incoming connections are accepted.</description>
  <service name="dhcpv6-client"/>
  <service name="http"/>
  <service name="ssh"/>
</zone>

これで、外部から80ポートへアクセスできるようになりました。サービスの再起動も不要でした。

ケーススタディ2: 特定ポートのhttp通信を許可する

例として5000ポートでの通信を許可する場合。

5000ポートを使う適当なプロセスをでっちあげる。

[root@localhost ~]# python -m SimpleHTTPServer 5000
Serving HTTP on 0.0.0.0 port 5000 ...

/usr/lib/firewalld/services/http.xml/etc/firewalld/servicesにコピーして編集。

[root@localhost ~]# cp /usr/lib/firewalld/services/http.xml /etc/firewalld/services/
[root@localhost ~]# vi /etc/firewalld/services/http.xml

みればわかるくらい単純だけどこんな感じに。

<?xml version="1.0" encoding="utf-8"?>
<service>
  <short>WWW (HTTP)</short>
  <description>HTTP is the protocol used to serve Web pages. If you plan to make your Web server publicly available, enable this option. This option is not required for viewing pages locally or developing Web pages.</description>
  <port protocol="tcp" port="80"/>
  <port protocol="tcp" port="5000"/>
</service>

httpサービスは追加済なのでreloadする。

[root@localhost ~]# firewall-cmd --reload

以上で完了。
設定の書き方はman firewalld.serviceみる。

ケーススタディ3: 独自のサービスを追加して管理する

上記では既存のhttpサービスに追加したけど、たぶん、独自のサービスを追加したほうが管理もしやすいので正道なはず。

編集したファイルは不要なので削除。リロードもしておく。

[root@localhost ~]# rm /etc/firewalld/services/http.xml
[root@localhost ~]# firewall-cmd --reload

既存のhttpファイルをもとにpy-appという独自サービスの設定ファイルを作成。
firewall-cmd --new-service=[service] --permanentの使い方がいまいちわからないので今回はファイルを直接作成する。

[root@localhost ~]# cp /usr/lib/firewalld/services/http.xml /etc/firewalld/services/py-app.xml

中身は以下。

<?xml version="1.0" encoding="utf-8"?>
<service>
  <short>myapp by python</short>
  <description>for file sharing</description>
  <port protocol="tcp" port="5000"/>
</service>

作成できたらサービスとして追加できるが、--get-servicesには表示されないので、firewall-cmd --reloadしたほうがいいとは思う。いずれにせよ、ファイルが作成できた時点で以下のコマンドは実行可能。

[root@localhost ~]# firewall-cmd --add-service=py-app --zone=public --permanent                                                                                                                         
success
[root@localhost ~]# firewall-cmd --list-services --zone=public  --permanent                                                                                                                      
dhcpv6-client http py-app ssh

今回はreloadしないと反映できなかった。さっきのケースが勘違いかも。

[root@localhost ~]# firewall-cmd --reload

おそらくこんな感じでPostgresqlやらrabbitmqやらfluentdやらのサービスを作成していくことになるんだろう。

ケーススタディ4: firewalldの設定を一覧でみる

firewalldはD-BUS経由での操作もできる単なる管理インタフェースみたいなので、実際のフィルタリングはiptablesが動いている。なので、設定を一覧でみたい、実際の反映結果をみたい、というときは今までどおり、iptables-saveを使えばいい。

[root@localhost ~]# iptables-save 
# Generated by iptables-save v1.4.21 on Tue Oct 21 18:04:25 2014
*nat
:PREROUTING ACCEPT [4:176]
:INPUT ACCEPT [4:176]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
...
-A INPUT_ZONES -i enp0s3 -g IN_public
-A INPUT_ZONES -g IN_public
-A IN_public -j IN_public_log
-A IN_public -j IN_public_deny
-A IN_public -j IN_public_allow
-A IN_public_allow -p tcp -m tcp --dport 80 -m conntrack --ctstate NEW -j ACCEPT
-A IN_public_allow -p tcp -m tcp --dport 5000 -m conntrack --ctstate NEW -j ACCEPT
-A IN_public_allow -p tcp -m tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT
COMMIT
# Completed on Tue Oct 21 18:04:25 2014

というわけで簡単なことを筋道立てて設定・管理するならfirewalldが便利なんだろう。あとD-BUSから操作する場合。
けど、複雑なことをエイヤッと解決したい場合は今までどおりiptablesを直接触ったほうがいいと思う。

追記: firewalldとiptablesの設定の共有はできないっぽい

などを読むと、firewalld/etc/sysconfig/iptablesの設定を読んでくれないっぽい。なのでどちらを使うか選ぶしかないっぽい。
firewalldの代わりにiptablesを有効にする際のざっくり手順は以下。

yum install iptables-services
systemctl stop firewalld
systemctl disable firewalld
systemctl enable iptables
systemctl start iptables