K8s 集群证书问题记录

最近在环境中部署了一个 Virtual-Kubelet,由于它与 APIServer 的证书交互出了一些问题,导致了一些功能不可用,故去了解了下 K8s 集群的所有证书与关系,做一个梳理。

https 流程

想了解证书的关系,首先要弄清楚 https 的流程,可以先阅读这篇文章

简单来说,完成一次 https 连接,需要有以下证书密钥互相传输:

  • server 端公钥、证书
  • client 端公钥、证书

问题现象

用户使用 ServiceAccoutToken 分配的证书,无法访问 Virtual-Kubelet 上的 mtrics 接口,但是可以直接访问原生 Kubelet 的 metrics 接口。

问题分析

一开始感觉是 Virtual-Kubelet 起的 TLS 服务配置问题,故先进行‘拆盲盒’,参考原生 Kubelet 配置,将 Virtual-Kubelet server 的 TLS 支持版本、支持算法等配置都进行了修改,但是没有解决问题。

后来找了环境部署相关的同事做了了解,由于安全原因,我们 K8s 集群使用两套证书配置,其中一套用于 APIServer 提供 server(称为CA1),一套用于访问 Kubelet 作为 client(称为CA2),这两套使用不同的 CA 证书签发,所以无法直接互相访问。

在两套证书的背景下,会发现理论上使用 ServiceAccoutToken 也应该访问不到原生 Kubelet 的 metrics 接口,因为 ServiceAccoutToken 是由 APIServer 的 server ca 证书(即CA1)签发的,而访问 metrics 接口的网络路由是用户 client 访问 APIServer server,然后 APIServer client 访问 Kubelet metrics 接口,Kubelet server 证书理论上应该是使用 CA2 签发的,应该无法访问。

问题根因

通过走读原生 Kubelet 代码,发现了根因。

1
2
3
4
5
6
7
8
9
10
if len(kc.Authentication.X509.ClientCAFile) > 0 {
clientCAs, err := certutil.NewPool(kc.Authentication.X509.ClientCAFile)
if err != nil {
return nil, fmt.Errorf("unable to load client CA file %s: %w", kc.Authentication.X509.ClientCAFile, err)
}
// Specify allowed CAs for client certificates
tlsOptions.Config.ClientCAs = clientCAs
// Populate PeerCertificates in requests, but don't reject connections without verified certificates
tlsOptions.Config.ClientAuth = tls.RequestClientCert
}

原来 Kubelet Server 原生的配置对于 Client 证书的合法性并不做验证,只要提供了就可以访问。

解决方案

将 Virtual-Kubelet 的 ClientAuth 也 设置成 tls.RequestClientCert

参考文档

一文带你彻底厘清 Kubernetes 中的证书工作机制

https的认证加密过程