跳至内容

iptables 指南 firewalld - 简介

firewalld 作为默认防火墙推出时(它在 2011 年推出,但我认为它首次出现在 CentOS 7 中),作者继续使用 iptables。有以下两个原因。首先,当时 firewalld 的可用文档使用的是简单的规则,没有显示 firewalld 如何在 IP 级保护服务器。其次,作者有十多年的 iptables 使用经验,继续使用它比学习 firewalld 更容易。

本文档旨在解决大多数 firewalld 参考的局限性,并迫使作者使用 firewalld 来模仿那些更细粒度的防火墙规则。

从手册页: "firewalld 提供了一个动态管理的防火墙,支持网络/防火墙区域来定义网络连接或接口的信任级别。它支持 IPv4、IPv6 防火墙设置、以太网桥以及运行时和永久配置选项的分离。它还支持一个接口,供服务或应用程序直接添加防火墙规则。"

firewalld 实际上是 Rocky Linux 中 netfilter 和 nftables 内核子系统的前端。

本指南侧重于将 iptables 防火墙中的规则应用于 firewalld 防火墙。如果您是防火墙之旅的初学者,本文档 可能对您更有帮助。请考虑阅读这两篇文档,以充分利用 firewalld

先决条件和假设

  • 在本文档中,假设您是 root 用户或具有使用 sudo 的提升权限。
  • 对防火墙规则有一定了解,特别是 iptables,或者至少您想学习一些关于 firewalld 的知识。
  • 您能够在命令行中舒适地输入命令。
  • 本文档中的所有示例都使用 IPv4 IP。

区域

要真正理解 firewalld,您需要了解区域的使用。区域提供防火墙规则集的粒度。

firewalld 有几个内置区域

区域示例用途
drop丢弃传入连接,不回复 - 只允许传出数据包。
block拒绝传入连接,并使用 icmp-host-prohibited 消息(对于 IPv4)和 icmp6-adm-prohibited 消息(对于 IPv6) - 只有从该系统内部发起的网络连接是可能的。
public在公共区域使用 - 仅接受选定的传入连接。
外部仅接受选定的传入连接,用于在启用伪装的外部网络上使用。
DMZ仅接受选定的传入连接,用于您非军事化区中对公众可访问的计算机,这些计算机对您内部网络的访问有限。
工作适用于工作区中的计算机 - 仅接受选定的传入连接。
家庭适用于家庭区域 - 仅接受选定的传入连接。
内部用于您的内部网络设备访问 - 仅接受选定的传入连接。
信任接受所有网络连接。

注意

firewall-cmd 是用于管理 firewalld 守护程序的命令行程序。

要列出系统上的现有区域,请键入

firewall-cmd --get-zones

警告

请记住检查防火墙的状态,如果 firewalld-cmd 返回错误,请使用以下命令之一:

firewall-cmd 命令

$ firewall-cmd --state
running

systemctl 命令

$ systemctl status firewalld

作者不喜欢大多数这些区域名称。drop、block、public 和 trusted 很清楚,但有些不足以实现完美的粒度安全。以以下 iptables 规则部分为例

iptables -A INPUT -p tcp -m tcp -s 192.168.1.122 --dport 22 -j ACCEPT

您在这里允许单个 IP 地址通过 SSH(端口 22)连接到服务器。如果您决定使用内置区域,则可以使用“trusted”来执行此操作。首先,将 IP 添加到区域,然后将规则应用于该区域

firewall-cmd --zone=trusted --add-source=192.168.1.122 --permanent
firewall-cmd --zone trusted --add-service=ssh --permanent

但是,如果此服务器上还有仅对组织分配的 IP 块可访问的内部网,您是否会将“internal”区域应用于该规则?作者更喜欢创建一个处理管理员 IP(允许安全外壳连接到服务器的 IP)的区域。

添加区域

要添加区域,您需要使用带有 --new-zone 参数的 firewall-cmd。您将添加“admin”(表示管理)作为区域

firewall-cmd --new-zone=admin --permanent

注意

