firewalld 基本概念
firewalld像iptables、nftables等一样,本身并不是防火墙,只是防火墙管理工具,通过定义防火墙规则最终交由内核的netfilter进行包过滤实现防火墙功能。
firewalld软件包提供了firewalld daemon和一系列工具如firewall-cmd、firewall-config、firewall-offline-cmd等。
firewalld由d-bus层和core层构成。d-bus层提供api,其它程序(如firewall-cmd、firewall-config、firewall-applet、甚至是你自己编写的程序或守护进程)通过调用api可定义防火墙规则或查询防火墙状态等等。core层为d-bus层提供服务,负责和后端交互。架构图如下:
备注:firewalld提供的firewall-offline-cmd不调用d-bus层,而是直接调用core层中的IO来修改防火墙规则。
澄清概念:
- 许多人觉得执行systemctl stop firewalld可以关闭防火墙功能,就认为firewalld是防火墙,这个理解是错误的。执行systemctl stop firewalld,实际上是对底层包过滤规则清除(类似于nft flush ruleset 或iptables -F ,清除当前的ruleset)相当于关闭了防火墙。
- firewalld定义的防火墙规则要被内核的netfilter理解,中间的翻译任务由iptables或nftables进行,也就是firewalld后端需要iptables或nftables。
firewalld、iptables和nftables关系
在centos7及之前版本中,iptables也提供了类似firewalld的daemon,用户可以选择iptables或firewalld daemon其一。centos8已弃用iptables,只用nftables。nftables和iptables负责的应该属于数据包过滤框架。nftables是从linux内核3.13开始出现,旨在替代现存的 {ip,ip6,arp,eb}_tables
(本文统称为iptables)。
firewalld zone、network interface、connection关系
firewalld易用特点就是使用zone、service简化防火墙配置任务,另外一个优势就是动态管理。
zone是firewalld一切的基础,在zone中可配置各种规则,比如根据service/port(经常使用)、source等定义,或定义rich rule(富规则),所以说zone是预先定义的一组规则集。这样zone就实现了对网络可信等级的划分。firewalld缺省定义了9个zone(当然可以对其可修改,也可以自己创建额外的zone)。
通过对网卡(实际上是connection,即网卡配置文件。虽然一个网卡可有多个配置文件,但同时只能有一个活动的配置文件,可以在配置文件中使用zone=来定义connection所属zone)切换zone,可快速将网络置于不同的可信等级。
此外,firewalld zone也提供了类似路由器一些功能,如端口转发、ip地址伪装等。
归入zone顺序
对于一个接受到的请求具体使用哪个zone,firewalld是通过三种方法来判断的:
- source,也就是源地址
- interface,接收请求的网卡
- firewalld.conf中配置的默认zone
这三个的优先级按顺序依次降低,也就是说如果按照source可以找到就不会再按interface去查找,如果前两个都找不到才会使用第三个,也就是firewalld.conf中配置的默认zone。
zone分类
zone名称 | 默认配置 |
---|---|
trusted | 允许所有流量 |
home | 拒绝除和传出流量相关的,以及ssh,mdsn,ipp-client,samba-client,dhcpv6-client预定义服务之外其它所有传入流量 |
internal | 和home相同 |
work | 拒绝除和传出流量相关的,以及ssh,ipp-client,dhcpv6-client预定义服务之外的其它所有传入流量 |
public | 拒绝除和传出流量相关的,以及ssh,dhcpv6-client预定义服务之外的其它所有传入流量,新加的网卡默认属于public zone |
external | 拒绝除和传出流量相关的,以及ssh预定义服务之外的其它所有传入流量,属于external zone的传出ipv4流量的源地址将被伪装为传出网卡的地址。 |
dmz | 拒绝除和传出流量相关的,以及ssh预定义服务之外的其它所有传入流量 |
block | 拒绝除和传出流量相关的所有传入流量 |
drop | 拒绝除和传出流量相关的所有传入流量(甚至不以ICMP错误进行回应) |
预定义服务配置
firewall-cmd --get-services
: 查看预定义服务列表/usr/lib/firewalld/services/*.xml
:预定义服务的配置
三种配置方法
- firewall-config (firewall-config包)图形工具
- firewall-cmd (firewalld包)命令行工具
- /etc/firewalld/zones 添加配置文件
firewall-cmd
添加使用 --permanent
选项表示设置成永久生效,需要重新启动 firewalld
服务或执行 firewall-cmd --reload
命令
重新加载防火墙规则时才会生效。若不带有此选项,表示用于设置运行时规则,但是这些规则在系统或firewalld服务重启、停止时配置将失效。
--runtime-to-permanent
:将当前的运行时配置写入规则配置文件中,使之成为永久性配置。
常用命令
--get-zones 列出所有可用区域
--get-default-zone 查询默认区域
--set-default-zone=<ZONE> 设置默认区域
--get-active-zones 列出当前正使用的区域
--add-source=<CIDR>[--zone=<ZONE>] 添加源地址的流量到指定区域,如果无--zone= 选项,使用默认区域
--remove-source=<CIDR> [--zone=<ZONE>] 从指定区域删除源地址的流量,如无--zone= 选项,使用默认区域
--add-interface=<INTERFACE>[--zone=<ZONE>] 添加来自于指定接口的流量到特定区域,如果无--zone= 选项,使用默认区域
--change-interface=<INTERFACE>[--zone=<ZONE>] 改变指定接口至新的区域,如果无--zone= 选项,使用默认区域
--add-service=<SERVICE> [--zone=<ZONE>] 允许服务的流量通过,如果无--zone= 选项,使用默认区域
--add-port=<PORT/PROTOCOL>[--zone=<ZONE>] 允许指定端口和协议的流量,如果无--zone= 选项,使用默认区域
--remove-service=<SERVICE> [--zone=<ZONE>] 从区域中删除指定服务,禁止该服务流量,如果无--zone= 选项,使用默认区域
--remove-port=<PORT/PROTOCOL>[--zone=<ZONE>] 从区域中删除指定端口和协议,禁止该端口的流量,如果无--zone= 选项,使用默认区域
--reload 删除当前运行时配置,应用加载永久配置
--list-services 查看开放的服务
--list-ports 查看开放的端口
--list-all [--zone=<ZONE>] 列出指定区域的所有配置信息,包括接口,源地址,端口,服务等,如果无--zone= 选项,使用默认区域
区域管理
(1)显示当前系统中的默认区域
firewall-cmd --get-default-zone
(2)显示默认区域的所有规则
firewall-cmd --list-all
(3)显示当前正在使用的区域及其对应的网卡接口
firewall-cmd --get-active-zones
(4)设置默认区域
firewall-cmd --set-default-zone=home
firewall-cmd --get-default-zone
服务管理
(1)查看默认区域内允许访问的所有服务
firewall-cmd --list-service
(2)添加httpd 服务到public 区域
firewall-cmd --add-service=http --zone=public
(3)查看public区域已配置规则
firewall-cmd --list-all --zone=public
(4)删除public区域的httpd服务
firewall-cmd --remove-service=http --zone=public
(5)同时添加httpd、https服务到默认区域,设置成永久生效
firewall-cmd --add-service=http --add-service=https --permanent
firewall-cmd --reload
firewall-cmd --list-al1
富规则(rich-rules)
rich规则比基本的firewalld语法实现更强的功能,不仅实现允许/拒绝,还可以实现日志syslog和auditd,也可以实现端口转发,伪装和限制速率
匹配顺序
规则实施顺序:
- 该区域的端口转发,伪装规则
- 该区域的日志规则
- 该区域的允许规则
- 该区域的拒绝规则
每个匹配的规则生效,所有规则都不匹配,该区域默认规则生效
语法
rule
[source]
[destination]
service|port|protocol|icmp-block|masquerade|forward-port
[log]
[audit]
[accept|reject|drop]
规则选项
--add-rich-rule
--remove-rich-rule
--query-rich-rule
--list-rich-rule
family
:指定该规则仅应用于IPv4数据包:如果未提供此关键字,则该规则将同时应用于IPv4和IPv6。
source address
:提供数据包必须具有的源地址,才能使用源地址触发规则。
service
:指定了规则的服务类型,在本例中为ssh。
reject/drop/accept
:提供了数据包与规则匹配时要执行的操作,在本例中为reject.
- REJECT动作会返回一个拒绝(终止)数据包(TCP FIN或UDP-ICMP-PORT-UNREACHABLE),明确的拒绝对方的连接动作。
- DROP动作只是简单的直接丢弃数据,并不反馈任何回应。需要Client等待超时,Client容易发现自己被防火墙所阻挡。
访问限制
# 拒绝从192.168.0.11的所有流量,当address 选项使用source 或 destination时,必须用family= ipv4 |ipv6
firewall-cmd --permanent --zone=public --add-rich-rule='rule family=ipv4 source address=192.168.0.11/32 reject'
# 限制每分钟只有两个连接到ftp服务
firewall-cmd --add-rich-rule='rule service name=ftp limit value=2/m accept'
# 抛弃esp( IPsec 体系中的一种主要协议)协议的所有数据包
firewall-cmd --permanent --add-rich-rule='rule protocol value=esp drop'
# 接受所有192.168.1.0/24子网端口5900-5905范围的TCP流量
firewall-cmd --permanent --zone=vnc --add-rich-rule='rule family=ipv4 source address=192.168.1.0/24 port port=5900-5905 protocol=tcp accept'
日志规则
语法
log [prefix="<PREFIX TEXT>" [level=<LOGLEVEL>] [limit value="<RATE/DURATION>"]
<LOGLEVEL> 可以是emerg,alert, crit, error, warning, notice, info, debug.
<DURATION> s:秒, m:分钟, h:小时, d:天
audit [limit value="<RATE/DURATION>"]
实例
#接受ssh新连接,记录日志到syslog的notice级别,每分钟最多三条信息
firewall-cmd --permanent --zone=work --add-rich-rule='rule service name="ssh" log prefix="ssh " level="notice" limit value="3/m" accept'
#从2001:db8::/64子网的DNS连接在5分钟内被拒绝,并记录到日志到audit,每小时最大记录一条信息
firewall-cmd --add-rich-rule='rule family=ipv6 source address="2001:db8::/64" service name="dns" audit limit value="1/h" reject' --timeout=300
firewall-cmd --permanent --add-rich-rule='rule family=ipv4 source address=172.25.X.10/32 service name="http" log level=notice prefix="NEW HTTP " limit value="3/s" accept'
# 测试
firewall-cmd --reload
tail -f /var/log/messages
curl http://serverX.example.com
伪装NAT
检查防火墙是否支持伪装
firewall-cmd --permanent --zone=<ZONE> --add-masquerade
firewall-cmd --query-masquerade #检查是否允许伪装
firewall-cmd --add-masquerade #允许防火墙伪装IP
firewall-cmd --remove-masquerade #禁止防火墙伪装IP
实例
firewall-cmd --add-rich-rule='rule family=ipv4 source address=192.168.0.0/24 masquerade'
端口转发
端口转发:将发往本机的特定端口的流量转发到本机或不同机器的另一个端口。通常要配合地址伪装才能实现
firewall-cmd --permanent --zone=<ZONE> --add-forward-port=port=<PORTNUMBER>:proto=<PROTOCOL>[:toport=<PORTNUMBER>][:toaddr=]
说明:toport= 和toaddr= 至少要指定一个
实例
转发传入的连接9527/TCP,到防火墙的80/TCP到public zone 的192.168.0.254
firewall-cmd --add-masquerade 启用伪装
firewall-cmd --zone=public --add-forward-port=9527:proto=tcp:toport=80:toaddr=192.168.0.254
rich规则的port转发语法
forward-port port=<PORTNUM> protocol=tcp|udp [to-port=<PORTNUM>] [to-addr=<ADDRESS>]
转发从192.168.0.0/24来的,发往80/TCP的流量到防火墙的端口8080/TCP
firewall-cmd --zone=work --add-rich-rule='rule family=ipv4 source address=192.168.0.0/24 forward-port port=80 protocol=tcp to-port=8080'
转发从 172.25.x.10/32来的,发往 443/TCP 端口的流量到防火墙的端口 22/TCP
firewall-cmd --permanent --add-rich-rule 'rule family=ipv4 source address=172.25.X.10/32 forward-port port=443 protocol=tcp to-port=22'
firewall-cmd --reload
ssh -p 443 serverX.example.com
项目实例
目标:验证rich规则的潜在问题
我们允许192.168.50.0/24所有网络访问局域网的10.10.10.1上的远程桌面
允许192.168.50.17的主机通过ssh访问防火墙
拒绝192.168.50.0/24其他主机通过ssh访问防火墙
拒绝所有来自192.168.50.0/24对防火墙的ping请求
允许192.168.50.0/24所有主机网络访问局域网的10.10.10.1上的远程桌面
firewall-cmd --zone=external --add-forward-port=\
port=3389:proto=tcp:toport=3389:toaddr=10.10.10.1
允许192.168.50.17的主机通过ssh访问防火墙
firewall-cmd --zone=external --add-rich-rule="rule \
family="ipv4" \
source address="192.168.50.17" \
service name="ssh" \
log prefix=\"ssh connect from:\" \
level="notice" \
accept"
拒绝192.168.50.0/24的其他主机访问防火墙的ssh服务
firewall-cmd --zone=external --add-rich-rule="rule \
family="ipv4" \
source address="192.168.50.0/24" \
service name="ssh" \
log prefix=\"ssh reject from:\" \
level="notice" \
drop"
拒绝所有来自192.168.50.0/24对防火墙的ping请求
firewall-cmd --zone=external --add-rich-rule="rule \
protocol value="icmp" \
reject"
查看 rich 规则
firewall-cmd --zone=external --list-rich-rules
实验的重点:就是要验证第一条rich的规则是否会被优先执行,还是第二条drop规则会先于第一条accept规则执行?
我们在192.168.50.17的主机上测试一下能否ssh到防火墙?如下图ssh请求无响应且没有错误提示返回,这里至少已经证实
- 即便在规则列表中accept规则位置先于drop规则,但是drop规则总是会优先于accept规则被匹配。
- 已经无法ping通防火墙,并且由防火墙返回错误信息。
当前的rich规则的一个问题是,它们是基于规则操作来组织的。 日志规则始终在拒绝规则之前发生。 拒绝规则总是发生在允许规则之前。 这导致用户感到困惑,因为它隐式地对规则进行了重新排序。 这也使得不可能添加全面的rich规则来拒绝流量。因此firewalld的rich规则执行逻辑如下:
- 日志规则
- drop/reject规则
- accept规则
防火墙的端口转发测试,192.168.50.17是一台Ubuntu主机,我们使用Remmina远程桌面软件连接到内网10.10.10.1的主机,
OK,端口转发也是成功的
那么实现遗留的问题,就是rich规则如何能如我们所愿地定的规则顺序执行?这正是本文的重点
Rich规则的priority字段
新版的firewalld添加了新的priority字段。它可以是-32768到32767之间的任何数字,其中数字越小,优先级越高。此范围足够大,以允许从脚本或其他实体自动生成规则。
那么就非常简单:只需在你想优先执行的rich规则中给priority字段定义一个足够小的负数,就能确保能优先于其他drop/reject规则被firewalld匹配。如下图所示
firewall-cmd --zone=external --add-rich-rule="rule \
priority="-100" \
family="ipv4" \
source address="192.168.50.17" \
service name="ssh" \
log prefix=\"ssh connect from:\" \
level="notice" \
accept"
Ok,此时,accept的规则优先于其他drop/reject规则被匹配,这正是我们所希望的。
要记得
将上面的运行时配置转化为持久配置,执行下面命令
firewall-cmd --runtime-to-permanent
nftables
- nftables 框架替换了 iptables 默认网络数据包过滤工具,可以通过nft命令可编程式的配置防火墙。
- firewalld也是Linux的防火墙,同时支持iptables和nftables,最新版本默认使用nftables。
- 简单的说firewalld是基于nftfilter防火墙的用户界面工具。而iptables和nftables是命令行工具。
- firewalld引入区域的概念,可以动态配置,让防火墙配置及使用变得简便。
- 从用户的角度来看,nftables添加了一个名为nft的新工具,它取代了iptables,arptables和ebtables中的所有其他工具。
- 从架构的角度来看,它还取代了处理包过滤规则集的运行时评估的内核部分。
操作
# 查询所有表名
nft list tables
# 查看某个表的规则
nft list table filter
增
# 增加表
nft add table fillter
# 增加链
nft add chain filter input { type filter hook input priority 0 \; } # 要和hook(钩子)相关连
# 增加规则
nft add rule filter input tcp dport 22 accept
删
只需要把上面的 add 改为 delete 即可
改
更改链名用rename
更改规则用replace
查
nft list ruleset # 列出所有规则
nft list tables # 列出所有表
nft list table filter # 列出filter表
nft chain filter input # 列出filter表input链
以上命令后面也可以加 -nn 用于不解析ip地址和端口
加 -a 用于显示 handles