TiDB 作为一款分布式数据库,天生就具备多组件、多节点协同工作的特性。这种架构在带来弹性扩展能力的同时,也意味着数据在 PD、TiKV、TiDB Server 以及客户端之间流动时,会经过多个网络边界。如果你只是把集群部署在内网,却不对这些链路做任何加密,等于把数据裸奔在交换机上。任何一个被入侵的旁路设备、一次 ARP 欺骗、甚至运维人员误接的抓包工具,都能直接看到你的 SQL 查询结果和敏感字段。所以,TLS 加密不是可有可无的选项,而是生产环境的基本门槛。接下来,我们直接从证书体系、配置步骤、证书轮换和常见故障排查四个维度,把 TiDB 的 TLS 落地细节讲清楚。
TiDB 的 TLS 加密链路全景很多人以为给 TiDB 配 TLS 就是客户端到 TiDB Server 这一条链路,实际上远不止于此。TiDB 集群内部有三类核心通信路径:客户端与 TiDB Server 之间、TiDB Server 与 PD 之间、TiDB Server 与 TiKV 之间,以及 PD、TiKV、TiFlash 等组件彼此间的内部 RPC 调用。官方把这些链路归为两大类:客户端与服务端之间的加密,以及组件之间的内部加密。你可以在集群配置中分别启用它们,也可以只启用其中一部分,但从安全实践角度看,要么全开,要么就别开,半开半闭的状态最容易让人产生“已经安全了”的错觉。启用内部组件间 TLS 后,TiKV 与 PD 之间的心跳信息、Region 调度数据、Raft 日志复制流量全部走 TLS 隧道,即使有人在交换机镜像端口抓包,拿到的也是一堆密文。
证书体系设计:不要用单张证书糊弄所有节点TiDB 的 TLS 依赖标准的 X.509 证书体系,这意味着你需要一套 CA、若干服务端证书和客户端证书。很多人图省事,用同一张证书复制到所有节点上,这种做法在安全审计时会被直接判定为不合规。正确做法是:为每个组件创建独立的证书,并且在证书的 Common Name 或 Subject Alternative Name 字段中明确标识该节点的身份。比如 PD 节点的证书 SAN 里要包含 pd-0、pd-0.tidb-cluster.svc 这类集群内部可解析的主机名,TiKV 节点的证书同理。这样做不仅符合零信任网络下的身份认证原则,还能在启用证书吊销时精确定位到具体节点。证书的密钥类型建议使用 ECDSA P-256,比 RSA 2048 握手更快,对分布式数据库频繁建立短连接和 RPC 调用的场景更友好。
使用 cfssl 构建证书链的完整流程生产环境不建议用 mysql_ssl_rsa_setup 这类工具,它生成的证书没有合理的 SAN 扩展,组件间验证时会直接报错。推荐用 cfssl 工具链,它能精确控制证书的每一个字段。先创建 CA 配置文件 ca-config.json,里面定义签名策略和过期时间:
{
"signing": {
"default": {
"expiry": "87600h"
},
"profiles": {
"server": {
"expiry": "87600h",
"usages": ["signing", "key encipherment", "server auth"]
},
"client": {
"expiry": "87600h",
"usages": ["signing", "key encipherment", "client auth"]
}
}
}
}
然后生成 CA 本身的证书请求 ca-csr.json,指定 CA 的 CN 和密钥算法:
{
"CN": "TiDB Internal CA",
"key": {
"algo": "ecdsa",
"size": 256
},
"names": [
{
"O": "MyOrg"
}
]
}
用 cfssl gencert -initca ca-csr.json | cfssljson -bare ca 生成 ca.pem 和 ca-key.pem。接下来为 PD、TiKV、TiDB Server 分别生成服务端证书。以 PD 为例,pd-csr.json 要明确列出所有可能被访问的主机名和 IP:
{
"CN": "pd",
"hosts": [
"127.0.0.1",
"pd-0",
"pd-0.tidb-cluster.svc",
"*.pd-peer",
"10.0.0.1"
],
"key": {
"algo": "ecdsa",
"size": 256
}
}
用 cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=server pd-csr.json | cfssljson -bare pd 生成 pd.pem 和 pd-key.pem。TiKV 和 TiDB Server 的证书同理生成,只是 hosts 字段要换成各自的主机名和 IP。客户端证书则使用 client profile,CN 可以设为客户端用户名,比如 dba 或 monitoring。最终你会得到一套完整的证书矩阵,每个节点都有自己独立的密钥对,全部由同一个内部 CA 签发。
在 TiDB 集群中启用 TLS 的具体配置如果你用的是 TiUP 部署的集群,编辑 topology.yaml 文件,在 server_configs 区域统一配置 TLS 路径。关键配置段如下:
server_configs:
tidb:
security:
cluster-ssl-ca: /path/to/ca.pem
cluster-ssl-cert: /path/to/tidb-server.pem
cluster-ssl-key: /path/to/tidb-server-key.pem
tikv:
security:
ca-path: /path/to/ca.pem
cert-path: /path/to/tikv-server.pem
key-path: /path/to/tikv-server-key.pem
pd:
security:
cacert-path: /path/to/ca.pem
cert-path: /path/to/pd-server.pem
key-path: /path/to/pd-server-key.pem
注意 TiDB Server 的配置项名称是 cluster-ssl- 前缀,而 TiKV 和 PD 是 ca-path、cert-path 这样的命名,这是历史遗留差异,不要写混。除了组件间加密,你还需要开启客户端到 TiDB Server 的 TLS。在 tidb 段追加:
ssl-ca: /path/to/ca.pem
ssl-cert: /path/to/tidb-server.pem
ssl-key: /path/to/tidb-server-key.pem
执行 tiup cluster deploy 或 tiup cluster reload 后,集群会滚动重启并加载证书。此时用 MySQL 客户端连接,如果不带 --ssl-mode 参数,默认会尝试 TLS,但建议显式指定 mysql -u root -h tidb-server-ip -P 4000 --ssl-ca=/path/to/ca.pem --ssl-cert=/path/to/client.pem --ssl-key=/path/to/client-key.pem。登录后执行 SHOW STATUS LIKE 'Ssl_cipher'; 如果返回非空值,说明当前连接已加密。
强制 TLS 与证书验证的硬核策略仅仅提供 TLS 选项还不够,你需要在 TiDB Server 的配置中强制所有客户端连接必须使用 TLS,并且验证客户端证书。在 tidb 配置段加入:
require-secure-transport: true
ssl-verify-server-cert: true
require-secure-transport 为 true 时,任何不带 TLS 的连接都会被直接拒绝。如果你还想做双向认证,即服务端也验证客户端证书,可以在 MySQL 层面创建要求 X509 的用户:CREATE USER 'app_user'@'%' REQUIRE X509; 或者更精细地 REQUIRE SUBJECT '/CN=app_user'。这样即使有人拿到了数据库密码,没有对应的客户端证书也无法连接。对于监控组件、Dashboard 等 HTTP 服务,TiDB 也支持配置 TLS,在 pd 和 tidb 的配置中分别设置 dashboard 相关的证书路径即可。
证书轮换:不停机更换证书的实操步骤证书总有到期的一天,TiDB 支持在线证书轮换,不需要停机。轮换的核心思路是先让新老证书并存一段时间,等所有组件都加载了新证书后,再移除旧证书。具体操作分四步:第一步,用现有 CA 签发一套新的节点证书,有效期覆盖你的下一个周期。第二步,将新证书文件分发到所有节点的证书目录,注意不要覆盖旧文件,而是放在一个新路径,比如 /path/to/new-certs/。第三步,修改 topology.yaml 或使用 tiup cluster edit-config 将各组件证书路径指向新文件,执行 tiup cluster reload --force。TiDB 会逐个节点滚动重启,此时新证书生效,但旧证书对应的连接如果还存活,会因为长连接已经完成握手而不受影响。第四步,观察监控和日志,确认没有 TLS 握手失败的错误后,再清理旧证书文件。如果你的 CA 本身也要轮换,那就需要同时准备两份 CA 证书,在配置中把 ca.pem 替换为一个包含新老 CA 证书的 bundle 文件,等所有节点都信任新 CA 后,再移除老 CA。
常见故障排查:握手失败、证书过期和性能抖动TLS 配置出错时,TiDB 的日志会给出相对明确的错误信息,但你需要知道去哪里看。PD 和 TiKV 的 TLS 握手失败通常记录在各自的 log 目录下,关键词是 tls handshake failed 或 certificate verify failed。如果看到 x509: certificate signed by unknown authority,说明某个组件不信任签发证书的 CA,检查该组件配置中的 ca-path 是否指向了正确的 CA 文件。如果看到 x509: cannot validate certificate for 10.0.0.5 because it doesn't contain any IP SANs,说明证书的 SAN 字段缺少该节点的 IP 地址,需要重新签发证书并加上对应的 IP SAN。还有一种隐蔽的情况是时间不同步,TLS 握手会验证证书的有效期,如果某个节点的时间偏差超过证书的 Not Before 或 Not After,握手直接失败。所以部署 TiDB 之前,NTP 服务必须先配好。性能方面,启用 TLS 会增加 CPU 开销,主要是握手阶段的非对称加密运算。在连接池配置合理、长连接复用充分的情况下,这个开销通常不超过 5%。如果你发现启用 TLS 后 P99 延迟显著升高,先检查客户端是否每次请求都新建连接,如果是,把连接池的最小空闲连接数调大,让 TLS 会话复用机制生效。
把证书管理纳入 CI/CD 流水线手动管理证书在节点数量超过 20 个时会变成灾难。推荐的做法是把证书生成和分发流程代码化。你可以用 cert-manager 这类 Kubernetes 原生的证书管理工具,在 TiDB Operator 部署的集群中自动申请和轮换证书。如果是物理机或虚拟机环境,写一个简单的脚本,用 cfssl 批量生成证书,再通过 Ansible 分发到各节点,最后触发 tiup cluster reload。证书过期时间监控也要自动化,写一个 cron 任务定期检查各节点证书的到期时间,openssl x509 -in /path/to/cert.pem -noout -enddate 就能拿到,剩余时间小于 30 天时触发告警。这套流水线跑通之后,TLS 证书管理就不再是安全体系里的薄弱环节,而是变成一段可审计、可回滚的代码。
