关于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 方式2:将VM3上的eth0接口到internal ZONE中,而eth1加入public ZONE,并在对应的ZONE上加规则。VM3上面防火墙设置如下 #将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规则找原因吧……
