mTLS 是什么
普通 TLS 只验证服务器证书,双向 TLS(mTLS)要求客户端也出示证书并通过验证:服务器用配置的 CA 证书链校验客户端证书,客户端身份就来自证书里的主体信息。它是服务间通信、零信任架构、Kubernetes 网关的常见做法,代价是要有一套签发、分发与轮换体系。
基本信息
| 验证方向 | 双向:客户端验服务器,服务器也验客户端 |
|---|---|
| 服务器侧关键项 | ssl_client_certificate 指定受信 CA,ssl_verify_client on 开启校验 |
| 客户端侧 | curl 用 --cert / --key,openssl s_client 同样支持指定证书 |
| 身份提取 | Nginx 可用 $ssl_client_s_dn 把证书主体传给后端做鉴权 |
| 有效期 | 通常很短(小时级到 90 天),依赖自动化轮换 |
典型使用场景
- 服务间调用互认身份:替代长期共享的静态 Token
- 零信任网关:只有持有效设备证书的终端才能访问内部系统
- 服务网格与网关入口:由控制面自动签发与轮换工作负载证书
- 对外 API 合作方接入:给合作方单独的客户端证书,按主体限流与审计
- 数据库或中间件开启客户端证书校验,阻断未授权客户端
- 替换老旧的 IP 白名单机制,让授权关系随证书而非网络位置变化
最小示例
最小示例
ssl_client_certificate /etc/nginx/ca.pem; # 受信的客户端 CA 链
ssl_verify_client on; # 强制校验,optional 为可选
ssl_verify_depth 2; # 允许的链深度
# 后端读取 $ssl_client_s_dn / $ssl_client_verify 做鉴权与审计客户端验证
客户端验证
curl --cert client.pem --key client.key https://m.example.com/ -v 2>&1 | grep -i 'certificate'
openssl s_client -connect m.example.com:443 -cert client.pem -key client.key </dev/null 2>&1 | grep -i 'verify return'
openssl s_client -connect m.example.com:443 </dev/null 2>&1 | grep -i 'verify return' # 不带证书应当失败常见失败与定位
| 现象 | 原因 | 确认方法 |
|---|---|---|
| 握手直接断开无提示 | 服务器要求客户端证书但客户端未提供 | 不带证书再跑一次对比 |
| certificate verify failed | 客户端证书的签发者不在服务器受信 CA 中 | 核对客户端证书的签发者与 CA 链 |
| 主体取值为空 | 证书与私钥不匹配或未配置 ssl_client_certificate | 比对证书与私钥模数 |
| 业务侧鉴权失败 | DN 格式与后端解析规则不一致 | 打印 $ssl_client_s_dn 看实际格式 |
mTLS 证书的有效期通常很短,靠人工分发不可持续。生产上要用 cert-manager、SPIFFE 之类的体系做自动签发与轮换,否则证书到期就是一次系统性故障。