mTLS 是什么
mTLS(双向 TLS)在常规「服务端出示证书」的基础上,进一步要求客户端也提供证书并由服务端校验其链、有效期与用途。它把身份认证从「密码或令牌」换成「持有私钥」,适合服务间调用、设备接入与零信任架构。部署关键在客户端 CA 信任链、校验模式选择与身份信息向业务层传递。
基本信息
| 关键指令 | ssl_client_certificate(客户端 CA 链)、ssl_verify_client on 或 optional |
|---|---|
| 校验内容 | 证书链、有效期、扩展用途(clientAuth)、吊销状态(CRL/OCSP 可选) |
| 身份传递 | 校验通过后把主体信息传给后端,如 $ssl_client_s_dn 与 $ssl_client_verify |
| 常见用途 | 服务间认证、设备接入、API 网关与零信任 |
| 运维重点 | 客户端证书的签发、轮换与吊销 |
| 风险点 | optional 模式下后端未行使校验判断 |
典型使用场景
- 服务间调用:Kubernetes 内部或微服务之间用证书互相认证
- 设备接入:IoT 与专网终端用预置证书入网
- API 网关:对合作方发放客户端证书,替代静态密钥
- 零信任架构:以证书身份作为访问控制的基础
- 管理后台加固:把运维入口限制为持有证书的设备
nginx mTLS 配置片段
nginx mTLS 配置片段
server {
listen 443 ssl;
server_name api.example.com;
ssl_certificate /etc/nginx/ssl/server.fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/server.key;
# 客户端证书的 CA 链(可以是企业自建 CA)
ssl_client_certificate /etc/nginx/ca/client-ca.crt;
ssl_verify_client on; # on 强制校验;optional 允许无证书但需后端判断
ssl_verify_depth 2; # 允许的链深度,按实际层级调整
# 把校验结果与主体信息传给后端用于授权
proxy_set_header X-Client-DN $ssl_client_s_dn;
proxy_set_header X-Client-Verify $ssl_client_verify;
}用 curl 测试 mTLS 通道
用 curl 测试 mTLS 通道
# 带上客户端证书与私钥访问,验证握手与授权
curl -sS --cert client.crt --key client.key https://api.example.com/health -o /dev/null -w '%{http_code}\n'
# 不带证书访问,预期被拒绝(400 或 403)
curl -sS https://api.example.com/health -o /dev/null -w '%{http_code}\n'
# 检查客户端证书用途是否包含 clientAuth
openssl x509 -in client.crt -noout -text | grep -A1 'Extended Key Usage'校验模式对比
| 模式 | 行为 | 风险与适用 |
|---|---|---|
| ssl_verify_client on | 无证书或校验失败直接拒绝 | 安全默认,适合强制认证场景 |
| ssl_verify_client optional | 允许无证书连接,需后端判断 | 漏判会把未认证请求放行 |
| ssl_verify_client optional_no_ca | 不校验证书链,仅取证书信息 | 仅用于特殊调试,生产禁用 |
| 吊销校验 | 结合 CRL 或 OCSP | 依赖外部可用性,建议配合短有效期 |
使用 ssl_verify_client optional 时后端必须自行判断 $ssl_client_verify 的值:该模式会对无证书的连接放行,如果业务代码默认信任请求,未认证流量就会直达内部接口,这在实际事故中出现过多次。
客户端证书的轮换与吊销是长期运维负担:证书有效期越长风险越大,建议使用较短有效期配合自动化签发;吊销机制依赖 CRL 或 OCSP 的可用性,条件允许时可用短有效期加白名单替代。