关于firewalld防火墙设置的博客很多,但都是介绍它的使用方法或者使用规则,但并不是知道了firewall-cmd命令的使用就能够很好地设置防火墙规则,本人也是在使用的过程中就遇到过“明明设置了规则,但就是没有生效的情况”,因此有必要深入地理解firewalld的工作方式。
下面给出本人在实际工作中遇到的一种情况,我们将通过这个场景来深入理解firewalld的工作过程。
在上面的使用场景中,有3台虚拟机通过交换机互联,并分配有10.0.0.0/24网段的地址,其中VM3通过2620端口向VM1和VM2提供服务,不允许暴露ssh端口,并且VM3需要通过eth1接口供外部远程ssh访问。
针对上面的需求,当时想到了两种实现方式:
- 方式1:将VM3上的eth0地址段加入到internal ZONE中,而eth1加入public ZONE,并在对应的ZONE上加规则。VM3上面防火墙设置如下:
#将eth0接口的IP地址段加入到对应的ZONE
firewall-cmd --zone=internal --add-source=10.0.0.0/24
#允许2620端口的tcp服务
firewall-cmd --zone=internal --add-port=2620/tcp
#不允许ssh连接
firewall-cmd --zone=internal --remove-service=ssh
#将eth1接口加入到对应的ZONE
firewall-cmd --zone=public --add-interface=eth1
#允许ssh连接,public ZONE默认是允许ssh服务的,不需要再加这条规则
firewall-cmd --zone=public --add-service=ssh
#将eth0接口的IP地址段加入到对应的ZONE
firewall-cmd --zone=internal --add-interface=eth0
#允许2620端口的tcp服务
firewall-cmd --zone=internal --add-port=2620/tcp
#不允许ssh连接
firewall-cmd --zone=internal --remove-service=ssh
#将eth1接口加入到对应的ZONE
firewall-cmd --zone=public --add-interface=eth1
#允许ssh连接,public ZONE默认是允许ssh服务的,不需要再加这条规则
firewall-cmd --zone=public --add-service=ssh
经过实际实验发现上述两种实现方式中,只有方式2能够达到目的,在采用方式1下,VM3仍然能够接受来自VM1和VM2的ssh连接,难道用IP地址段来绑定ZONE无效?
为了弄清楚方式1不生效的原因,自己查看了一下方式1设置下的iptables规则,毕竟firewalld最终还是通过iptables规则来实现防火墙的功能的,也就是firewall-cmd设置的规则最终会转换成iptables规则。
我们先看一下internal和public ZONE当前的防火墙设置,如下所示。
internal (active)
target: default
icmp-block-inversion: no
interfaces:
sources: 10.0.0.0/24
services: mdns samba-client dhcpv6-client
ports: 2620/tcp
protocols:
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
public
target: default
icmp-block-inversion: no
interfaces:
sources:
services: ssh dhcpv6-client
ports:
protocols:
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
再看看对应的iptables规则,这里我们需要关注的是filter表的INPUT链,如下所示。
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
3676 206K ACCEPT all -- any any anywhere anywhere ctstate RELATED,ESTABLISHED
2052 123K ACCEPT all -- lo any anywhere anywhere
8 504 INPUT_direct all -- any any anywhere anywhere
8 504 INPUT_ZONES_SOURCE all -- any any anywhere anywhere
8 504 INPUT_ZONES all -- any any anywhere anywhere
0 0 DROP all -- any any anywhere anywhere ctstate INVALID
6 360 REJECT all -- any any anywhere anywhere reject-with icmp-host-prohibited
Chain INPUT_ZONES (1 references)
pkts bytes target prot opt in out source destination
8 504 IN_public all -- + any anywhere anywhere [goto]
Chain INPUT_ZONES_SOURCE (1 references)
pkts bytes target prot opt in out source destination
0 0 IN_internal all -- any any 10.0.0.0/24 anywhere [goto]
Chain INPUT_direct (1 references)
pkts bytes target prot opt in out source destination
Chain IN_internal (1 references)
pkts bytes target prot opt in out source destination
0 0 IN_internal_log all -- any any anywhere anywhere
0 0 IN_internal_deny all -- any any anywhere anywhere
0 0 IN_internal_allow all -- any any anywhere anywhere
0 0 ACCEPT icmp -- any any anywhere anywhere
Chain IN_internal_allow (1 references)
pkts bytes target prot opt in out source destination
0 0 ACCEPT udp -- any any anywhere 224.0.0.251 udp dpt:mdns ctstate NEW
0 0 ACCEPT udp -- any any anywhere anywhere udp dpt:netbios-ns ctstate NEW
0 0 ACCEPT udp -- any any anywhere anywhere udp dpt:netbios-dgm ctstate NEW
0 0 ACCEPT tcp -- any any anywhere anywhere tcp dpt:lpsrecommender ctstate NEW
Chain IN_internal_deny (1 references)
pkts bytes target prot opt in out source destination
Chain IN_internal_log (1 references)
pkts bytes target prot opt in out source destination
Chain IN_public (1 references)
pkts bytes target prot opt in out source destination
8 504 IN_public_log all -- any any anywhere anywhere
8 504 IN_public_deny all -- any any anywhere anywhere
8 504 IN_public_allow all -- any any anywhere anywhere
1 84 ACCEPT icmp -- any any anywhere anywhere
Chain IN_public_allow (1 references)
pkts bytes target prot opt in out source destination
1 60 ACCEPT tcp -- any any anywhere anywhere tcp dpt:ssh ctstate NEW
Chain IN_public_deny (1 references)
pkts bytes target prot opt in out source destination
Chain IN_public_log (1 references)
pkts bytes target prot opt in out source destination
如果仔细查看上面的规则,就会发现实际上如果是采用IP地址段的方式来绑定ZONE,会在INPUT_ZONES_SOURCE链中产生对应的规则,如果采用接口绑定ZONE的方式,会在INPUT_ZONES的链中产生相应规则,而它们均在INPUT的链中,并且INPUT_ZONES_SOURCE在前,INPUT_ZONES在后。也就是说,来自VM1或者VM2的ssh数据包,会首先匹配10.0.0.0/24进入INPUT_ZONES_SOURCE链,进一步沿着链往前匹配,发现没有ACCEPT、REJECT或者DROP的匹配,最终返回到INPUT的链,又进入到INPUT_ZONES继续匹配,最终在IN_public_allow链中ACCEPT。
上面这段表述可能不太清楚,如果读懂了上面的iptables规则,理解了firewalld的规则是如何对应到iptables规则上去的,也就弄清楚了方式1不生效的原因,并且我们也就知道了当网口收到数据包后,会与哪个ZONE中的哪些规则发生作用。
知其然更要知其所以然。万变不离其中,在使用firewalld设置防火墙规则时遇到不理解的地方就看iptables规则找原因吧……