一、背景介绍

Redis 是一个高性能的内存数据库,广泛应用于分布式缓存、会话管理和任务队列等多个场景。然而,在 Redis 5.0 版本中,并未原生支持 TLS 通信,这意味着客户端与服务器之间的通信数据将以明文方式传输,这对数据安全性和隐私保护提出了较大挑战。

针对上述问题,在 Redis 5.0 版本环境下,企业可以采用 Stunnel 工具作为补充方案,借助其构建安全的 TLS 隧道,实现加密传输。

本文结合一个实际案例,说明如何在 Kubernetes 集群中,使用 Stunnel sidecar 模式实现 Redis 5.0 的 TLS 通信。

二、部署场景

在集群架构中,我们使用 Stunnel 的 sidecar 模式,即 Stunnel 与 Redis、业务容器共存于同一个 Pod 中,以实现高效和安全的数据传输。具体方式如下:

  1. Stunnel 服务端容器(stunnel server)和 Redis 5.0 部署在同一个 Pod 中,Stunnel 作为 Redis 的通信入口,负责将外部的 TLS 请求解密后代理给 Redis。

  2. Stunnel 客户端容器(stunnel client)和 业务应用容器部署在另一个 Pod 中,Stunnel 为业务应用提供加密的隧道通信代理。

  3. 业务应用 -> stunnel client -> tls隧道 -> stunnel server -> Redis:业务应用容器通过 localhost 的协议连接到 stunnel client,加密后,将流量转发到 Redis 的 Stunnel server。

  4. 高可用性部署:Redis 以集群模式(Redis Cluster)运行,Stunnel 配合 Redis Pod,所有数据传输层级均通过 Stunnel 加密。

下文将详细介绍相关配置、部署步骤及其工作原理。


三、实践步骤与详细配置

1. 环境准备

a. 基础环境

  • Redis 版本:5.0

  • Stunnel 版本:≥5.0(推荐 5.67 或更高)

  • Kubernetes 环境:1.20+

  • TLS 证书生成工具:OpenSSL

b. TLS 证书的生成

  1. 创建自签名的根 CA 证书

openssl genrsa -out ca.key 2048
openssl req -new -x509 -days 365 -key ca.key -out ca.crt -subj "/CN=Redis-CA"
  1. 为 Stunnel Server 生成证书

openssl genrsa -out server.key 2048
openssl req -new -key server.key -out server.csr -subj "/CN=Stunnel-Server"
openssl x509 -req -in server.csr -days 365 -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt
  1. 为 Stunnel Client 生成证书

openssl genrsa -out client.key 2048
openssl req -new -key client.key -out client.csr -subj "/CN=Stunnel-Client"
openssl x509 -req -in client.csr -days 365 -CA ca.crt -CAkey ca.key -set_serial 02 -out client.crt
  1. 生成的证书文件列表

  • CA 证书:ca.crt

  • Stunnel Server 私钥和证书:server.keyserver.crt

  • Stunnel Client 私钥和证书:client.keyclient.crt

这些证书将在后续的配置中被挂载到 Stunnel 容器中。


2. 配置 Redis 集群的 Deployment (包含 Redis 和 Stunnel Server)

以下是 Redis 和 Stunnel Server 容器在同一 Pod 中的部署 YAML 文件:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: redis-cluster
spec:
  serviceName: redis-cluster
  replicas: 3
  selector:
    matchLabels:
      app: redis-cluster
  template:
    metadata:
      labels:
        app: redis-cluster
    spec:
      containers:
        - name: redis
          image: redis:5.0
          ports:
            - containerPort: 6379
          command: ["redis-server", "--cluster-enabled", "yes", "--cluster-node-timeout", "5000"]
          volumeMounts:
            - name: redis-data
              mountPath: /data
        - name: stunnel-server
          image: stunnel/stunnel:5.67
          ports:
            - containerPort: 6380
          volumeMounts:
            - name: certs
              mountPath: /etc/stunnel/certs
          env:
            - name: STUNNEL_CONFIG
              value: |
                [redis-tls]
                accept = 6380
                connect = 6379
                cert = /etc/stunnel/certs/server.crt
                key = /etc/stunnel/certs/server.key
                CAfile = /etc/stunnel/certs/ca.crt
                verify = 2
      volumes:
        - name: redis-data
          emptyDir: {}
        - name: certs
          secret:
            secretName: redis-tls-certs

关键配置说明:

  • Redis 容器监听在默认端口 6379,用于处理明文通信。

  • Stunnel Server 容器监听在 6380 端口,将外部的 TLS 流量通过证书解密后代理到 Redis。


3. 配置 Stunnel Client 和业务容器的 Deployment

以下是业务服务和 Stunnel Client 容器在同一 Pod 中的配置:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis-client
spec:
  replicas: 1
  selector:
    matchLabels:
      app: redis-client
  template:
    metadata:
      labels:
        app: redis-client
    spec:
      containers:
        - name: application
          image: my-business-app:latest
          env:
            - name: REDIS_HOST
              value: "127.0.0.1"
            - name: REDIS_PORT
              value: "6379"
        - name: stunnel-client
          image: stunnel/stunnel:5.67
          volumeMounts:
            - name: certs
              mountPath: /etc/stunnel/certs
          env:
            - name: STUNNEL_CONFIG
              value: |
                [redis-tls]
                client = yes
                accept = 6379
                connect = redis-cluster:6380
                cert = /etc/stunnel/certs/client.crt
                key = /etc/stunnel/certs/client.key
                CAfile = /etc/stunnel/certs/ca.crt
                verify = 2
      volumes:
        - name: certs
          secret:
            secretName: redis-tls-certs

关键配置说明:

  • 业务容器通过 REDIS_HOST=127.0.0.1REDIS_PORT=6379 连接到位于同一 Pod 的 Stunnel Client 代理。

  • Stunnel Client 容器作为客户端设置,接收明文流量并通过 TLS 隧道加密后将数据发送到 Redis 的 Stunnel Server。


4. 启动测试和验证

验证步骤:

  1. 创建 Redis 集群:

redis-cli --cluster create <IP1>:6380 <IP2>:6380 <IP3>:6380 --tls \
--cert client.crt --key client.key --cacert ca.crt
  1. 使用部署的业务容器访问 Redis:

redis-cli -h 127.0.0.1 -p 6379 SET key value
redis-cli -h 127.0.0.1 -p 6379 GET key
  1. 确认 TLS 加密生效:

  • 捕获网络数据包,确保流量已被加密。


四、总结与实践价值

通过本文的案例分享,我们成功在不支持 TLS 的 Redis 5.0 集群环境中,采用 Stunnel sidecar 模式实现了 TLS 安全通信。具体总结如下:

  1. 安全性提升:通过 Stunnel 隧道加密通信,保护敏感数据在传输中免受窃取或攻击。

  2. 边车模式优势:Stunnel 与目标服务共存的 sidecar 模式,提升了容器化环境的部署灵活性。

  3. 低侵入性方案:无需修改 Redis 源代码或业务代码,仅通过网络配置实现安全加密。

此方案非常适合需要在标准化 Kubernetes 运行环境中提升安全性的场景,尤其针对遗留系统的安全增强需求。