作者在整个过程中经常使用 --permanent 标志。对于测试,建议在没有 --permanent 标志的情况下添加规则,测试它,如果它按预期工作,则在运行 firewall-cmd --reload 之前使用 firewall-cmd --runtime-to-permanent 将规则移动到活动状态。如果风险较低(换句话说,您不会将自己锁定在系统之外),则可以像这里所做的那样添加 --permanent 标志。

在使用此区域之前,您需要重新加载防火墙

firewall-cmd --reload

提示

关于自定义区域的说明:如果您需要添加一个将成为受信任区域的区域,但该区域只包含特定的源 IP 或接口,而不包含任何协议或服务,“trusted”区域不适合您,可能是因为您已经将其用于其他用途等。您可以添加一个自定义区域来执行此操作,但您必须将区域的目标从“default”更改为“ACCEPT”(REJECT 或 DROP 也可以使用,具体取决于您的目标)。以下是一个在 LXD 机器上使用桥接接口(在本例中为 lxdbr0)的示例。

首先,添加区域并重新加载,以便您可以使用它

firewall-cmd --new-zone=bridge --permanent
firewall-cmd --reload

接下来,将区域的目标从“default”更改为“ACCEPT”(注意,更改目标需要 --permanent 选项),然后分配接口,并重新加载

firewall-cmd --zone=bridge --set-target=ACCEPT --permanent
firewall-cmd --zone=bridge --add-interface=lxdbr0 --permanent
firewall-cmd --reload

这告诉防火墙您

  1. 正在将区域的目标更改为 ACCEPT
  2. 正在将桥接接口“lxdbr0”添加到区域
  3. 正在重新加载防火墙

所有这些都表明您接受来自桥接接口的所有流量。

列出区域

在继续之前,您需要检查列出区域的过程。您将获得一个单列输出,而不是 iptables -L 提供的表格输出。使用 firewall-cmd --zone=[zone_name] --list-all 命令列出区域。以下是在列出新创建的“admin”区域时的情况

firewall-cmd --zone=admin --list-all

admin
  target: default
  icmp-block-inversion: no
  interfaces:
  sources:
  services:
  ports:
  protocols:
  forward: no
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:

您可以使用以下命令列出系统上的活动区域

firewall-cmd --get-active-zones

重要:活动区域

区域只能在满足以下两种条件之一的情况下处于活动状态

  1. 该区域已分配给网络接口。
  2. 该区域已分配源 IP 或网络范围。

从区域中删除 IP 和服务

如果您遵循了之前的说明将 IP 添加到“trusted”区域,那么您现在必须将其删除。请记住我们关于使用 --permanent 标志的说明?这是一个避免在进行适当测试之前使用它,然后再将此规则投入生产的好地方

firewall-cmd --zone=trusted --remove-source=192.168.1.122

您还希望从区域中删除 SSH 服务

firewall-cmd --zone=trusted --remove-service ssh

然后进行测试。您需要确保在执行最后两个步骤之前,可以通过另一个区域的 ssh 进行连接。(参见下面的警告!)。如果您没有进行其他更改,则“public”区域仍然允许 SSH,因为它是默认情况下存在的。

一旦您满意,将运行时规则移动到永久状态

firewall-cmd --runtime-to-permanent

并重新加载

firewall-cmd --reload

警告

如果您正在远程服务器或 VPS 上工作,请不要执行最后一条指令!永远不要从远程服务器中删除 ssh 服务,除非您有其他方法访问外壳程序(见下文)。

假设您通过防火墙锁定了对 ssh 访问的权限。在这种情况下,您将需要(在最坏的情况下)亲自修复服务器、联系支持,或者可能从控制面板重新安装操作系统(取决于服务器是物理的还是虚拟的)。

使用新区域 - 添加管理 IP

现在,只需重复我们使用“admin”区域的原始步骤

firewall-cmd --zone=admin --add-source=192.168.1.122
firewall-cmd --zone admin --add-service=ssh

列出区域,以确保区域看起来正确,并且已正确添加服务

firewall-cmd --zone=admin --list-all

测试您的规则以确保它有效。要进行测试

  1. 以 root 用户或具有 sudo 权限的用户身份,从您的源 IP(上面是 192.168.1.122)登录 SSH(使用 root 用户是因为您将运行需要该用户的命令。如果您使用 sudo 用户,请记住在连接后运行 sudo -s)。
  2. 连接后,运行 tail /var/log/secure,您将获得类似于以下内容的输出
Feb 14 22:02:34 serverhostname sshd[9805]: Accepted password for root from 192.168.1.122 port 42854 ssh2
Feb 14 22:02:34 serverhostname sshd[9805]: pam_unix(sshd:session): session opened for user root by (uid=0)

这表明我们的 SSH 连接的源 IP 与您刚刚添加到“admin”区域的 IP 相同。您将可以安全地将此规则移动到永久状态

firewall-cmd --runtime-to-permanent

完成添加规则后,请重新加载

firewall-cmd --reload

您可能需要将其他服务添加到“admin”区域,但 SSH 目前是最合理的。

警告

默认情况下,“public”区域启用了 ssh 服务;这可能是一个安全漏洞。创建管理区域后,将其分配给 ssh 并进行测试,您可以从 public 区域中删除该服务。

如果您需要添加多个管理 IP(很可能),只需将其添加到区域的源。在本例中,您将 IP 添加到“admin”区域

firewall-cmd --zone=admin --add-source=192.168.1.151 --permanent

注意

请记住,如果您正在远程服务器或 VPS 上工作,并且有一个并非始终使用相同 IP 的互联网连接,您可能希望将 ssh 服务打开到互联网服务提供商或地理区域使用的 IP 地址范围。再次,这样做是为了防止您被自己的防火墙锁定在系统之外。

许多 ISP 会对专用 IP 地址收取额外费用,如果他们提供的话,因此这是一个真正的担忧。

这里的示例假设您正在使用您自己私有网络上的 IP 来访问同样是本地的服务器。

ICMP 规则

检查另一个您想要在 firewalld 中模拟的 iptables 防火墙行 - ICMP 规则

iptables -A INPUT -p icmp -m icmp --icmp-type 8 -s 192.168.1.136 -j ACCEPT

对于我们中的新手来说,ICMP 是一种数据传输协议,专为错误报告而设计。它告诉您何时连接到机器存在问题。

实际上,您可能会将 ICMP 打开到我们所有本地 IP(在本例中为 192.168.1.0/24)。我们的“public”和“admin”区域默认情况下会启用 ICMP,因此,要将 ICMP 限制为那个网络地址,首先要做的就是阻止“public”和“admin”区域上的这些请求。

同样,这是为了演示目的。您肯定希望您的管理用户能够与您的服务器进行 ICMP 连接,而且他们可能仍然能够进行连接,因为它们是 LAN 网络 IP 的成员。

要关闭“public”区域上的 ICMP

firewall-cmd --zone=public --add-icmp-block={echo-request,echo-reply} --permanent

在我们的“trusted”区域上执行相同的操作

firewall-cmd --zone=trusted --add-icmp-block={echo-request,echo-reply} --permanent

以下是关于新事物的介绍:花括号“{}”允许我们指定多个参数。与往常一样,在进行此类更改后,您需要重新加载

firewall-cmd --reload

从不允许的 IP 使用 ping 进行测试,您将获得

ping 192.168.1.104
PING 192.168.1.104 (192.168.1.104) 56(84) bytes of data.
From 192.168.1.104 icmp_seq=1 Packet filtered
From 192.168.1.104 icmp_seq=2 Packet filtered
From 192.168.1.104 icmp_seq=3 Packet filtered

Web 服务器端口

以下是允许 httphttps(服务网页所需的协议)的 iptables 脚本

iptables -A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp -m tcp --dport 443 -j ACCEPT

以下是您可能已经多次见过的 firewalld 等效脚本

firewall-cmd --zone=public --add-service=http --add-service=https --permanent

这很好,但是如果例如您正在运行 Nextcloud 服务,该服务在 http/https 上运行,而您只想让受信任的网络访问它呢?这并不罕见!这种情况经常发生,仅仅公开允许流量,而不考虑谁真正需要访问,是一个巨大的安全风险。

您实际上不能使用上面使用的“trusted”区域信息。那是为了测试。您必须假设您至少将 LAN IP 块添加到了“trusted”。这将如下所示

firewall-cmd --zone=trusted --add-source=192.168.1.0/24 --permanent

将服务添加到区域

firewall-cmd --zone=trusted --add-service=http --add-service=https --permanent

如果您将这些服务添加到“public”区域,则需要将其删除

firewall-cmd --zone=public --remove-service=http --remove-service=https --permanent

重新加载

firewall-cmd --reload

FTP 端口

回到 iptables 脚本。您有以下处理 FTP 的规则

iptables -A INPUT -p tcp -m tcp --dport 20-21 -j ACCEPT
iptables -A INPUT -p tcp -m tcp --dport 7000-7500 -j ACCEPT

脚本的这部分处理标准 FTP 端口(20 和 21)以及一些额外的被动端口。FTP 服务器(例如 VSFTPD)通常需要此类规则。通常,此类规则将位于面向公众的 Web 服务器上,用于允许来自客户的 FTP 连接。

firewalld 中不存在 ftp-data 服务(端口 20)。这里列出的 7000 到 7500 端口用于被动 FTP 连接,同样,它们在 firewalld 中也不存在作为服务。您可以切换到 SFTP,这简化了这里的端口允许规则,并且可能是推荐的方式。

这演示了将一组 iptables 规则转换为 firewalld。为了解决所有这些问题,您可以执行以下操作。

首先,将 ftp 服务添加到也托管 Web 服务的区域。在本例中,这可能是“public”

firewall-cmd --zone=public --add-service=ftp --permanent

添加 ftp-data 端口

firewall-cmd --zone=public --add-port=20/tcp --permanent

添加被动连接端口

firewall-cmd --zone=public --add-port=7000-7500/tcp --permanent

然后重新加载

firewall-cmd --reload

数据库端口

如果您正在处理 Web 服务器,那么您几乎肯定正在处理数据库。您对数据库的访问控制应与其他服务一样谨慎。如果不需要来自外部世界的访问,请将您的规则应用于“public”以外的其他内容。另一个考虑因素是,您是否需要提供访问权限?同样,这可能取决于您的环境。作者之前所在的公司,为客户使用托管 Web 服务器。许多人拥有 Wordpress 网站,他们都没有真正需要或请求对 MariaDB 的任何前端进行访问。如果客户需要更多访问权限,我们的解决方案是为他们的 Web 服务器创建 LXD 容器,按照客户想要的方式构建防火墙,并将他们对该服务器上发生的事情负责。不过,如果您的服务器是公开的,您可能需要提供对 phpmyadmin 或其他 MariaDB 前端的访问权限。在这种情况下,您需要关注数据库的密码要求,并将数据库用户设置为非默认值。对于作者来说,密码长度是创建密码时最主要的考虑因素.

密码安全性是另一份处理该问题的文档中的讨论内容。假设您对数据库访问权限有良好的密码策略,并且防火墙中处理数据库的 iptables 行如下所示

iptables -A INPUT -p tcp -m tcp --dport=3600 -j ACCEPT

在这种情况下,将服务添加到 firewalld 转换的“public”区域

firewall-cmd --zone=public --add-service=mysql --permanent

Postgresql 注意事项

Postgresql 使用其服务端口。这是一个 IP 表规则示例

iptables -A INPUT -p tcp -m tcp --dport 5432 -s 192.168.1.0/24 -j ACCEPT

虽然在面向公众的 Web 服务器上不太常见,但作为内部资源可能更常见。相同的安全注意事项适用。如果您在受信任的网络(在我们的示例中为 192.168.1.0/24)上有一个服务器,您可能不希望或不需要向该网络上的所有人提供访问权限。Postgresql 具有可用于更细粒度访问权限的访问列表。我们的 firewalld 规则看起来像这样

firewall-cmd --zone=trusted --add-service=postgresql

DNS 端口

拥有私有或公共 DNS 服务器也意味着在您编写的规则中采取预防措施以保护这些服务。如果您有一个私有 DNS 服务器,其 iptables 规则如下所示(请注意,大多数 DNS 服务是 UDP 而不是 TCP,但并不总是这样)

iptables -A INPUT -p udp -m udp -s 192.168.1.0/24 --dport 53 -j ACCEPT

那么只允许您的“trusted”区域是正确的。您已经设置了“trusted”区域的源。您需要做的就是将服务添加到该区域

firewall-cmd --zone=trusted --add-service=dns

对于面向公众的 DNS 服务器,您只需要将相同的服务添加到“public”区域

firewall-cmd --zone=public --add-service=dns

关于列出规则的更多信息

注意

您可以通过列出 nftables 规则来列出所有规则。它很丑陋,我不推荐它,但如果您真的必须这样做,您可以执行 nft list ruleset

到目前为止,没有做太多的一件事就是列出规则。您可以按区域执行此操作。以下是您已使用的区域的示例。请注意,您可以在将规则永久化之前列出该区域,这是一个好主意。

firewall-cmd --list-all --zone=trusted

在这里,您可以看到您在上面应用的内容

trusted (active)
  target: ACCEPT
  icmp-block-inversion: no
  interfaces:
  sources: 192.168.1.0/24
  services: dns
  ports:
  protocols:
  forward: no
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks: echo-reply echo-request
  rich rules:

这适用于任何区域。例如,这是到目前为止的“public”区域

firewall-cmd --list-all --zone=public

public
  target: default
  icmp-block-inversion: no
  interfaces:
  sources:
  services: cockpit dhcpv6-client ftp http https
  ports: 20/tcp 7000-7500/tcp
  protocols:
  forward: no
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks: echo-reply echo-request
  rich rules:

请注意,您已从服务中删除了 SSH 访问权限并阻止了 ICMP“echo-reply”和“echo-request”。

到目前为止,在您的“admin”区域中,它看起来像这样

firewall-cmd --list-all --zone=admin

  admin (active)
  target: default
  icmp-block-inversion: no
  interfaces:
  sources: 192.168.1.122 192.168.1.151
  services: ssh
  ports:
  protocols:
  forward: no
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:

看来 firewalld 默认情况下在内部处理以下 iptables 规则

iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

接口

默认情况下,firewalld 将监听所有可用的接口。在具有许多面向许多网络网关的接口的裸机服务器上,您需要根据其所面向的网络将接口分配给区域。

我们的示例中没有添加接口,因为实验室使用 LXD 进行测试。在这种情况下,您只有一个接口可以使用。假设您的“public”区域需要配置使用以太网端口 enp3s0,因为该端口具有公共 IP 地址,并且假设您的“trusted”和“admin”区域位于 LAN 接口上,这可能是 enp3s1。

要将这些区域分配给相应的接口,请使用以下命令

firewall-cmd --zone=public --change-interface=enp3s0 --permanent
firewall-cmd --zone=trusted --change-interface=enp3s1 --permanent
firewall-cmd --zone=admin --change-interface=enp3s1 --permanent
firewall-cmd --reload

常见的 firewall-cmd 命令

您已经使用过一些命令。以下是一些更常见的命令及其功能

命令结果
firewall-cmd --list-all-zones类似于 firewall-cmd --list-all --zone=[zone],只是它列出了所有区域及其内容。
firewall-cmd --get-default-zone显示默认区域,除非您更改它,否则为“public”。
firewall-cmd --list-services --zone=[zone]显示为该区域启用的所有服务。
firewall-cmd --list-ports --zone=[zone]显示在该区域上打开的所有端口。
firewall-cmd --get-active-zones显示系统上的活动区域、其活动接口、服务和端口。
firewall-cmd --get-services显示所有可用的服务,可供使用。
firewall-cmd --runtime-to-permanent如果您在没有 --permanent 选项的情况下输入了许多规则,请在重新加载之前执行此操作。

这里没有涵盖很多 firewall-cmd 选项,但这为您提供了最常用的命令。

结论

由于 firewalld 是 Rocky Linux 中推荐并包含的防火墙,因此了解其工作原理是一个好主意。firewalld 文档中包含的简单规则通常不考虑服务器的使用情况,并且除了公开允许服务之外,不提供其他选项。这是安全漏洞的缺陷,这些漏洞根本不需要存在。

当您看到这些说明时,请考虑您的服务器的使用情况以及该服务是否需要向全世界开放。如果不是,请考虑按照上述方法在您的规则中应用更多粒度。

这并非要成为 firewalld 的详尽指南,而只是一个起点。

作者:Steven Spencer

贡献者:wsoyinka、Antoine Le Morvan、Ezequiel Bruni、qyecst、Ganna Zhyrnova