介绍
将应用程序设置中的离散组件部署到不同的节点是减少负载和开始水平扩展的常用方法。 一个典型的例子是在与您的应用程序不同的服务器上配置数据库。 虽然这种设置有很多优点,但通过网络连接涉及到一系列新的安全问题。
在本指南中,我们将演示如何在分布式设置中的每台服务器上设置简单的防火墙。 我们将配置我们的策略以允许我们的组件之间的合法流量,同时拒绝其他流量。
对于本指南中的演示,我们将使用两台 Ubuntu 14.04 服务器。 一个将拥有一个使用 Nginx 服务的 WordPress 实例,另一个将托管应用程序的 MySQL 数据库。 尽管我们将使用此设置作为示例,但您应该能够推断所涉及的技术以满足您自己的服务器要求。
先决条件
要开始使用,您必须拥有两台全新的 Ubuntu 14.04 服务器。 添加一个具有 sudo
权限的普通用户帐户。 要了解如何正确执行此操作,请遵循我们的 Ubuntu 14.04 初始服务器设置指南 。
我们将保护的应用程序设置基于 本指南 。 如果您想继续学习,请按照该教程的指示设置您的应用程序和数据库服务器。
设置基本防火墙
我们将从为我们的每台服务器实施基线防火墙配置开始。 我们将实施的政策采用安全第一的方法。 我们将锁定除 SSH 流量之外的几乎所有内容,然后为我们的特定应用程序在防火墙中戳洞。
本指南中的防火墙提供了我们需要的基本设置。 安装iptables-persistent
包,将基本规则粘贴到/etc/iptables/rules.v4
文件中:
sudo apt-get update sudo apt-get install iptables-persistent sudo nano /etc/iptables/rules.v4
/etc/iptables/rules.v4
*filter # Allow all outgoing, but drop incoming and forwarding packets by default :INPUT DROP [0:0] :FORWARD DROP [0:0] :OUTPUT ACCEPT [0:0] # Custom per-protocol chains :UDP - [0:0] :TCP - [0:0] :ICMP - [0:0] # Acceptable UDP traffic # Acceptable TCP traffic -A TCP -p tcp --dport 22 -j ACCEPT # Acceptable ICMP traffic # Boilerplate acceptance policy -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT -A INPUT -i lo -j ACCEPT # Drop invalid packets -A INPUT -m conntrack --ctstate INVALID -j DROP # Pass traffic to protocol-specific chains ## Only allow new connections (established and related should already be handled) ## For TCP, additionally only allow new SYN packets since that is the only valid ## method for establishing a new TCP connection -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 # Reject anything that's fallen through to this point ## Try to be protocol-specific w/ rejection message -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 the changes 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
如果您在实时环境中实现此功能 ,请不要重新加载防火墙规则 。 加载此处概述的基本规则集将立即断开应用程序和数据库服务器之间的连接。 在重新加载之前,我们需要调整规则以反映我们的操作需求。
发现您的服务使用的端口
为了添加例外以允许我们的组件之间进行通信,我们需要知道正在使用的网络端口。 我们可以通过检查我们的配置文件找到正确的网络端口,但是找到正确端口的一种与应用程序无关的方法是只检查哪些服务正在侦听我们每台机器上的连接。
我们可以使用 netstat
工具来找出这一点。 由于我们的应用程序仅通过 IPv4 进行通信,因此我们将添加 -4
参数,但如果您也使用 IPv6,则可以将其删除。 为了找到我们正在运行的服务,我们需要的其他参数是 -plunt
。
在您的 Web 服务器上,我们会看到如下内容:
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 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(已在防火墙规则中说明)
调整 Web 服务器防火墙规则
现在我们有了所需的端口信息,我们将调整 Web 服务器的防火墙规则集。 使用 sudo
权限在编辑器中打开规则文件:
sudo nano /etc/iptables/rules.v4
在 Web 服务器上,我们需要将端口 80 添加到可接受流量列表中。 由于服务器正在侦听所有可用地址,因此我们不会通过接口或目标地址来限制规则。
我们的网络访问者将使用 TCP 协议进行连接。 我们的基本框架已经有一个自定义链,称为 TCP
用于 TCP 应用程序异常。 我们可以将端口 80 添加到该链中,就在我们的 SSH 端口的例外下方:
/etc/iptables/rules.v4
*filter . . . # Acceptable TCP traffic -A TCP -p tcp --dport 22 -j ACCEPT -A TCP -p tcp --dport 80 -j ACCEPT . . .
我们的网络服务器将启动与我们的数据库服务器的连接。 我们的传出流量在我们的防火墙中不受限制,并且允许与已建立连接相关的传入流量,因此我们不必在此服务器上打开任何其他端口来允许此连接。
完成后保存并关闭文件。 我们的网络服务器现在有一个防火墙策略,允许所有合法流量,同时阻止其他一切。
测试您的规则文件是否有语法错误:
sudo iptables-restore -t < /etc/iptables/rules.v4
如果没有显示语法错误,请重新加载防火墙以实施新规则集:
sudo service iptables-persistent reload
调整数据库服务器防火墙规则
在我们的数据库服务器上,我们需要允许访问我们服务器私有 IP 地址上的端口 3306
。 在我们的例子中,该地址是 192.0.2.30
。 我们可以专门限制对该地址的访问,或者我们可以通过匹配分配该地址的接口来限制访问。
要查找与该地址关联的网络接口,请键入:
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
链添加一条规则,以形成我们的 Web 和数据库服务器之间的连接的例外。
如果您希望根据相关的实际地址限制访问,您可以添加如下规则:
/etc/iptables/rules.v4
*filter . . . # Acceptable TCP traffic -A TCP -p tcp --dport 22 -j ACCEPT -A TCP -p tcp --dport 3306 -d 192.0.2.30 -j ACCEPT . . .
如果您希望基于包含该地址的接口允许异常,则可以添加与此类似的规则:
/etc/iptables/rules.v4
*filter . . . # Acceptable TCP traffic -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 的两台服务器来提供 WordPress 实例来演示此配置,但无论您选择何种特定技术,上述技术都适用。
要详细了解防火墙和 iptables
,请查看以下指南: