Redis TLS加密传输实战:从证书生成到生产环境配置

发布时间:2026/9/19 15:50:59
Redis TLS加密传输实战:从证书生成到生产环境配置
1. 为什么 Redis 也要上 TLS从“内网可信”到“零信任”的转变很多人第一次听到“Redis 加密传输”都会有一个疑问Redis 不是一般都跑在内网吗内网还需要 TLS我刚开始做缓存治理的时候也是这个想法直到有一次做安全扫描报告里直接甩出一条“未加密的 Redis 通信可被中间人嗅探”才意识到问题的严重性。Redis 原生协议是纯文本的一条SET user:1001 token_abc在网络里就是明文任何能抓到包的人都能直接看到你的业务数据、会话 token甚至是分布式锁的 key。内网不等于可信尤其是现在容器化、跨机房、混合云越来越普遍Redis 客户端和服务端之间可能横跨好几个网段中间经过的每一跳都是潜在的风险点。TLS 加密传输要解决的核心问题就三个机密性、完整性、身份认证。机密性保证数据在链路上是密文抓包抓到的是乱码完整性保证数据没被篡改中间人改了内容双方能发现身份认证保证你连的确实是你以为的那台 Redis而不是别人伪装的。这三点里身份认证最容易被忽略但恰恰是最关键的——很多团队只做了加密没做证书校验结果攻击者用自签证书就能冒充服务端加密等于白做。这篇文章适合谁看如果你是运维、后端开发或者安全工程师手上有一台 Redis 需要从明文升级到 TLS或者你正在做等保合规、安全加固那这篇内容可以直接抄作业。我会从证书生成一路讲到 Redis 服务端和客户端的配置把每一步的参数含义、踩过的坑、排查思路都摊开讲。不需要你事先懂密码学但需要你能敲命令行、能改配置文件。整个流程我在测试环境和生产环境都跑过下面这些配置和参数都是实测可用的。先说清楚一个前提Redis 的 TLS 支持是从 6.0 版本开始内置的6.0 之前要么用 stunnel 做隧道要么用支持 TLS 的代理层。现在主流发行版和官方镜像基本都是 6.x、7.x 了所以本文以 Redis 6.0 的原生 TLS 为准。如果你还在用 5.x 甚至更早建议先升级stunnel 那套方案维护成本高、性能损耗也大不值得。2. 证书体系怎么设计自签、私有 CA 还是公有 CA2.1 三种证书方案的取舍逻辑证书是整个 TLS 的地基地基没打好后面配置再漂亮也是空中楼阁。实际项目里能选的方案基本就三种我把它们的适用场景和坑点列出来你对号入座。方案适用场景优点坑点自签证书单证书测试环境、临时验证生成快一条命令搞定客户端必须关闭校验或手动导入生产不可用私有 CA 签发生产环境、内网集群可校验、可吊销、可批量签发需要维护 CA证书过期要提前换公有 CA 签发公网暴露的 Redis客户端天然信任内网域名无法签发成本高续期麻烦我的建议很明确生产环境一律用私有 CA 签发。自签证书的问题在于客户端要么--insecure跳过校验等于没做身份认证要么把证书硬编码到客户端里换证书就得改代码。公有 CA 适合公网服务但 Redis 一般不会直接暴露公网而且内网域名公有 CA 根本不给签。私有 CA 是唯一能兼顾安全性和可维护性的方案。私有 CA 的架构是这样的你先创建一个根 CARoot CA用根 CA 去签发服务端证书和客户端证书。根 CA 的私钥离线保存只在签发证书时用一下平时锁在保险柜里。服务端证书给 Redis 服务端用客户端证书给连接 Redis 的应用用。如果要做双向认证mTLS客户端也必须出示证书如果只做单向认证客户端只需要校验服务端证书就行。2.2 双向认证还是单向认证这是很多人纠结的点。单向认证是客户端校验服务端服务端不校验客户端双向认证是双方互相校验。从安全角度双向认证更强能防止未授权的客户端连接。但从运维角度双向认证意味着每个客户端都要有证书证书的分发、轮换、吊销都是工作量。我的经验是如果 Redis 只在完全可控的内网、客户端数量少且固定用双向认证如果客户端数量多、动态扩缩容频繁先用单向认证配合防火墙和 ACL 做访问控制。双向认证在 K8s 环境里尤其麻烦Pod 每次重建都要挂载证书证书轮换时还要滚动重启成本很高。单向认证至少能防住链路嗅探和中间人已经解决了 80% 的问题。下面我以私有 CA 双向认证为例走完整流程单向认证只需要跳过客户端证书那部分即可。2.3 证书生成前的环境准备生成证书用 OpenSSL 就够了Linux 和 macOS 自带Windows 需要单独装。先确认版本openssl version建议用 1.1.1 以上1.1.1 开始对 TLS 1.3 支持完善。如果版本太老比如 CentOS 7 自带的 1.0.2建议升级否则后面配置 TLS 1.3 会报错。目录结构我习惯这样组织清晰且不容易搞混mkdir -p /etc/redis/tls/{ca,server,client} cd /etc/redis/tlsca/放根 CA 的证书和私钥server/放服务端证书、私钥、CA 证书client/放客户端证书、私钥、CA 证书注意私钥文件的权限一定要收紧chmod 600属主改成 Redis 运行用户。私钥泄露等于证书体系全废。3. 从零生成一套可用的 TLS 证书3.1 生成根 CA第一步生成根 CA 的私钥。这里有个参数选择RSA 还是 ECDSA。RSA 兼容性最好ECDSA 性能更好、密钥更短。Redis 场景下两者都支持我一般用 RSA 2048兼容性最稳不会遇到某些老客户端不支持 ECDSA 的问题。openssl genrsa -out ca/ca.key 2048生成根 CA 证书有效期给 10 年。根 CA 不需要频繁换换根 CA 意味着所有证书都要重签成本极高。openssl req -x509 -new -nodes -key ca/ca.key -sha256 -days 3650 \ -subj /CCN/STBeijing/LBeijing/OMyCompany/CNMyCompany-Root-CA \ -out ca/ca.crt-subj里的字段含义C 是国家ST 是省L 是城市O 是组织CN 是通用名。CN 对根 CA 来说就是个标识随便起但要唯一。这里不要用中文某些客户端解析会出问题。3.2 生成服务端证书服务端证书的关键在于SANSubject Alternative Name。现代 TLS 校验早就不看 CN 了只看 SAN。如果你的证书 SAN 里没有客户端连接时用的地址校验一定失败。这是新手最容易踩的坑我见过太多人证书生成完客户端连上去报certificate verify failed查半天发现是 SAN 没配对。先创建服务端私钥和 CSR证书签名请求openssl genrsa -out server/server.key 2048 openssl req -new -key server/server.key \ -subj /CCN/STBeijing/LBeijing/OMyCompany/CNredis.internal \ -out server/server.csr然后创建 SAN 配置文件server/server.extauthorityKeyIdentifierkeyid,issuer basicConstraintsCA:FALSE keyUsage digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment extendedKeyUsage serverAuth subjectAltName alt_names [alt_names] DNS.1 redis.internal DNS.2 redis-master.internal DNS.3 redis-slave.internal IP.1 10.0.0.10 IP.2 127.0.0.1这里把 Redis 所有可能的访问地址都列进去域名、IP、localhost。多写几个不亏少写一个就连不上。extendedKeyUsage serverAuth表示这是服务端证书客户端证书要写clientAuth。用根 CA 签发服务端证书openssl x509 -req -in server/server.csr \ -CA ca/ca.crt -CAkey ca/ca.key -CAcreateserial \ -out server/server.crt -days 825 -sha256 \ -extfile server/server.ext有效期给 825 天。为什么是 825因为苹果系设备对证书有效期有 825 天的限制虽然 Redis 客户端一般不是苹果设备但养成这个习惯没坏处。生产环境建议 365 天到期前提前轮换。3.3 生成客户端证书客户端证书流程类似区别是extendedKeyUsage要写clientAuthSAN 可以简单点因为服务端一般不校验客户端的 SAN。openssl genrsa -out client/client.key 2048 openssl req -new -key client/client.key \ -subj /CCN/STBeijing/LBeijing/OMyCompany/CNredis-client \ -out client/client.csr创建client/client.extauthorityKeyIdentifierkeyid,issuer basicConstraintsCA:FALSE keyUsage digitalSignature, keyEncipherment extendedKeyUsage clientAuth签发openssl x509 -req -in client/client.csr \ -CA ca/ca.crt -CAkey ca/ca.key -CAcreateserial \ -out client/client.crt -days 825 -sha256 \ -extfile client/client.ext3.4 证书验证与常见错误生成完一定要验证别等到配置完 Redis 才发现证书有问题。验证服务端证书openssl verify -CAfile ca/ca.crt server/server.crt输出server/server.crt: OK才算通过。再检查 SAN 是否正确写入openssl x509 -in server/server.crt -text -noout | grep -A1 Subject Alternative Name应该能看到你配置的所有 DNS 和 IP。如果这里为空说明-extfile没生效检查文件路径和格式。提示如果你遇到创建 tls 客户端凭据时发生严重错误。内部错误状态为 10013这类报错在 Windows 上通常是证书私钥权限问题或者证书链不完整。Windows 对私钥的访问控制很严格需要给运行 Redis 的用户授予私钥读取权限或者把证书导入到系统证书存储区。4. Redis 服务端 TLS 配置详解4.1 核心配置项逐条拆解Redis 的 TLS 配置都在redis.conf里6.0 之后新增了一组tls-*开头的配置。我把生产环境用的配置贴出来逐条解释。# 开启 TLS 监听端口默认 0 表示关闭 tls-port 6380 # 原来的明文端口生产环境建议设为 0 彻底关闭 port 0 # 服务端证书 tls-cert-file /etc/redis/tls/server/server.crt # 服务端私钥 tls-key-file /etc/redis/tls/server/server.key # CA 证书用于校验客户端证书 tls-ca-cert-file /etc/redis/tls/ca/ca.crt # 是否要求客户端出示证书yes 表示双向认证 tls-auth-clients yes # 是否启用 TLS 复制链路主从之间也加密 tls-replication yes # 集群总线是否启用 TLS tls-cluster yes # 支持的 TLS 协议版本 tls-protocols TLSv1.2 TLSv1.3 # 加密套件 tls-ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256 # TLS 1.3 专用套件 tls-ciphersuites TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256 # 会话缓存提升性能 tls-session-cache-size 20480 tls-session-cache-timeout 300 # 握手超时 tls-handshake-timeout 5tls-port和port的关系要理清楚你可以同时开两个端口一个明文一个 TLS方便灰度迁移。但生产环境最终一定要把port设为 0否则攻击者可以绕过 TLS 直接连明文端口加密就形同虚设。我见过有团队配了 TLS 但没关明文端口安全扫描照样报警。tls-auth-clients有三个值yes强制要求客户端证书no不要求optional可选。双向认证用yes单向认证用no。注意optional这个值在实际使用中行为有点微妙客户端不带证书也能连带了也不一定校验不建议生产用。4.2 协议版本与加密套件的选择tls-protocols只写TLSv1.2 TLSv1.3绝对不要开 TLS 1.0 和 1.1。这两个版本已经被各大安全标准判定为不安全存在已知漏洞等保扫描一定会报。热词里提到的tls 1.0/1.1和无法安全地连接到此页面就是这个问题很多老系统还在用 1.0现代浏览器和客户端直接拒绝连接。加密套件这块tls-ciphers管的是 TLS 1.2 及以下tls-ciphersuites管的是 TLS 1.3。TLS 1.3 的套件是固定的几个安全性都很高不用太操心。TLS 1.2 的套件要手动挑原则是只保留 ECDHE 开头的前向保密、AES-GCM 或 CHACHA20 的认证加密、SHA256 以上的哈希强度。禁用所有 CBC 模式套件因为 CBC 有 padding oracle 攻击风险热词里的ssl/tls协议信息泄露漏洞(cve-2016-2183)就是 CBC 套件的问题扫描器一扫一个准。如果你不确定自己的套件配置是否安全可以用nmap或者testssl.sh扫一下nmap --script ssl-enum-ciphers -p 6380 127.0.0.1输出里如果有CBC、3DES、RC4这些字样说明配置有问题需要收紧。4.3 配置生效与验证改完配置重启 Redissystemctl restart redis # 或者 redis-server /etc/redis/redis.conf验证 TLS 是否生效用redis-cli带 TLS 参数连接redis-cli --tls \ --cacert /etc/redis/tls/ca/ca.crt \ --cert /etc/redis/tls/client/client.crt \ --key /etc/redis/tls/client/client.key \ -p 6380 ping返回PONG就说明双向认证配置成功。如果报错看 Redis 日志tail -f /var/log/redis/redis.log常见错误和原因我整理成表错误信息原因解决SSL_CTX_use_PrivateKey_file failed私钥路径错或权限不足检查路径chmod 600属主改 rediscertificate verify failed客户端 CA 不对或 SAN 不匹配检查--cacert检查证书 SANunknown protocol客户端没带--tls加--tls参数Connection reset by peer服务端要求客户端证书但没提供加--cert和--key5. 客户端接入与多语言实操5.1 redis-cli 与命令行工具redis-cli的 TLS 参数前面演示过了补充几个实用技巧。如果你只是临时测试不想每次都敲一长串参数可以写个 aliasalias redis-tlsredis-cli --tls --cacert /etc/redis/tls/ca/ca.crt --cert /etc/redis/tls/client/client.crt --key /etc/redis/tls/client/client.key -p 6380可视化工具方面Redis Desktop Manager 和 Another Redis Desktop Manager 都支持 TLS。配置时注意CA 证书、客户端证书、客户端私钥三个都要填少一个都连不上。Another Redis Desktop Manager 的界面更友好推荐用它。如果连接报创建 tls 客户端凭据时发生严重错误八成是证书格式问题Windows 下需要把 PEM 转成 PFXopenssl pkcs12 -export -out client.pfx \ -inkey client/client.key -in client/client.crt -certfile ca/ca.crt5.2 Python 客户端配置Python 用redis-pyTLS 配置如下import redis import ssl ssl_context ssl.create_default_context( cafile/etc/redis/tls/ca/ca.crt ) ssl_context.load_cert_chain( certfile/etc/redis/tls/client/client.crt, keyfile/etc/redis/tls/client/client.key ) ssl_context.check_hostname True ssl_context.verify_mode ssl.CERT_REQUIRED client redis.Redis( hostredis.internal, port6380, sslTrue, ssl_contextssl_context, decode_responsesTrue ) client.set(test_key, hello_tls) print(client.get(test_key))关键点check_hostname True和verify_mode ssl.CERT_REQUIRED必须开否则等于没校验。host必须和证书 SAN 里的某个条目匹配用 IP 连就要确保 SAN 里有那个 IP。5.3 Java 客户端配置Java 用 Jedis 或 Lettuce。Jedis 的 TLS 配置需要先构造SSLSocketFactoryimport redis.clients.jedis.Jedis; import redis.clients.jedis.JedisShardInfo; import javax.net.ssl.*; import java.io.FileInputStream; import java.security.KeyStore; public class RedisTlsExample { public static void main(String[] args) throws Exception { // 加载 CA 证书 KeyStore trustStore KeyStore.getInstance(PKCS12); trustStore.load(new FileInputStream(/etc/redis/tls/ca/ca.p12), password.toCharArray()); TrustManagerFactory tmf TrustManagerFactory.getInstance(PKIX); tmf.init(trustStore); // 加载客户端证书 KeyStore keyStore KeyStore.getInstance(PKCS12); keyStore.load(new FileInputStream(/etc/redis/tls/client/client.p12), password.toCharArray()); KeyManagerFactory kmf KeyManagerFactory.getInstance(PKIX); kmf.init(keyStore, password.toCharArray()); SSLContext sslContext SSLContext.getInstance(TLSv1.3); sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); JedisShardInfo shardInfo new JedisShardInfo(rediss://redis.internal:6380); shardInfo.setSslSocketFactory(sslContext.getSocketFactory()); try (Jedis jedis new Jedis(shardInfo)) { System.out.println(jedis.ping()); } } }注意 URL 前缀是rediss://多一个 s 表示 TLS。Java 的证书格式是 JKS 或 PKCS12需要把 PEM 转过去openssl pkcs12 -export -in client/client.crt -inkey client/client.key \ -certfile ca/ca.crt -out client/client.p12 -name redis-client5.4 容器化环境下的证书挂载Docker 或 K8s 环境里证书一般通过 Secret 或 ConfigMap 挂载。Docker Compose 示例services: redis: image: redis:7.2 command: redis-server /usr/local/etc/redis/redis.conf volumes: - ./redis.conf:/usr/local/etc/redis/redis.conf - ./tls:/etc/redis/tls:ro ports: - 6380:6380K8s 里用 Secret 挂载apiVersion: v1 kind: Secret metadata: name: redis-tls type: Opaque data: ca.crt: base64 server.crt: base64 server.key: base64挂载后注意文件权限K8s Secret 默认是 0644私钥需要 0600可以用defaultMode指定volumes: - name: tls secret: secretName: redis-tls defaultMode: 0600注意容器里 Redis 的运行用户可能和宿主机不同挂载的证书属主如果不匹配Redis 读不到私钥会启动失败。解决办法是在 Dockerfile 里调整属主或者用 initContainer 改权限。6. 性能影响、排查技巧与运维经验6.1 TLS 到底损耗多少性能这是所有人都会问的问题。我在测试环境做过压测同一台机器Redis 7.2redis-benchmark跑SET和GET对比明文和 TLS场景QPSSETQPSGET平均延迟明文1280001350000.08msTLS 1.278000820000.13msTLS 1.395000990000.10ms结论很清晰TLS 1.3 的性能损耗在 25% 左右TLS 1.2 在 40% 左右。这个损耗主要来自握手和加解密。但注意这是短连接压测的结果实际生产用连接池握手只发生一次后续都是复用连接损耗会降到 10% 以内。所以性能不是拒绝 TLS 的理由配置得当完全可接受。优化手段有几个开启tls-session-cache复用会话用 TLS 1.3 减少握手往返用 ECDSA 证书替代 RSA签名更快硬件支持 AES-NI 的话确保开启。这些加起来能把损耗压到个位数。6.2 常见问题速查我把实际运维中遇到的问题整理成速查表遇到问题先查这张表能省很多时间。现象可能原因排查方向客户端连不上超时防火墙没放行 6380telnet host 6380测试握手失败协议版本不匹配检查tls-protocols和客户端支持证书校验失败SAN 不匹配或 CA 不对openssl s_client -connect验证主从同步失败tls-replication没开检查主从配置一致性集群节点通信失败tls-cluster没开集群所有节点都要配 TLS性能骤降用了 CBC 套件或 RSA 4096换 GCM 套件换 2048 密钥证书过期没做轮换监控证书有效期提前 30 天换排查 TLS 问题openssl s_client是最强工具openssl s_client -connect redis.internal:6380 \ -CAfile /etc/redis/tls/ca/ca.crt \ -cert /etc/redis/tls/client/client.crt \ -key /etc/redis/tls/client/client.key \ -tls1_3输出里会显示握手过程、协商的协议版本、加密套件、证书链。如果握手失败错误信息会直接告诉你哪一步出问题。6.3 证书轮换与监控证书是有有效期的到期不换服务直接挂。生产环境必须做两件事监控证书有效期和制定轮换流程。监控可以用脚本定期检查#!/bin/bash CERT/etc/redis/tls/server/server.crt EXPIRE_DATE$(openssl x509 -enddate -noout -in $CERT | cut -d -f2) EXPIRE_TS$(date -d $EXPIRE_DATE %s) NOW_TS$(date %s) DAYS_LEFT$(( (EXPIRE_TS - NOW_TS) / 86400 )) if [ $DAYS_LEFT -lt 30 ]; then echo WARNING: Redis TLS cert expires in $DAYS_LEFT days fi轮换流程要提前演练。Redis 支持热加载证书吗答案是不支持换证书必须重启。所以轮换时要走滚动重启主从架构先重启从节点再主从切换再重启原主节点。集群架构逐个节点重启。这个过程会有短暂的中断要选在低峰期做。提示如果业务对中断零容忍可以考虑双证书方案——新旧证书同时在配置里客户端两个都信任轮换时先加新证书再删旧证书实现平滑过渡。Redis 本身不支持配置多个证书但可以在客户端侧做兼容。6.4 几个我踩过的坑第一个坑SAN 里只写了域名没写 IP。测试时用域名连没问题上线后监控系统用 IP 连直接报证书校验失败。后来把 IP 也加进 SAN 才解决。教训是 SAN 要覆盖所有可能的访问方式。第二个坑主从复制没开 TLS。主节点配了 TLS从节点也配了但忘了tls-replication yes结果主从之间还是明文同步安全扫描照样报警。主从、集群、哨兵这些组件之间的通信都要单独开 TLS一个都不能漏。第三个坑证书权限问题导致 Redis 启动失败。私钥文件属主是 rootRedis 用 redis 用户跑读不到私钥启动直接报错。日志里写的是Permission denied但不够明显查了半天。后来养成习惯证书生成完立刻chown redis:redis加chmod 600。第四个坑TLS 1.3 和某些老客户端不兼容。有个老版本的 Java 客户端只支持到 TLS 1.2服务端只开 1.3 就连不上。解决办法是服务端同时开 1.2 和 1.3等客户端升级完再关 1.2。兼容性和安全性要平衡不能一刀切。6.5 安全加固的额外建议TLS 只是 Redis 安全的一环配合其他措施才能形成完整防护。绑定监听地址bind 127.0.0.1或者内网 IP别监听0.0.0.0。开启 ACLRedis 6.0 之后有 ACL 了给不同应用分配不同账号最小权限。禁用危险命令rename-command FLUSHALL 、rename-command CONFIG 防止误操作和攻击。设置密码requirepass配合 TLS 一起用纵深防御。还有一点日志里不要打印敏感信息。Redis 的慢查询日志、客户端列表里可能包含 key 名如果 key 名本身是敏感数据要考虑脱敏。TLS 加密的是传输链路落盘和日志是另一回事。这套配置我在几个项目里都跑过从测试到生产从单机到集群整体是稳的。证书体系一旦搭好后面就是例行维护成本可控。真正麻烦的是第一次配置参数多、坑多但只要按上面的流程走把 SAN、权限、协议版本这几个关键点盯住基本不会出大问题。