kube-apiserver 双向证书认证是 mTLS 吗?它和普通公网域名 HTTPS 认证有什么区别?
结论
是。 kube-apiserver 的证书双向认证就是 mTLS(Mutual TLS,双向 TLS):客户端校验 apiserver 服务端证书,apiserver 也校验客户端证书,双方互证身份。
分析版本
- 规范:TLS 1.2 / 1.3 握手过程(RFC 5246 / RFC 8446)
- 软件:Kubernetes apiserver x509 认证模块(
--client-ca-file) - 适用版本:Kubernetes 1.20+
- 关键源码路径:
staging/src/k8s.io/apiserver/pkg/authentication/request/x509/
详细分析
1. 单向与双向的分界点:CertificateRequest
普通 HTTPS 与 mTLS 共用前半段握手,真正的分界线是服务端是否下发 CertificateRequest。下发了,就意味着服务端要求客户端也出示证书;没下发,客户端就无需携带证书。判断一次 TLS 连接是不是 mTLS,抓包看有没有这条消息即可。
2. CertificateVerify 是 mTLS 的核心
证书本身是公开信息(公钥人人可见),光发证书不能证明身份。CertificateVerify 用客户端私钥对整段握手摘要做签名,服务端用证书里的公钥验签——验过才证明「持有对应私钥」。这一步同时防住了证书被复制后盗用的风险。
3. 为什么公网 HTTPS 不默认 mTLS
mTLS 要求服务端的客户端 CA 白名单提前就位,且客户端必须事先持有证书。公网用户是不确定的大众,不可能人手发证书;而 K8s 集群内是机器对机器通信,节点、kubelet、控制器都是可控主体,由集群 CA 统一签发证书,正好匹配 mTLS 的信任模型。
4. apiserver 校验通过后身份怎么用
客户端证书校验通过后,x509 认证模块把证书字段解析成身份(CN 用户名、O 用户组),再交给后续的 RBAC 做授权决策——证书在这里不只是准入凭证,也是授权依据。
5. 易混点:ServiceAccount Token 不是证书认证
Pod 里的 ServiceAccount 用的是 JWT Token,属于另一条并行的认证路径,与客户端证书二选一(一个请求带哪个,就走哪个认证模块)。它不影响传输层性质:只要 apiserver 启用了 --client-ca-file 校验,连接本身就是 mTLS。
6. 客户端证书到底发的是什么
图里是握手线上 Certificate 消息的实际结构,这里只补图里没有的两点:
- 格式转换:kubeconfig 里
client-certificate-data是 PEM(base64 文本),建连时客户端会解码成 DER 二进制再放进握手消息;文件里看到的格式和线上传的格式不是一回事。 - 为什么叶子在前:服务端校验时从叶子证书开始,逐张用下一张证书的公钥验签,直到命中信任库里的根。顺序反了服务端就拼不出信任链。
想抓实际发出的内容验证:
openssl s_client -connect <apiserver地址>:6443 -cert client.crt -key client.key
输出里的 Certificate chain 段就是客户端实际发出去的证书列表,第一张是叶子证书。
7. 服务端会把自己的私钥发给客户端吗
不会。 服务端私钥和客户端私钥地位完全对等:任何一方的私钥都永远不离开本机,网络上只传输证书(证书里装的是公钥)。
服务端发出去的只有证书链(叶子证书 + 中间 CA),私钥只存在服务器本地(apiserver 即 --tls-private-key-file),从不经过网络。
服务端证明持有私钥的方式和客户端 CertificateVerify 同源,只是体现在密钥交换环节:
- RSA 密钥交换:客户端用服务端证书里的公钥加密 pre-master-secret,只有持私钥的服务端能解开;
- ECDHE(前向保密):服务端用私钥对 ServerKeyExchange 参数签名,客户端用证书里的公钥验签。
双方对称关系:
| 发给对方的 | 留在本地的 | 证明方式 | |
|---|---|---|---|
| 服务端 | 证书(公钥) | 私钥 | 解密 pre-master-secret / 签名握手参数 |
| 客户端 | 证书(公钥) | 私钥 | CertificateVerify 签名 |
私钥一旦通过网络发出,TLS 的身份认证与加密体系就形同虚设——这是协议级硬约束,不是配置选择。
浙公网安备 33010602011771号