内容


如何基于 spiped 建立一个安全的 Redis 集群

Comments

Redis 本身不提供 SSL/TLS 的支持,在需要安全访问的环境下,推荐使用 spiped 在 Redis 服务器和客户端建立一个对称性加密的安全通道。在单机模式下,Redis 只在一个端口下提供服务,这种安全通道很容易建立。但如果使用 Redis 集群,服务端口则一下拓展到 N*2 个,并且除了服务器到客户端,还需要建立 Redis 服务器节点之间的安全通道,本文将为您详细介绍如何去配制这样一个安全的 Redis 集群环境。

Redis 安全性简介

Redis 设计的初衷是应用于一个可信任的环境,因此 Redis 本身并没有在安全性上做更多的实现,而把重点放在了性能和易用性上面。当 Redis 服务运行于一个外网可以访问的环境下,Redis 的服务端口应该被防火墙禁止访问,Redis 客户端可以通过本机的回送地址 127.0.0.1 访问本机上的 Redis 服务,不足之处是其他机器上的客户端不能访问位于本机之外的 Redis 服务。除了使用防火墙外,Redis 还提供了保护模式,其本质是只监听在本机回送地址 127.0.0.1 这个网络接口上的 Redis 访问,并且这个保护模式是默认打开的。

无论通过防火墙禁用 Redis 服务端口,还是直接使用 Redis 保护模式,其本质都是只允许位于同一主机的 Redis 客户端通过本机回送地址 127.0.0.1 去访问 Redis 服务,而有些时候我们需要位于不同主机的 Redis 客户端去访问同一个 Redis 服务,这时 Redis 服务就不能只绑定在本机回送地址 127.0.0.1 上,而当 Redis 服务运行在一个公网环境下的时候,这就意味着其他主机也可以访问这个 Redis 服务,正如我们之前说到的,Redis 本身在安全性上并没有做过多的实现,客户端到服务端的通信也是不支持 SSL 访问的,这就存在一个很大的安全漏洞,因此 Redis 官网也推荐在公网或非信任的网络环境下,需要实现额外的安全配置,比如说使用 SSL 代理,并推荐使用 spiped。

Spiped 简介及如何用 spiped 去支持 Redis 单机版的安全访问

Spiped 是一个专门用来做对称加密和服务认证的应用,它的工作原理和 SSH 通道有些相似,但并不使用 SSH 协议,并且 spiped 依赖于一个认证双方共享的安全密钥来进行通信的对称加密。接下来我们将演示如何使用 spiped 来实现单机版 Redis 的安全访问。

  1. 确保 Redis.conf 配置文件中只绑定了 127.0.0.1 网络接口,并且 Redis 的服务端口为默认的 6379,启动单机版 Redis 服务。服务启动后,可以通过 redis-cli 来验证服务状态,直接运行 redis-cli 命令,就会默认连接本机回送地址 127.0.0.1 上端口为 6379 的服务。

    [root@kvm-010367 opt]# redis-cli

    127.0.0.1:6379> keys *

    (empty list or set)

    我们还可以同时测试下从物理网卡 IP 去连接 Redis 服务,这时连接会报错,因为 Redis 并没有在物理网卡 IP 上绑定服务。

    [root@kvm-010367 opt]# redis-cli -h 10.0.15.52

    Could not connect to Redis at 10.0.15.52:6379: Connection refused

    Could not connect to Redis at 10.0.15.52:6379: Connection refused

  2. 创建 spiped 安全通道共享密钥,如:

    dd if=/dev/urandom bs=32 count=1 of=/etc/spiped/redis.key

    在执行上述命令后,会生成一个随机的安全密钥文件在"/etc/spiped/redis.key"。

  3. 启动 Redis 服务端 spiped,如:

    spiped -F -d -s [10.0.15.52]:6379 -t [127.0.0.1]:6379 -k /etc/spiped/redis.key &

    这里 10.0.15.52 是 Redis 服务器的物理网卡地址,这条命令的意思是让 spiped 进程在源(source -s)IP 为 10.0.15.52 的网络接口上的 6379 端口监听,并将收到的消息用指定的共享密钥解密(-k 指定步骤 2 生成的共享密钥文件, -d 标志为解密 decrypt),并转发给目的(target -t)IP 为 127.0.0.1 网络接口的 6379 端口,即 Redis 的服务端口。

    在启动好 spiped 进程后,我们可以再次测试下步骤 1 中的从物理网卡 IP 去连接 Redis 服务:

    [root@kvm-010367 opt]# redis-cli -h 10.0.15.52

    10.0.15.52:6379>

    由于 spiped 进程在物理网卡的 6379 端口上监听,redis-cli 连接成功,但当我们去执行任何 Redis 命令时,都会失败,因为我们发送的命令都会被 spiped 用共享密钥解密,导致 Redis 服务接收到的命令无法被识别,这是正常的,因为我们还没有配置 spiped 安全通道的另外一端。

    [root@kvm-010367 opt]# redis-cli -h 10.0.15.52

    10.0.15.52:6379> keys *

    Error: Protocol error, got "/" as reply type byte

  4. 将步骤 2 生成的共享密钥文件复制到网络上的另一台主机,并在该主机上运行 Redis 客户端 spiped,如:

    spiped -F -e -s '[127.0.0.1]:6379' -t '[10.0.15.52]:6379' -k /etc/spiped/redis.key

    这里 10.0.15.52 是 Redis 服务器的物理网卡地址,这条命令的意思是让 spiped 进程在源(source -s)IP 为 127.0.0.1 的网络接口(redis 客户端本机回送地址)上的 6379 端口监听,并将收到的消息用指定的共享密钥加密(-k 指定步骤 2 生成的共享密钥文件, -e 标志为加密 encrypt),并转发给目的(target -t)IP 为 10.0.15.52 的 6379 端口,即步骤 3 在 Redis 服务器上开的 spiped 进程的监听地址。

    在启动好客户端 spiped 进程后,我们就可以在另外一台主机上以安全的方式访问运行在主机 10.0.15.52 上的 Redis 服务了。

    [root@kvm-010648 opt]# redis-cli

    127.0.0.1:6379> keys *

    (empty list or set)

    虽然我们在 Redis 客户端主机并没有运行 Redis 服务,但通过 spiped 我们在客户端的 127.0.0.1 的 6379 端口虚拟了一个 Redis 服务,并将请求以加密的方式转发到了真正的 Redis 服务器

    通过建立 spiped 安全通道,我们很好的解决了 Redis 的两个安全性问题,跨主机之间的 Redis 通信的认证和数据加密,只有拥有共享密钥的客户端才能使用在 Redis 服务器在物理网卡上提供的服务,并保证客户端和服务器端的通信是加密的。

Redi 集群简介

Redis 集群是在 Redis3.0 之后加入的,它为 Redis 提供了负载均衡和高可用性。

负载均衡是通过多个主节点共同存储数据来实现的,在 Redis 集群中,数据存储被划分成 16384 个分片,假设集群中的主节点数量为 N,则每个主节点存储 16384/N 个分片。在向 Redis 集群存储数据时,会根据数据键值的 CRC16 值去除以 16384 取余,并根据这个值去确定这个数据应该存储在哪一个 Redis 主节点。

高可用性是通过为每一个 Redis 主节点配置备份的从节点来实现的,在配置 Redis 集群的时候,每一个主节点都应该配置至少一个从节点,当主节点出错的情况下,Redis 集群会自动升级出错主节点的备份从节点做主节点,从而保证了 Redis 服务的高可用行。在主节点和它的所有从节点都宕机的情况下,由这个节点负责的存储分片则变的不可用,这时整个 Redis 集群将变的不可用。

Redis 集群节点与单机版的 Redis 节点略有不同,一个 Redis 集群节点需要开放两个服务端口,一个是命令端口,用于 Redis 数据存储和操作,这点与单节点的 Redis 一样,另外一个是集群总线端口,用于集群状态的管理,这个端口永远是节点的命令端口+10000,在配置 Redis 集群的时候只需要指定集群节点的命令端口,集群总线端口将自动生成,如命令端口为 6379,则集群总线端口为 16379,在配置的集群的时候需要保证这两个端口都没有被占用,并能够被其他集群节点访问。

当我们使用 Redis 集群的时候,我们需要的是它的负载均衡和高可用性,这也要求集群中的 Redis 节点位于不同的主机,也就是说 Redis 集群节点的命令端口和总线端口都必须绑定到物理网卡 IP 上,这样节点才能被其他 Redis 集群节点访问,组成 Redis 集群。而当我们部署一个 Redis 集群的时候,在特殊的网络环境下,我们往往需要客户端到集群节点,集群节点之间的数据通信是加密的,并且只有信任的客户端才能访问 Redis 服务,使用 spiped 同样能很好的解决这个问题,与单节点不同的是,因为涉及到多个节点,并且每个节点的服务端口数量是 2,我们需要开更多的 spiped 安全通道,接下来本文将为您介绍如何配置一个这样安全的 Redis 集群。

