Firewalld 简介
目前有很多开源防火墙产品,包括: pfSense、OPNsense、ClearOS 等,它们都是基于 FreeBSD 或 Linux 等。Firewalld 是一个用于管理 Linux 操作系统防火墙的动态守护进程,它支持防火墙区域和允许对入站和出站的网络流量进行更精细的控制。Firewalld 使用了 zones 和 services 的概念来简化流量管理。它提供了图形界面和命令行界面工具(如 firewall-cmd、firewall-config 和 firewall-applet)来配置规则和策略。 提到 Firewalld,我们就不得不说 Iptables 与 nftables,通过下图再结合文字说明,可能我们会更加容易理解。
Firewalld、Iptables、nftables 都是 Linux 中三种不同的防火墙操作命令工具,它们在功能和操作上都有所不同:
iptables:
iptables 是一个较老的、成熟的工具,直接操作 Linux 内核的 netfilter 框架来管理网络包过滤。
它工作在 TCP/IP 协议 7 层模型的第 3 层(网络层)和第 4 层(传输层),使用复杂的命令行语法。
iptables 的规则是即时的,也就是说,一旦重启系统,除非规则被保存和恢复,否则会丢失。 iptables 不支持动态更新规则,每次更改规则都需要重新加载整个规则集,这可能会导致短暂的连接中断。
firewalld:
Firewalld 它使用与 iptables 相同的底层网络过滤框架 netfilter,提供了一个用户友好的前端。
它支持动态更新规则而无需重启服务或丢失现有的连接状态信息,这使得它在处理频繁变化的网络环境时更为方便和灵活。
它使用 zones 来定义不同信任等级的网络和设备,并允许用户根据区域来管理访问权限,这让安全规则的管理更加直观和灵活。 Firewalld 使用 XML 文件格式来存储其配置和规则。
它提供了直接的支持 for IPv4、IPv6、以太网桥和 ipset。
nftables:
Nftables 是 netfilter 项目的新一代工具,旨在替代 iptables、ip6tables、arptables 和 ebtables。 它提供了一个统一的命令行界面,用于处理不同类型的网络流量。 Nftables 同样工作在 TCP/IP 协议 7 层模型的第 3 层(网络层)和第 4 层(传输层),但它的语法更加简洁和直观。 它提供了一种新的、易于理解和维护的规则语言,允许用户编写更加高效和简洁的规则集。 nftables 的规则集可以通过内置的命令 nft 轻松保存和加载,而且它支持原子规则集更改,这意味着所有的更改可以一次性应用,避免了中间状态导致的潜在问题。 Nftables 提供了更好的性能和更高的灵活性,例如支持多表继承和复合数据类型。 它内置了对动态更新规则的支持,类似于 firewalld,但不需要额外的守护进程或服务。 Nftables 直接集成在 Linux 内核中,不需要依赖外部模块,这有助于简化系统配置和提高效率。 随着 nftables 的发展,很多 Linux 发行版已经开始将其作为默认的防火墙工具。 Nftables 设计之初就考虑了向前兼容性,所以有一个兼容层可以支持旧的 iptables 规则。 在这里我们提到了一个名词原子规则集更改,那什么是原子规则集更改了?
原子规则集更改是指在更新防火墙规则时,所有的更改都是作为一个单一不可分割的操作来执行的。也就是说,这些更改要么全部应用,要么全部不应用,不会存在只应用了部分更改的中间状态。在没有原子性的系统中,规则的更改可能会逐条地执行,这就可能导致短暂的时间窗口,在这个时间窗口中,防火墙的状态可能是不完整或不一致的。这种状态可能导致安全漏洞,比如可能会有一段时间允许不该进入的流量进入,或者阻止了本该允许的流量。通过原子规则集更改,nftables 确保在更新规则时,整个系统从一个一致的状态过渡到另一个一致的状态,无需担心这种中间状态的安全问题。这对于维护复杂的防火墙规则集来说是非常重要的,因为它可以减少由于规则应用的不一致性导致的潜在风险。
尽管 firewalld 在某些方面提供了更现代化的特性和更好的用户体验,但有些高级用户可能仍然偏爱 iptables,由于其直接性和精细控制的能力。在某些情况下,firewalld 和 iptables 也可以同时使用,但一般建议使用一个命令来进行配置,从而避免配置上的混淆。在 Rocky Linux 9.3 系统上,firewalld 默认使用 nftables 作为其后端。
怎么知道 Rocky Linux 9.3 是否使用 nftables 作为其后端了?我们通过 firewall-cmd 命令放行端口 443,看使用 nft 命令是否可以查看到对应配置。
[ root@localhost ~]# nft -v nftables v1.0.4 (Lester Gooch #3 ) [root@localhost ~]# firewall-cmd --add-port=443/tcp success [root@localhost ~]# nft list ruleset | grep -B 5 443 chain filter_IN_public_allow { tcp dport 22 ct state { new, untracked } accept ip6 daddr fe80::/64 udp dport 546 ct state { new, untracked } accept tcp dport 9090 ct state { new, untracked } accept tcp dport 80 ct state { new, untracked } accept tcp dport 443 ct state { new, untracked } accept
Firewalld Zones 简介
在 Firewalld 中,区域(Zones)是用来定义一个信任级别的网络。每个区域都有一组规则,决定了进入和离开该区域的数据包的处理方式。Firewalld 中的预定义区域包括以下几种:
drop :这是最不信任的区域。所有进入的数据包都会被丢弃,没有任何回应(即没有任何拒绝的通知),只有出去的数据包能够通过。这个区域适用于您不想让任何外部系统知道您的系统存在的情况。block :与 drop 类似,block 区域也是不信任的。所有进入的连接都会被拒绝,有一个 icmp-host-prohibited 消息作为回应,而出站的连接则允许。public :这是一个不信任的区域。您不信任其他的计算机,但您可能会允许某些入站的连接。external :这个区域用于外部(即互联网)网络,适用于路由器和网关。默认情况下,Firewalld 会对此区域进行伪装(masquerading),这意味着您的内部网络是隐藏的。internal :内部区域通常用于内部(局域网)网络。在这个区域,您相对信任网络上的其他计算机。dmz (非军事区):在 DMZ 区域,主机被放置在一个隔离的子网中,提供对公共服务的有限访问,而无法接触到内部网络。适用于公共服务器的位置。work :这是一个用于工作的区域,您大部分信任网络中的其他计算机。只有被认为是安全的连接和服务会被允许。home :这个区域用于家庭环境。您大部分信任您家庭网络中的其他计算机。只有被认为是安全的连接和服务会被允许。trusted :这是最信任的区域。所有的网络连接都被允许。只有在您完全信任您的网络和所有连接的情况下,才应该使用这个区域。每个区域都可以有服务和端口关联。服务是预定义的入口点,比如 HTTP 或 SSH 等,而端口可以是任何特定的网络端口,比如 eth0 或 ens18 等。您可以根据您的网络环境和安全需求,将接口(如网卡)分配给相应的区域。例如,如果您有一个服务器运行在 DMZ 中,您可能会将那个网络接口分配给 DMZ 区域,并且只允许所需的服务(比如 HTTP)。
通过使用区域,Firewalld 允许管理员以更高层次的抽象来管理网络安全策略,使得分离和控制不同级别的信任网络变得更加方便。从这里其实我们不难看出,为什么很多国外的 Linux 大神,会很喜欢将 Linux Firewalld 直接作为专业的防火墙设备,当然早期的时候更多采用 iptables 作为专业的防火墙设备。当然如果您想有一个更加专业的开源防火墙建议使用 PfSense,目前它已经提供硬件与公有云厂商(AWS)服务,可以直接在公有云上进行购买。
在每个区域(Zones)中,又包含有相同的 12 个配置项,对应配置项简单说明:
target:该设置决定了未匹配任何规则的流量的默认处理方式。例如,default(默认)通常指向一个预设的默认行为,如 ACCEPT、REJECT、DROP 等。在某些区域中,target 可以被设置为特定的动作,比如 DROP 会丢弃所有未匹配的包。 icmp-block-inversion:如果设置为 yes,则 ICMP 阻止规则的行为将被反转。这意味着,通常情况下会被阻止的 ICMP 请求将被允许,而通常被允许的将被阻止。 interfaces:这里列出了分配给该区域的网络接口(如 eth0、eth1)。分配给区域的接口将按照区域的规则处理网络流量。 sources:这里可以指定该区域的源 IP 地址(或子网)。这允许基于来源地址对流量进行区分处理。 services:这里指定了允许通过该区域的预定义服务列表。例如,ssh 表示 SSH 服务的流量(通常是端口 22)被允许通过。 ports:这里可以列出一些具体的端口号,用来允许通过这些端口的流量。格式通常是 端口号/协议,例如 443/tcp。 protocols:允许通过该区域的网络协议列表,如 tcp、udp、icmp 等。 forward:如果设置为 yes,则启用了该区域的 IPv4 和 IPv6 转发功能。这对于路由器和网关设备来说是必要的。 masquerade:如果设置为 yes,则启用伪装(NAT)功能,这通常用于隐藏内部网络的私有 IP 地址。 forward-ports:这里可以设置端口转发规则,将外部端口的流量转发到内部的一个不同端口和/或地址。 source-ports:这里可以指定源端口的规则,允许基于源端口进行流量过滤。 icmp-blocks:这里列出了要阻止的 ICMP 消息类型。 防火墙常用命令
在使用 Firewalld 命令配置之前,我们需要先了解 –permanent 和 –runtime-to-permanent 是两个不同的选项,它们用于处理防火墙规则的持久性。下面是每个选项的详细解释:
–permanent:
使用 –permanent 选项可以将规则永久保存到防火墙的配置中。这意味着,即便系统重启,这些规则也会被保留并在启动时应用。
例如,如果您想永久允许 HTTP 服务,您可以执行命令 firewall-cmd –permanent –add-service=http。这将在防火墙的配置文件中保存规则。
需要注意的是,使用 –permanent 选项添加的规则在添加后不会立即生效。为了让这些永久规则生效,您需要重新加载防火墙配置,使用命令 firewall-cmd –reload。
–runtime-to-permanent:
–runtime-to-permanent 是一个相对较新的选项,用于将当前运行时(runtime)的配置转变为永久配置。
这个选项的好处是它允许您在确认当前运行时配置有效且符合预期后,直接将这些配置保存为永久配置,无需手动重复添加每一条规则。
您可以使用命令 firewall-cmd –runtime-to-permanent 来执行这一操作。执行后,当前的所有运行时设置都会被复制到永久配置中。
和 –permanent 一样,使用 –runtime-to-permanent 之后,您可能需要执行 firewall-cmd –reload 来应用变更。
在实际使用中,–permanent 选项常用于配置初始防火墙规则或进行规划好的更改,而 –runtime-to-permanent 选项则非常适用于测试阶段,当您想确保当前的运行时规则可以正常工作后再将其保存下来。这样可以减少配置错误和不必要的重复工作。
启用禁用防火墙
# 启动防火墙 [ root@localhost ~]# systemctl start firewalld # 查看防火墙状态 [ root@localhost ~]# systemctl status firewalld # 停止防火墙 [root@localhost ~]# systemctl stop firewalld # 禁用防火墙 [root@localhost ~]# systemctl disable firewalld # 启用防火墙 [root@localhost ~]# systemctl enable firewalld # 启用防火墙并启动防火墙 [root@localhost ~]# systemctl enable --now firewalld
配置 zone
# 获取默认 zone,默认为 public 区域 [root@localhost ~]# firewall-cmd --get-default-zone public # 修改默认 zone [root@localhost ~]# firewall-cmd --set-default-zone=homes success # 查看所有 zone 信息 [root@localhost ~]# firewall-cmd --get-zones block dmz drop external home internal nm-shared public trusted work # 查看所有 zone 详细信息 [root@localhost ~]# firewall-cmd --list-all-zones block target: %%REJECT%% icmp-block-inversion: no interfaces: sources: services: ports: protocols: forward: yes masquerade: no forward-ports: source-ports: icmp-blocks: rich rules: ......(略) # 查看指定 zone 信息 [root@localhost ~]# firewall-cmd --zone=public --list-all public (active) target: default icmp-block-inversion: no interfaces: ens18 sources: services: cockpit dhcpv6-client ssh ports: 443/tcp protocols: forward: yes masquerade: no forward-ports: source-ports: icmp-blocks: rich rules: # 在配置 firewall 规则时,如果未指定 zone,默认添加至 public zone [root@localhost ~]# firewall-cmd --add-port=443/tcp --permanent [root@localhost ~]# firewall-cmd --reload [root@localhost ~]# firewall-cmd --list-all-zones | grep -A 14 public public (active) target: default icmp-block-inversion: no interfaces: ens18 sources: services: cockpit dhcpv6-client ssh ports: 443/tcp protocols: forward: yes masquerade: no forward-ports: source-ports: icmp-blocks: rich rules: # 修改网络接口归属区域,将接口 ens18 分配到 home 区域 [root@localhost ~]# firewall-cmd --zone=home --change-interface=ens18
添加删除服务
# 添加服务 [root@localhost ~]# firewall-cmd --add-service=http --permanent # 永久生效配置 [root@localhost ~]# firewall-cmd --reload # 列出服务 [root@localhost ~]# firewall-cmd --list-service # 移除服务 [root@localhost ~]# firewall-cmd --remove-service=http # 将运行时的配置写入配置文件 [root@localhost ~]# firewall-cmd --runtime-to-permanent # 永久生效配置 [root@localhost ~]# firewall-cmd --reload # 添加服务至指定 zone [root@localhost ~]# firewall-cmd --zone=public --add-service=http --permanent # 列出指定 zone 服务 [ root@localhost ~]# firewall-cmd --list-service --zone=public Cockpit dhcpv6-client ssh
添加删除端口
# 添加端口 [root@localhost ~]# firewall-cmd --add-port=3306/tcp --permanent # 永久生效配置 [root@localhost ~]# firewall-cmd --reload # 列出端口 [root@localhost ~]# firewall-cmd --list-port # 移除端口 [root@localhost ~]# firewall-cmd --remove-port=3306/tcp --permanent # 永久生效配置 [root@localhost ~]# firewall-cmd --reload # 添加端口至指定 zone [root@localhost ~]# firewall-cmd --zone=home --add-port=443/tcp --permanent # 列出指定 zone 端口 [root@localhost ~]# firewall-cmd --list-ports --zone=public 443/tcp
Firewalld Service 定义
在 firewalld 中自带一个常见服务列表,在配置的时候,只需要使用 –add-services 即可,对于不在常用服务列表的,再通过 –add-port 进行配置。
[root@localhost ~] RH-Satellite-6 RH-Satellite-6-capsule afp amanda-client .....(略) [root@localhost ~] total 840 -rw-r--r--. 1 root root 381 Apr 22 2023 RH-Satellite-6-capsule.xml -rw-r--r--. 1 root root 556 Apr 22 2023 RH-Satellite-6.xml -rw-r--r--. 1 root root 352 Apr 22 2023 afp.xml -rw-r--r--. 1 root root 399 Apr 22 2023 amanda-client.xml .....(略) [root@localhost ~] <?xml version="1.0" encoding="utf-8"?> <service> <short>Zabbix Server</short> <description>Zabbix is a mature and effortless enterprise-class open source monitoring solution for network monitoring and application monitoring of millions of metrics.</description> <port protocol="tcp" port="10051"/> </service>
XML 文件详解
在 Firewalld 中,服务是由 XML 文件定义的,这些 XML 文件描述了服务的相关信息以及它使用的网络端口和协议。下面以 Redis 服务 XML 文件为例,详细解释各个标签的作用:
[root@localhost ~]# cat /usr/lib/firewalld/services/redis.xml <?xml version="1.0" encoding="utf-8" ?> <service > <short > redis</short > <description > Redis is an open source (BSD licensed), in-memory data structure store, used as a database, cache and message broker.</description > <port protocol ="tcp" port ="6379" /> </service >
: 这是 XML 声明,它指定了文档使用的 XML 版本(1.0)和字符编码(utf-8)。
: 这是服务定义的根元素,它包围了服务定义的所有其他元素。
: 这个标签包含了服务的简称,在这个例子中是 “redis”。
: 这个标签提供了服务的详细描述。在这个例子中,描述了 Redis 是一个开源的、基于内存的数据结构存储系统,可以作为数据库、缓存或消息代理使用。
: 这个标签定义了服务需要的网络端口。它包括两个属性:protocol 和 port。protocol 指定了端口使用的协议(在这个例子中是 “tcp”),而 port 属性指定了端口号(在这个例子中是 “6379”)。
总结来说,这个 XML 文件告诉 Firewalld,有一个名为 Redis 的服务,它需要开放 TCP 协议的 6379 端口,以便于 Redis 服务器能够接收来自客户端的连接。通过将此服务添加到特定的防火墙 zone,系统管理员可以允许通过防火墙的 Redis 流量。
修改 SSH 服务端口
正常如果我们修改了 SSH 端口为 2222,那么我们需要在防火墙上采用 –add-port 来放行 2222 端口,但还有另外一种方法,就是通过修改 XML 文件来实现。
# 需要先复制对应文件至自定义目录 [ root@localhost ~]# cp /usr/lib/firewalld/services/ssh.Xml /etc/firewalld/services/ssh.Xml [ root@localhost ~]# cat /etc/firewalld/services/ssh.Xml <?xml version="1.0" encoding="utf-8"?> <service> <short>SSH</short> <description>Secure Shell (SSH) is a protocol for logging into and executing commands on remote machines. It provides secure encrypted communications. If you plan on accessing your machine remotely via SSH over a firewalled interface, enable this option . You need the openssh-server package installed for this option to be useful.</description> <port protocol="tcp" port="22"/> </service> # 修改端口号至2222 [root@localhost ~]# sed -i "s/22/2222/g" /etc/firewalld/services/ssh.xml [root@localhost ~]# cat /etc/firewalld/services/ssh.xml <?xml version="1.0" encoding="utf-8"?> <service> <short>SSH</short> <description>Secure Shell (SSH) is a protocol for logging into and executing commands on remote machines. It provides secure encrypted communications. If you plan on accessing your machine remotely via SSH over a firewalled interface, enable this option . You need the openssh-server package installed for this option to be useful.</description> <port protocol="tcp" port="2222"/> </service> # 生效配置 [root@localhost ~]# firewall-cmd
icmp配置
ICMP 是 Internet 控制消息协议(Internet Control Message Protocol)的缩写,是 TCP/IP 网络协议栈的一个核心协议。它主要用于在网络设备(如路由器和网关)与主机之间传递控制消息,用于报告错误和进行网络诊断。它不适用于常规的数据传输,而是作为一种辅助手段来帮助维护和管理网络。
在 firewalld 中禁 Ping 可以有多种方式,比如添加 add-icmp-block 黑名单或者 rich-rule。
# 禁 Ping [root@localhost ~]# firewall-cmd --add-icmp-block=echo-request --permanent success # 或[root@localhost ~]# firewall-cmd --add-icmp-block={echo-request,echo-reply,timestamp-reply,timestamp-request} --permanent [root@localhost ~]# firewall-cmd --reload success # 查看是否生效[root@localhost ~]# firewall-cmd --list-icmp-blocks echo-request # 客户端测试 [ root@Demo ~]# ping 192.168.11.172 PING 192.168.11.172 (192.168.11.172) 56(84) bytes of data. From 192.168.11.172 icmp_seq=1 Packet filtered From 192.168.11.172 icmp_seq=2 Packet filtered From 192.168.11.172 icmp_seq=3 Packet filtered From 192.168.11.172 icmp_seq=4 Packet filtered ^C --- 192.168.11.172 ping statistics --- 4 packets transmitted, 0 received, +4 errors, 100% packet loss, time 3051ms # 移除禁 Ping [root@localhost ~]# firewall-cmd --remove-icmp-block=echo-request --permanent success [root@localhost ~]# firewall-cmd --reloadsuccess [root@localhost ~]# firewall-cmd --list-icmp-blocks # 还可以使用 rich-rule 来更精细地控制 ICMP 数据包的处理(禁 Ping) [root@localhost ~]# firewall-cmd --zone=public --add-rich-rule='rule protocol value=icmp drop' --permanent success [root@localhost ~]# firewall-cmd --reload success [root@localhost ~]# firewall-cmd --zone=public --list-rich-rulerule protocol value="icmp" drop # 客户端测试(使用这种方式配置后,再 Ping 不会有任何回显) [root@Demo ~]# ping 192.168.11.172 PING 192.168.11.172 (192.168.11.172) 56(84) bytes of data. # 移除禁 Ping [root@localhost ~]# firewall-cmd --zone=public --remove-rich-rule='rule protocol value=icmp drop' --permanent success [root@localhost ~]# firewall-cmd --reload success # 添加一条规则允许来自 192.168.1.1 的 ICMP echo-request(即 ping 请求)Firewall-cmd --zone=public --add-rich-rule='rule family="ipv4" source address="192.168.1.1" icmp-type name="echo-request" accept' --permanent # 重新加载防火墙规则使更改生效 Firewall-cmd --reload # 添加一条规则禁止来自 192.168.2.0/24 的 ICMP echo-request(即 ping 请求) firewall-cmd --zone=public --add-rich-rule='rule family="ipv4" source address="192.168.2.0/24" icmp-type name="echo-request" drop' --permanent # 重新加载防火墙规则使更改生效 firewall-cmd --reload
Traceroute 或 Tracepath 路由跟踪
这里将 traceroute 和 tracepath 路由跟踪防火墙配置拿出来单独说明,是因为 traceroute 路由跟踪的时候会用到一些特殊的端口号。
[root@localhost ~] [root@localhost ~] [root@Demo ~] traceroute to 192.168 .11.172 (192.168 .11.172 ), 30 hops max, 60 byte packets 1 192.168 .11.172 (192.168 .11.172 ) 0.409 ms 0 .336 ms 0 .300 ms # 禁用路由跟踪 [root @localhost ~]success [root@localhost ~] success [root@Demo ~] traceroute to 192.168 .11.172 (192.168 .11.172 ), 30 hops max, 60 byte packets 1 192.168 .11.172 (192.168 .11.172 ) 0.543 ms !X 0.473 ms !X 0.412 ms !X
IP 伪装 IP
伪装这个需求一般是用于内网用户通过防火墙 NAT 上网,或者信任区域到非信任区域等需求。这里我们输出一个简单需求,允许所有通过 eth1 接口的流量通过 eth0 接口伪装(masquerade)上网。
# 1. 启用伪装(Masquerade),一般公网 zone 为 pulic,确保 eth0 接口已经绑定至 public zone。 [root@localhost ~]# firewall-cmd --zone=public --add-masquerade --permanent # 2. 配置转发规则,允许 FORWARD 流量从 eth1 到 eth0 的流量转发。 [root@localhost ~]# firewall-cmd --permanent --direct --add-rule ipv4 filter FORWARD 0 -i eth1 -o eth0 -j ACCEPT # 3. 添加直接规则,确保所有从 eth1 出来的流量在通过 eth0 时进行伪装。这可以通过添加一个 NAT 表的 POSTROUTING 规则来实现。 [root@localhost ~]# firewall-cmd --permanent --direct --add-rule ipv4 nat POSTROUTING 0 -o eth0 -j MASQUERADE # 4. 应用更改,在添加所有规则后,您需要重新加载 `firewalld` 以应用更改: [root@localhost ~]# firewall-cmd --reload
NFQUEUE
其实在 firewalld 中还有一种访问规则的控制方式: NFQUEUE,NFQUEUE 是 Netfilter 提供的一种队列机制,它允许将网络数据包从内核空间发送到用户空间进行处理。这可以通过使用用户空间程序来实现对数据包的详细检查、修改或决定是否接受或拒绝数据包等高级操作。在 firewalld 中,NFQUEUE 可以用作一种特殊的目标(target),它允许您将匹配特定规则的数据包重定向到一个或多个 NFQUEUE 队列中。然后,用户空间程序可以从这些队列中读取数据包,进行处理,并将处理结果发送回内核,决定是丢弃数据包还是将其放行。如果您有了解过 Suricata 或 Snort 可能会比较清楚,您可以使用 NFQUEUE 来集成 Suricata 或 Snort 这样的入侵检测和防御系统(IDS/IPS),Suricata 或 Snort 系统可以深度分析通过 NFQUEUE 接收的数据包,并根据其内容决定下一步操作。
这里涉及很多 firewalld 的高级应用,大家可以参考文献中的 firewalld 官方文档。
文章引用自:https://rockylinux.cn/notes/rocky-linux-9-firewall-configuration.html