如何在Ubuntu16.04上使用Stunnel加密到Redis的流量

来自菜鸟教程
跳转至:导航、​搜索

介绍

Redis 是一个开源的键值对数据存储,使用内存存储模型和可选的磁盘写入来实现持久性。 它具有事务、发布/订阅消息模式和自动故障转移等功能。 Redis 有用大多数语言编写的客户端, 他们的网站 上有推荐的客户端。

Redis 本身不提供任何加密功能。 它的运行假设是它已部署到一个隔离的专用网络,只有受信任的方可以访问。 如果您的环境不符合该假设,您将不得不单独将 Redis 流量包装在加密中。

在本指南中,我们将演示如何使用称为 stunnel 的安全隧道程序加密 Redis 流量。 Redis 客户端和服务器之间的流量将通过专用的 SSL 加密隧道进行路由。 我们将使用两台 Ubuntu 16.04 服务器进行演示。

先决条件

首先,您应该在每台机器上配置一个具有 sudo 权限的非 root 用户。 此外,本指南将假设您有一个基本的防火墙。 您可以按照我们的 Ubuntu 16.04 初始服务器设置指南 来满足这些要求。

当您准备好继续时,请按照以下说明进行操作。

什么是stunnel?

对于基本的加密通信,stunnel 实用程序易于安装和配置。 它支持两台机器之间的加密转发。 客户端连接到本地端口,stunnel 在将其转发到远程服务器之前对其进行加密包装。 在服务器端,stunnel 侦听配置的端口并解密流量,然后将其转发到本地端口(在我们的例子中,Redis 服务器侦听的端口)。

使用 stunnel 的一些优点是:

  • Ubuntu 在其默认存储库中维护 stunnel 的软件包
  • Ubuntu 包含一个 init 脚本,用于在启动时自动启动进程
  • 配置简单直观
  • 每个目的都使用一条新隧道。 在某些情况下,这可能是一个缺点,但它提供了对访问的精细控制。

一些缺点是:

  • 客户端通过附加到非默认本地端口来连接到远程机器,这起初可能不直观。
  • 如果连接两台 Redis 服务器进行复制或集群,则必须在每台机器上配置两条隧道用于服务器到服务器的通信(一条用于出站流量,一条用于入站流量)。

考虑到这些特征,让我们开始吧。

安装 Redis 服务器和客户端软件包

在开始之前,我们应该在一台机器上安装 Redis 服务器,在另一台机器上安装客户端包。 如果您已经配置了其中一项或两项,请随时跳过。

注意: Redis 服务器指令设置了一个测试密钥,稍后将用于测试连接。 如果您已经安装了 Redis 服务器,您可以继续设置此密钥或在我们测试连接时使用任何其他已知密钥。


安装 Redis 服务器

我们将使用 Chris Lea 的 Redis 服务器 PPA 来安装最新版本的 Redis。 使用第三方存储库时请务必小心。 在这种情况下,Chris Lea 是一个值得信赖的打包者,他为几个流行的开源项目维护高质量、最新的包。

添加 PPA 并在您的第一台计算机上安装 Redis 服务器软件,方法是键入:

sudo apt-add-repository ppa:chris-lea/redis-server
sudo apt-get update
sudo apt-get install redis-server

在此过程中输入 Enter 接受提示。

安装完成后,输入以下命令测试是否可以在本地连接到 Redis 服务:

redis-cli ping

如果软件已安装并正在运行,您应该会看到:

Redis server outputPONG

让我们设置一个稍后可以使用的密钥:

redis-cli set test 'success'

我们已将 test 键设置为值 success。 在配置 stunnel 后,我们将尝试从我们的客户端计算机访问此密钥。

安装 Redis 客户端

另一台 Ubuntu 16.04 机器将充当客户端。 我们需要的所有软件都可以在默认存储库的 redis-tools 包中找到:

sudo apt-get update
sudo apt-get install redis-tools

由于远程 Redis 服务器的默认配置和防火墙处于活动状态,我们目前无法连接到远程 Redis 实例进行测试。

在每台计算机上安装和启用 stunnel

接下来,您需要在每个服务器和客户端上安装 stunnel。 Ubuntu 在其默认存储库中包含该实用程序的第四版,称为 stunnel4。 如果您不需要在上一节中安装任何东西,请确保在安装前包含 sudo apt-get update 命令以刷新您的包索引:

# sudo apt-get update
sudo apt-get install stunnel4

Ubuntu 上的 stunnel 服务使用较旧的 SysVinit 脚本启动,可由 systemd 管理。 而不是使用本机 systemd 方法,要将服务配置为在启动时启动,您必须修改 /etc/default/stunnel4 文件:

sudo nano /etc/default/stunnel4

通过将 ENABLED 选项设置为“1”,使服务在启动时启动:

/etc/default/stunnel4

. . .
ENABLED=1
. . .

保存并关闭每台服务器上的文件。

接下来,我们将创建用于加密通信的自签名 SSL 证书和密钥。

在 Redis 服务器上创建自签名 SSL 证书和密钥

在您的 Redis 服务器上,在 /etc/stunnel 目录中创建一个自签名 SSL 证书和密钥。 这将用于加密 stunnel 的两个实例之间的连接。 我们将使用名称 redis-server 来指代证书和密钥文件:

sudo openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout /etc/stunnel/redis-server.key -out /etc/stunnel/redis-server.crt

系统将提示您输入有关您正在创建的证书的信息。 由于这只会在内部使用,因此值并不重要,因此请填写您想要的任何内容。 您可以在下面看到一个示例:

Redis server output. . .
-----
Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:New York
Locality Name (eg, city) []:New York City
Organization Name (eg, company) [Internet Widgits Pty Ltd]:DigitalOcean
Organizational Unit Name (eg, section) []:Community
Common Name (e.g. server FQDN or YOUR name) []:redis-server
Email Address []:admin@example.com

通过键入以下内容来限制对生成的 .key 文件的访问:

sudo chmod 600 /etc/stunnel/redis-server.key

现在我们有了 SSL 证书和密钥,我们可以创建 Redis 服务器的 stunnel 配置文件。

创建 Redis 服务器 stunnel 配置文件

在 Redis 服务器上的 /etc/stunnel 目录中打开一个以 .conf 结尾的文件以开始使用:

sudo nano /etc/stunnel/redis.conf

在里面,指定一个位置以在主要部分中写入 PID 文件。 /run 目录旨在存储这些类型的文件,因此我们将使用它:

/etc/stunnel/redis.conf

pid = /run/stunnel-redis.pid

接下来,创建一个部分来配置对 Redis 服务的访问。 您可以随意调用它(我们将其称为 redis-server)。 该部分将此配置与您以后可能需要在此计算机上配置的任何其他隧道分开。

我们需要分别使用 certkey 指令指定 Redis 服务器自己的证书和密钥的位置。

我们还将在这里定义传入数据的隧道。 我们希望 accept 加密流量到 Redis 服务器的外部 IP 地址上的默认 Redis 端口(端口 6379)。 然后,我们希望 connect 将该流量发送到 local 接口上的默认 Redis 端口,以存放解密的流量。 这是 Redis 服务实际监听的地方:

/etc/stunnel/redis.conf

pid = /run/stunnel-redis.pid

[redis-server]
cert = /etc/stunnel/redis-server.crt
key = /etc/stunnel/redis-server.key
accept = redis_servers_public_IP:6379
connect = 127.0.0.1:6379

完成后,保存并关闭文件。

重新启动 stunnel 并配置防火墙

现在在 Redis 服务器上配置了 stunnel,我们可以通过键入以下内容来重启服务:

sudo systemctl restart stunnel4.service

如果您检查 Redis 服务器上侦听连接的服务,您应该会在公共接口上看到 stunnel 正在侦听端口 6379。 您还应该看到 Redis 正在侦听本地接口上的同一端口:

sudo netstat -plunt
Redis server outputActive Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 public_IP:6379          0.0.0.0:*               LISTEN      4292/stunnel4   
tcp        0      0 127.0.0.1:6379          0.0.0.0:*               LISTEN      2679/redis-server 1
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1720/sshd       
tcp6       0      0 :::22                   :::*                    LISTEN      1720/sshd

尽管 stunnel 正在侦听公共接口,但防火墙可能尚未配置为允许流量通过。

要允许所有流量到端口 6379,请键入:

sudo ufw allow 6379

这将打开对 stunnel 正在侦听的公共接口上的端口 6379 的访问。 stunnel 端口只接受加密流量。

将证书分发给客户端

每个 Redis 客户端都需要一份 Redis 服务器证书文件的副本。 分发 .crt 文件的最简单方法是简单地将文件内容输出到服务器上,然后将内容复制到连接机器上的相应文件中。

通过键入以下内容在 Redis 服务器上输出 .crt 文件的内容:

cat /etc/stunnel/redis-server.crt
Redis server output-----BEGIN CERTIFICATE-----
MIIEGTCCAwGgAwIBAgIJALUdz8P8q8UPMA0GCSqGSIb3DQEBCwUAMIGiMQswCQYD
VQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENp

. . .

Tq7WJk77tk4nPI8iGv1WuK8xTAm5aOncxP16VoMpsDMV+GB1p3nBkMQ/GKF8pPXU
fn6BnDWKmeZqAlBM+MGYAfkbZWdBslrWasCJzs+tehTqL0LLJ6d3Gi9biBPb
-----END CERTIFICATE-----

将显示的证书 包括标记为 BEGIN CERTIFICATE 和 END CERTIFICATE 的行复制到剪贴板。

在客户端机器上,打开/etc/stunnel目录下的同名文件:

sudo nano /etc/stunnel/redis-server.crt

粘贴您从 Redis 服务器复制的内容。 完成后保存并关闭文件。

创建 Redis 客户端 stunnel 配置文件

现在客户端已经有了服务器证书的副本,我们可以配置客户端的 stunnel 配置。

在客户端机器上的 /etc/stunnel 目录中打开一个以 .conf 结尾的文件。 我们将再次调用文件 redis.conf

sudo nano /etc/stunnel/redis.conf

在里面,指定一个 PID 文件,服务将在其中再次存储其进程 ID:

/etc/stunnel/redis.conf

pid = /run/stunnel-redis.pid

接下来,添加一个部分来配置出站数据的隧道。 您可以随意命名(我们将其命名为 redis-client)。 该部分将此配置与您以后可能需要在此计算机上配置的任何其他隧道分开。

我们需要使用 client 指令将此部分显式标记为客户端配置。 设置 accept 指令以侦听本地接口上未使用的端口,以处理来自本地 Redis 客户端的连接(在本例中我们将使用端口 8000)。 将 connect 指令设置为 Redis 服务器的公共 IP 地址和我们打开的端口。

然后使用 CAfile 指向 Redis 服务器证书的副本。 我们还必须将 verify 设置为 4,这使得 stunnel 只检查证书而不考虑证书链(因为我们自签名证书):

/etc/stunnel/redis.conf

pid = /run/stunnel-redis.pid

[redis-client]
client = yes
accept = 127.0.0.1:8000
connect = remote_server_IP_address:6379
CAfile = /etc/stunnel/redis-server.crt
verify = 4

完成后保存并关闭文件。

重新启动客户端服务并测试连接

重启客户端的stunnel服务,实现修改:

sudo systemctl restart stunnel4.service

检查客户端上的隧道是否设置正确:

sudo netstat -plunt
Redis client outputActive Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 127.0.0.1:8000          0.0.0.0:*               LISTEN      3809/stunnel4   
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1714/sshd       
tcp6       0      0 :::22                   :::*                    LISTEN      1714/sshd

如您所见,stunnel 正在本地端口 8000 上侦听连接。

现在,您应该能够通过将客户端指向本地接口上的端口 8000 来连接到远程 Redis 实例:

redis-cli -p 8000 ping
Redis client outputPONG

查询我们在本指南开头设置的测试密钥:

redis-cli -p 8000 get test
Redis client output"success"

这确认我们能够成功访问远程数据库。

为了确认我们无法不使用隧道与远程Redis服务器通信,我们可以尝试直接连接远程端口:

redis-cli -h redis_server_public_IP -p 6379 ping
Redis client outputError: Connection reset by peer

如您所见,只有在通过隧道正确加密的情况下,远程 Redis 端口才接受流量。

将上述示例扩展为多客户端和服务器到服务器通信

我们上面概述的示例使用了单个 Redis 服务器和单个客户端的简单示例。 但是,这些相同的方法可以应用于更复杂的交互。

扩展此示例以处理多个客户端很简单。 您需要执行上述操作。

  • 在新客户端上安装 Redis 客户端软件和 stunnel
  • 使stunnel软件开机启动
  • 将服务器的证书文件复制到/etc/stunnel目录下
  • stunnel客户端配置文件复制到新的客户端机器
  • 重启stunnel服务

要设置安全的服务器到服务器通信(例如,用于复制或集群),您需要设置两个并行隧道:

  • 在新服务器上,安装 Redis 服务器包和 stunnel
  • 使stunnel软件开机启动
  • 为新的 Redis 服务器生成新的证书和密钥文件(为文件使用唯一名称)
  • 将每个证书文件从一台服务器复制到另一台服务器到 /etc/stunnel 目录
  • 在每个服务器(包括现有服务器)上编辑或创建 stunnel 配置文件,使其包含:
  • 在新的 Redis 服务器上打开防火墙中的外部端口
  • 通过调整 Redis 配置文件配置每个 Redis 实例连接到本地映射的端口以访问远程服务器(所需的指令取决于服务器的关系。 有关更多详细信息,请参阅 Redis 文档)。

两台服务器的 stunnel 配置文件如下所示:

用于服务器到服务器通信的 stunnel 配置文件

pid = /run/stunnel-redis.pid

[redis-server]
cert = /etc/stunnel/this_servers_certificate.crt
key = /etc/stunnel/this_servers_key.key
accept = this_servers_public_IP:6379
connect = 127.0.0.1:6379

[redis-client]
client = yes
accept = 127.0.0.1:arbitrary_local_port
connect = remote_servers_public_IP:6379
CAfile = /etc/stunnel/remote_servers_certificate.crt
verify = 4

如有必要,可以在每台机器上配置多个客户端部分,以将本地端口映射到远程服务器。 在这些情况下,请务必使用 accept 指令为每个远程服务器选择不同的未使用本地端口。

结论

Redis 是一个功能强大且灵活的工具,对于许多部署来说都是无价的。 但是,在不安全的环境中运行 Redis 是一项巨大的责任,会使您的服务器和数据容易受到攻击或盗窃。 如果您没有仅由受信任方组成的隔离网络,则必须通过其他方式保护流量。 本指南中概述的方法只是保护 Redis 各方之间通信的一种方法。 其他选项包括 隧道与 spiped设置 VPN