如何用 spiped 建立一个安全的 Redis 集群

在配置一个工作的 Redis 集群的时,要求最少主节点的数量是 3,与 zookeeper 集群的最低节点数量类似,这里就不再多说。而要保证集群的高可用性,我们需要为每个主节点配置至少一个从节点,也就是说一个工作的 Redis 集群,至少需要 6 个节点,3 个主节点,3 个从节点,拓扑结构如下图 1,接下来将为您演示如何结合 spiped 和 Redis 来创建一个这样拓扑结构的安全集群。

图 1.Redis 集群拓扑
  1. 准备三台物理机或虚拟机,在每台物理机上准备两个 Redis 集群节点配置文件(每个配置文件需要在不同的目录),每个节点的配置文件应包含至少以下配置:

    bind 127.0.0.1

    port 7000

    cluster-enabled yes

    cluster-config-file nodes.conf

    这里面的 port 值根图 1 的拓扑结构一致,在 Host1 为 7000 7005, Host2 为 7001 7003,Host3 为 7002 7004。

  2. 分别在三个主机上用步骤 1 创建的配置文件,起两个 Redis 集群节点服务。
  3. 在主机 1 上面我们需要创建 4 个 Redis 服务端安全通道,分别绑定主机 1 上两个 Redis 节点的命定端口和集群总线端口。

    spiped -F -d -s [REDIS_HOST1_IP]:7000 -t [127.0.0.1]:7000 -k /etc/spiped/redis.key &

    spiped -F -d -s [REDIS_HOST1_IP]:17000 -t [127.0.0.1]:17000 -k /etc/spiped/redis.key &

    spiped -F -d -s [REDIS_HOST1_IP]:7005 -t [127.0.0.1]:7005 -k /etc/spiped/redis.key &

    spiped -F -d -s [REDIS_HOST1_IP]:17005 -t [127.0.0.1]:17005 -k /etc/spiped/redis.key &

    同时主机 1 还需要访问主机 2 和主机 3 上面的命令端口和集群总线端口,进行主从节点的数据备份和集群状态的管理,因此我们还需为主机 2 和主机 3 分别配置 4 个 Redis 客户端安全通道。

    用于连接主机 2 的客户端安全通道:

    spiped -F -e -s [127.0.0.1]:7001 -t [REDIS_HOST2_IP]:7001 -k /etc/spiped/redis.key &

    spiped -F -e -s [127.0.0.1]:17001 -t [REDIS_HOST2_IP]:17001 -k /etc/spiped/redis.key &

    spiped -F -e -s [127.0.0.1]:7003 -t [REDIS_HOST2_IP]:7003 -k /etc/spiped/redis.key &

    spiped -F -e -s [127.0.0.1]:17003 -t [REDIS_HOST2_IP]:17003 -k /etc/spiped/redis.key &

    用于连接主机 3 的客户端安全通道:

    spiped -F -e -s [127.0.0.1]:7002 -t [REDIS_HOST3_IP]:7002 -k /etc/spiped/redis.key &

    spiped -F -e -s [127.0.0.1]:17002 -t [REDIS_HOST3_IP]:17002 -k /etc/spiped/redis.key &

    spiped -F -e -s [127.0.0.1]:7004 -t [REDIS_HOST3_IP]:7004 -k /etc/spiped/redis.key &

    spiped -F -e -s [127.0.0.1]:17004 -t [REDIS_HOST3_IP]:17004 -k /etc/spiped/redis.key &

  4. 配置主机 2 上的 spiped 安全通道

    主机 2 上的 Redis 服务端安全通道:

    spiped -F -d -s [REDIS_HOST2_IP]:7001 -t [127.0.0.1]:7001 -k /etc/spiped/redis.key &

    spiped -F -d -s [REDIS_HOST2_IP]:17001 -t [127.0.0.1]:17001 -k /etc/spiped/redis.key &

    spiped -F -d -s [REDIS_HOST2_IP]:17003 -t [127.0.0.1]:17003 -k /etc/spiped/redis.key &

    spiped -F -d -s [REDIS_HOST2_IP]:7003 -t [127.0.0.1]:7003 -k /etc/spiped/redis.key &

    用于连接主机 1 的客户端安全通道:

    spiped -F -e -s [127.0.0.1]:7000 -t [REDIS_HOST1_IP]:7000 -k /etc/spiped/redis.key &

    spiped -F -e -s [127.0.0.1]:17000 -t [REDIS_HOST1_IP]:17000 -k /etc/spiped/redis.key &

    spiped -F -e -s [127.0.0.1]:7005 -t [REDIS_HOST1_IP]:7005 -k /etc/spiped/redis.key &

    spiped -F -e -s [127.0.0.1]:17005 -t [REDIS_HOST1_IP]:17005 -k /etc/spiped/redis.key &

    用于连接主机 3 的客户端安全通道:

    spiped -F -e -s [127.0.0.1]:7002 -t [REDIS_HOST3_IP]:7002 -k /etc/spiped/redis.key &

    spiped -F -e -s [127.0.0.1]:17002 -t [REDIS_HOST3_IP]:17002 -k /etc/spiped/redis.key &

    spiped -F -e -s [127.0.0.1]:7004 -t [REDIS_HOST3_IP]:7004 -k /etc/spiped/redis.key &

    spiped -F -e -s [127.0.0.1]:17004 -t [REDIS_HOST3_IP]:17004 -k /etc/spiped/redis.key &

  5. 配置主机 3 上的 spiped 安全通道。

    主机 3 上的 Redis 服务端安全通道:

    spiped -F -d -s [REDIS_HOST3_IP]:7002 -t [127.0.0.1]:7002 -k /etc/spiped/redis.key &

    spiped -F -d -s [REDIS_HOST3_IP]:17002 -t [127.0.0.1]:17002 -k /etc/spiped/redis.key &

    spiped -F -d -s [REDIS_HOST3_IP]:7004 -t [127.0.0.1]:7004 -k /etc/spiped/redis.key &

    spiped -F -d -s [REDIS_HOST3_IP]:17004 -t [127.0.0.1]:17004 -k /etc/spiped/redis.key &

    用于连接主机 1 的客户端安全通道:

    spiped -F -e -s [127.0.0.1]:7000 -t [REDIS_HOST1_IP]:7000 -k /etc/spiped/redis.key &

    spiped -F -e -s [127.0.0.1]:17000 -t [REDIS_HOST1_IP]:17000 -k /etc/spiped/redis.key &

    spiped -F -e -s [127.0.0.1]:7005 -t [REDIS_HOST1_IP]:7005 -k /etc/spiped/redis.key &

    spiped -F -e -s [127.0.0.1]:17005 -t [REDIS_HOST1_IP]:17005 -k /etc/spiped/redis.key &

    用于连接主机 2 的客户端安全通道:

    spiped -F -e -s [127.0.0.1]:7001 -t [REDIS_HOST2_IP]:7001 -k /etc/spiped/redis.key &

    spiped -F -e -s [127.0.0.1]:17001 -t [REDIS_HOST2_IP]:17001 -k /etc/spiped/redis.key &

    spiped -F -e -s [127.0.0.1]:7003 -t [REDIS_HOST2_IP]:7003 -k /etc/spiped/redis.key &

    spiped -F -e -s [127.0.0.1]:17003 -t [REDIS_HOST2_IP]:17003 -k /etc/spiped/redis.key &

  6. 在全部三台主机上配置好 spiped 安全通道后,我们需要在主机 1(或任意一台主机)上运行 Reids 集群配置脚本:

    <path_to_redis_script_dir>/redis-trib.rb create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005

    Redis 目前只提供 ruby 集群配置脚本,你需要在运行前确保集群配置脚本已经安装,在配置过程中,脚本会自动分配主从节点,我们只需确定分配的默认拓扑是我们在图 1 所指定的并接受默认配置就可以了。

    在集群配置脚本完成后,我们可以通过 redis-cli 检查集群的状态:

    [root@kvm-010651 ~]# redis-cli -p 7000

    127.0.0.1:7000> cluster nodes

    43eda54b2ccfc21e166fbb891c0dc3bd1584d702 127.0.0.1:7001 master - 0 1508990608117 2 connected 5461-10922

    80924aee1c579ace330140d8b8d856e16e91fb60 127.0.0.1:7005 slave 1a4e2aa9bb1916c18bda47d3fb253eb2e7773518 1508921602233 1508921601773 3 connected

    a3c975465ac7d1db35c10652b6f68231fb3035a0 127.0.0.1:7003 slave fa0752ec076871dab5d414158baa63b2dae50f98 1508332039016 1508332036453 4 connected

    1a4e2aa9bb1916c18bda47d3fb253eb2e7773518 127.0.0.1:7002 master - 0 0 3 connected 10923-16383

    284e6389c43306ea1dc99884d5c37a6d69105ae4 127.0.0.1:7004 slave 43eda54b2ccfc21e166fbb891c0dc3bd1584d702 0 1508990608578 5 connected

    fa0752ec076871dab5d414158baa63b2dae50f98 127.0.0.1:7000 myself,master - 1508921602234 1508921600970 1 connected 0-546

  7. 在 Redis 集群配置完成后,我们还需要在允许连接 Redis 集群服务的客户端上创建 6 个 spiped 安全通道,用来连接 Redis 集群 6 个节点的命令端口:

    用于连接主机 1 的客户端安全通道:

    spiped -F -e -s [127.0.0.1]:7000 -t [REDIS_HOST1_IP]:7000 -k /etc/spiped/redis.key &

    spiped -F -e -s [127.0.0.1]:7005 -t [REDIS_HOST1_IP]:7005 -k /etc/spiped/redis.key &

    用于连接主机 2 的客户端安全通道:

    spiped -F -e -s [127.0.0.1]:7001 -t [REDIS_HOST2_IP]:7001 -k /etc/spiped/redis.key &

    spiped -F -e -s [127.0.0.1]:7003 -t [REDIS_HOST2_IP]:7003 -k /etc/spiped/redis.key &

    用于连接主机 3 的客户端安全通道:

    spiped -F -e -s [127.0.0.1]:7002 -t [REDIS_HOST3_IP]:7002 -k /etc/spiped/redis.key &

    spiped -F -e -s [127.0.0.1]:7004 -t [REDIS_HOST3_IP]:7004 -k /etc/spiped/redis.key &

  8. 在配置好客户端安全通道后,我们同样可以在客户端运行 redis-cli 去测试客户端到 Redis 集群的连接,我们将会看到和 Redis 集群节点上运行 redis-cli 一样的结果:

    [root@kvm-010656 ~]# redis-cli -p 7000

    127.0.0.1:7000> cluster nodes

    43eda54b2ccfc21e166fbb891c0dc3bd1584d702 127.0.0.1:7001 master - 0 1508990608117 2 connected 5461-10922

    80924aee1c579ace330140d8b8d856e16e91fb60 127.0.0.1:7005 slave 1a4e2aa9bb1916c18bda47d3fb253eb2e7773518 1508921602233 1508921601773 3 connected

    a3c975465ac7d1db35c10652b6f68231fb3035a0 127.0.0.1:7003 slave fa0752ec076871dab5d414158baa63b2dae50f98 1508332039016 1508332036453 4 connected

    1a4e2aa9bb1916c18bda47d3fb253eb2e7773518 127.0.0.1:7002 master - 0 0 3 connected 10923-16383

    284e6389c43306ea1dc99884d5c37a6d69105ae4 127.0.0.1:7004 slave 43eda54b2ccfc21e166fbb891c0dc3bd1584d702 0 1508990608578 5 connected

    fa0752ec076871dab5d414158baa63b2dae50f98 127.0.0.1:7000 myself,master - 1508921602234 1508921600970 1 connected 0-546

  9. 这样我们就配好了一个安全的 Redis 集群,以及它的客户端。接下来我们可以为每一个 spiped 进程配置一个可自动恢复的 Linux 服务,来确保 spiped 进程被 kill 或退出的时候,可以自动重启。Spiped 进程做成可恢复的 Linux 服务很重要,因为如果服务端 spiped 进程退出,则对应的 Redis 节点将会变的不可用,如果客户端 spiped 进程退出,客户端则无法连接对应的服务端口。每个 Linux 系统的服务配置率有不同,本文将不在举例。

小结

Redis 集群为我们提供了一定的负载均衡与高可用性,在安全性要求比较高的网络环境下,通过合理的创建 spiped 安全通道,我们可以很方便的部署一个安全的 Redis 集群。

参考资源

本文仅代表作者个人观点


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Open source
ArticleID=1052415
ArticleTitle=如何基于 spiped 建立一个安全的 Redis 集群
publish-date=11222017