介绍
在应用程序设置中将离散组件部署到不同节点是减少负载并开始水平扩展的常见方式。一个典型的例子是将数据库配置在与应用程序不同的服务器上。虽然这种设置有许多优点,但通过网络连接涉及一系列新的安全问题。
在本指南中,我们将演示如何在分布式设置中为每个服务器设置防火墙。我们将配置策略以允许组件之间的预期流量,同时拒绝其他流量。
您还可以配置DigitalOcean的云防火墙,它作为DigitalOcean基础设施上额外的外部层运行在您的服务器上。这样,您就不必在服务器本身上配置防火墙。
在本指南中的演示中,我们将使用两个Ubuntu 22.04服务器。一个将使用Nginx提供Web应用程序,另一个将托管应用程序的MySQL数据库。虽然我们将使用此设置作为示例,但您应该能够推断出涉及的技术来适应您自己的服务器要求。
先决条件
要开始,您需要两台全新的Ubuntu 22.04服务器。在每台服务器上添加一个带有sudo
权限的常规用户帐户。要做到这一点,请遵循我们的Ubuntu 22.04初始服务器设置指南。
我们将要保护的应用程序设置基于这个指南。如果您想跟随该示例进行操作,请按照该教程指示设置您的应用程序和数据库服务器。否则,您可以将本文作为一个一般参考。
步骤1 — 设置防火墙
您将首先为每台服务器实施基线防火墙配置。我们将采取安全优先的策略。我们将锁定几乎所有内容,除了SSH流量,然后在防火墙中为我们的特定应用程序打洞。
本指南遵循iptables
语法。iptables
在Ubuntu 22.04上使用nftables
后端自动安装,因此您不必安装任何额外的软件包。
使用nano
或您喜欢的文本编辑器,打开/etc/iptables/rules.v4
文件:
- sudo nano /etc/iptables/rules.v4
从防火墙模板指南中粘贴配置:
*filter
# 允许所有出站流量,但默认情况下拒绝所有入站和转发数据包
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
# 自定义每个协议的链
:UDP - [0:0]
:TCP - [0:0]
:ICMP - [0:0]
# 可接受的UDP流量
# 可接受的TCP流量
-A TCP -p tcp --dport 22 -j ACCEPT
# 可接受的ICMP流量
# 标准接受策略
-A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
-A INPUT -i lo -j ACCEPT
# 拒绝无效数据包
-A INPUT -m conntrack --ctstate INVALID -j DROP
# 将流量传递到特定协议的链
## 仅允许新连接(已建立和相关的连接应已处理)
## 对于TCP,此外,仅允许新的SYN数据包,因为这是建立新TCP连接的唯一有效
## 方法
-A INPUT -p udp -m conntrack --ctstate NEW -j UDP
-A INPUT -p tcp --syn -m conntrack --ctstate NEW -j TCP
-A INPUT -p icmp -m conntrack --ctstate NEW -j ICMP
# 拒绝一切已到达此点的内容
## 尝试使用特定于协议的拒绝消息
-A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable
-A INPUT -p tcp -j REJECT --reject-with tcp-reset
-A INPUT -j REJECT --reject-with icmp-proto-unreachable
# 提交更改
COMMIT
*raw
:PREROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
COMMIT
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
COMMIT
*security
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
COMMIT
*mangle
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
COMMIT
保存并关闭文件。如果你在使用 nano
,按下 Ctrl+X
退出,然后在提示时,输入 Y
,然后按 Enter。
如果您正在实际环境中实施此操作,请勿重新加载防火墙规则。加载此处概述的规则集将立即中断您的应用程序与数据库服务器之间的连接。在重新加载之前,您需要调整规则以反映我们的运营需求。
步骤 2 — 发现您的服务正在使用的端口
为了允许您的组件之间通信,您需要知道正在使用的网络端口。您可以通过检查配置文件来找到正确的网络端口,但是一种与应用程序无关的找到正确端口的方法是检查我们每台机器上有哪些服务在监听连接。
您可以使用netstat
工具来找出这个信息。由于您的应用程序仅通过IPv4通信,我们将添加-4
参数,但如果您也使用IPv6,可以去掉该参数。您需要找到正在运行的服务的其他参数是-p
、-l
、-u
、-n
和-t
,您可以提供为-plunt
。
这些参数可以如下分解:
p
: Show the PID and name of the program to which each socket belongs.l
: Show only listening sockets.u
: Show UDP traffic.n
: Show numeric output instead of service names.t
: Show TCP traffic.
- sudo netstat -4plunt
在您的Web服务器上,输出可能如下所示:
OutputActive Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1058/sshd
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 4187/nginx
第一个高亮列显示了服务在行尾部分突出显示的IP地址和端口。特殊的0.0.0.0
地址意味着该服务正在监听所有可用地址。
在您的数据库服务器上,输出可能如下所示:
- sudo netstat -4plunt
OutputActive Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1097/sshd
tcp 0 0 192.0.2.30:3306 0.0.0.0:* LISTEN 3112/mysqld
您可以完全相同地阅读这些列。在此示例中,192.0.2.30
地址代表数据库服务器的私有IP地址。在前提教程中,您出于安全原因将MySQL限制在私有接口上。
记下您在此步骤中找到的值。这些是您需要调整防火墙配置的网络细节。
在您的Web服务器上,您需要确保以下端口是可访问的:
- 端口80对所有地址开放
- 端口22对所有地址开放(防火墙规则已经考虑到)
您的数据库服务器必须确保以下端口是可访问的:
- 地址
192.0.2.30
上的端口3306(或与之相关联的接口) - 端口22对所有地址开放(防火墙规则已经考虑到)
步骤3 — 调整 Web 服务器防火墙规则
现在您已经获得所需的端口信息,您将调整您的 Web 服务器防火墙规则集。以sudo
权限在编辑器中打开规则文件:
- sudo nano /etc/iptables/rules.v4
在 Web 服务器上,您需要将端口80添加到可接受流量的列表中。由于服务器正在监听所有可用地址 — 通常希望从任何地方访问的 Web 服务器 — 您不会通过接口或目标地址限制规则。
您的 Web 访问者将使用 TCP 协议进行连接。您的框架已经有一个名为TCP
的自定义链用于 TCP 应用程序异常。您可以在该链中添加端口80,在您的 SSH 端口异常下面:
*filter
. . .
# 可接受的 TCP 流量
-A TCP -p tcp --dport 22 -j ACCEPT
-A TCP -p tcp --dport 80 -j ACCEPT
. . .
系统: 您的Web服务器将启动与数据库服务器的连接。您的出站流量在防火墙中没有限制,与已建立的连接相关的入站流量是允许的,因此我们不必在此服务器上打开任何额外的端口来允许此连接。
完成后保存并关闭文件。您的Web服务器现在有一个防火墙策略,将允许所有合法的流量,同时阻止其他所有流量。
测试您的规则文件以查找语法错误:
- sudo iptables-restore -t < /etc/iptables/rules.v4
如果没有显示语法错误,请重新加载防火墙以实施新的规则集:
- sudo service iptables-persistent reload
步骤4 — 调整数据库服务器防火墙规则
在数据库服务器上,您需要允许访问服务器私有IP地址的端口3306
。在这种情况下,该地址为192.0.2.30
。您可以具体限制访问该地址,或者通过匹配分配了该地址的接口来限制访问。
要找到与该地址关联的网络接口,请运行ip -4 addr show scope global
:
- ip -4 addr show scope global
Output2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
inet 203.0.113.5/24 brd 104.236.113.255 scope global eth0
valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
inet 192.0.2.30/24 brd 192.0.2.255 scope global eth1
valid_lft forever preferred_lft forever
突出显示的区域显示eth1
接口与该地址关联。
接下来,您将调整数据库服务器上的防火墙规则。在数据库服务器上以sudo
权限打开规则文件:
- sudo nano /etc/iptables/rules.v4
再次,您将向我们的TCP
链添加一个规则,以形成对您的网站和数据库服务器之间连接的例外情况。
要根据实际地址限制访问权限,您可以像这样添加规则:
*filter
. . .
# 可接受的TCP流量
-A TCP -p tcp --dport 22 -j ACCEPT
-A TCP -p tcp --dport 3306 -d 192.0.2.30 -j ACCEPT
. . .
如果您宁愿根据承载该地址的接口允许该例外情况,您可以改为添加类似于此的规则:
*filter
. . .
# 可接受的TCP流量
-A TCP -p tcp --dport 22 -j ACCEPT
-A TCP -p tcp --dport 3306 -i eth1 -j ACCEPT
. . .
完成后保存并关闭文件。
使用此命令检查语法错误:
- sudo iptables-restore -t < /etc/iptables/rules.v4
准备好后,重新加载防火墙规则:
- sudo service iptables-persistent reload
现在,您的两个服务器应该受到保护,而不会限制它们之间数据的必要流动。
结论
在设置应用程序时,正确实施防火墙应始终是部署计划的一部分。尽管我们使用两台运行Nginx和MySQL的服务器演示了此配置,但上述演示的技术不论您的具体技术选择如何都是适用的。
要了解有关防火墙和iptables
的更多信息,请参阅以下指南: