探秘Kubernetes的TLS证书
文章目录
详细分析Kubernetes管理面服务中用到的所有TLS证书
1. TLS认证
在 Kubernetes 的组件之间进行通信时,数字证书的验证是在协议层面通过 TLS 完成的,Client/Server 建立通信时在应用层面并不需要进行特殊处理。
采用 TLS 进行验证有两种方式:
- 服务器单向认证:只需要服务器端提供证书(公钥),客户端通过服务器端证书验证服务的身份,但服务器并不验证客户端的身份。
- 双向 TLS 认证:除了客户端需要验证服务器的证书,服务器也要通过客户端证书验证客户端的身份。这种情况下服务器只允许特定身份的客户端访问。
- 双向 TLS 认证时有一种特殊场景,即Client跳过对服务器的认证,只Server验证Client的身份
- 一次双向认证中,涉及了以下证书:
- 服务器端证书/私钥:证书中包含了服务器信息和公钥,会在网络中传递
- 客户端证书/私钥:客户端用于证明自身身份的数字证书,里面主要包含了客户端的公钥以及客户端的身份信息。
- 服务器端 CA 根证书:签发服务器端证书的 CA 根证书(客户端要能获取)。
- 客户端端 CA 根证书:签发客户端证书的 CA 根证书(服务端要能获取)。
- 如果使用kubeadm部署,通常服务端客户端是共用自签发CA(/etc/kubernetes/pki/ca.crt,key),只要获取这个文件就可以任意的签发访问k8s集群
1. PKI证书
Kubernetes 中使用PKI证书进行TLS双向认证的场景无处不在,
- apiserver访问etcd
- apiserver / kubelet 双向访问
- controller-manager 、scheduler、proxy 访问apiserver
- 其他服务访问 apiserver
- controller-manager生成各种 service account token
比较重要的包括以下:
-
在**/etc/kubernetes/pki目录下的ROOT CA**,集群中所有的证书文件都是通过以下文件生成的:
- ca.crt,key(CN=kubernetes)
- etcd/ca.crt,key(CN=etcd-ca)
- front-proxy-ca.crt,key(CN=front-proxy-ca)
- sa.key/sa.pub
-
集群中比较重要的证书文件包括以下(基本都是apiserver使用的)
证书文件名称 Parent CA Default CN O (in Subject) 备注 apiserver.crt/key kubernetes kube-apiserver 服务端证书 Rest API apiserver-kubelet-client.crt/key kubernetes kube-apiserver-kubelet-client system:masters 客户端证书 **访问Kubelet ** apiserver-etcd-client.crt/key etcd-ca kube-apiserver-etcd-client system:masters 客户端证书 etcd目录 front-proxy-client.crt/key front-proxy-ca front-proxy-client 客户端证书 ??这个不知道访问啥的 kubelet.crt/key -ca@ @ /var/lib/kubelet/pki**
Kubelet的服务端证书?TLS bootstrapping方式自动生成并滚动**PS:其余ETCD目录还有证书文件
证书文件名称 Parent CA Default CN O (in Subject) healthcheck-client.crt/key etcd-ca kube-etcd-healthcheck-client system:masters peer.crt/key etcd-ca 当前节点ETCD节点名称 server.crt/key etcd-ca 当前节点ETCD节点名称 system:masters
2. Kubeconfig文件
kubeconfig 同样包含了认证信息,这些文件被作为 客户端认证文件(主要作为外部服务访问k8s集群时使用 来使用。
这些信息被Base64编码后保存在以下字段:
- certificate-authority-data:根证书的公钥(ca.crt文件base64编码后的值)
- client-certificate-data:客户端的公钥
- client-key-data:客户端的Key
证书文件名称 | Parent CA | Default CN | O (in Subject) | 备注 |
---|---|---|---|---|
admin.conf | kubernetes | kubernetes-admin | system:masters | kubectl管理员帐号 |
controller-manager.conf | kubernetes | system:kube-controller-manager | controller使用 | |
scheduler.conf | kubernetes | system:kube-scheduler | scheduler使用 | |
kubelet.conf | kubernetes | system:node:节点名称 | system:nodes | kubelet(访问API的客户端证书) |
3. Sercet
Sercet本质上和conf文件是等价的(一些文档中称为Token方式认证),主要用于集群内访问k8s时使用。
2. Kubeadm
1. 证书相关操作
大部分操作位于 kubeadm init phase certs 目录下:
|
|
PS:相关Config配置可以参考源码 cmd/kubeadm/app/apis/kubeadm/types.go 文件(以及 cmd/kubeadm/app/apis/kubeadm/v1beta2/types.go,俩个文件看着似乎差不多)
2. 更新证书
由于默认Kubeadm证书有效期只有1年,需要定期更新。
更新流程如下:
|
|
3. 修改证书超期时间
需要重新编译Kubeadm,通过Docker环境编译Kubernetes非常的便利!!
-
获取基础镜像(build/build-image/Dockerfile),默认为 k8s.gcr.io/build-image/kube-cross:tag (PS:tag 信息保存在 build/build-image/cross/VERSION 文件)
-
编译命令如下:
|
|
构建文档参考:https://github.com/kubernetes/kubernetes/tree/master/build
Kubeadm生成pki文件的Code为:cmd/kubeadm/app/util/pkiutil包中的NewSignedCert方法,其中CertificateValidity变量写死了超期时间
3. Kubelet 证书
1. Kubelet访问APIServer的证书配置
Kubelet 通过配置文件 kubelet.conf 来访问中的信息访问APIServer,新节点加入K8S集群时如何自动获取改文件,在官方文档**Kubelet TLS Bootstrapping**有非常细致的叙述,简单流程如下:
- Kubelet通过Bootstrap tokens或Token authentication file机制作为system:bootstrappers组的成员连接API Server
- 创建CSR为自己申请一个Client证书
- Controller自动批准该证书
- Kubelet取回证书信息,生成kubelet.conf文件
- 使用system:nodes组成员的身份访问API
使用kubeadm安装k8s集群时,会自动创建以下三个ClusterRoleBinding:
ClusterRoleBinding | 绑定的Group | 绑定的ClusterRole |
---|---|---|
kubeadm:kubelet-bootstrap | system:bootstrappers | system:node-bootstrapper(创建CSR) |
kubeadm:node-autoapprove-bootstrap | system:bootstrappers | system:certificates.k8s.io:certificatesigningrequests:nodeclient(签发证书) |
kubeadm:node-autoapprove-certificate-rotation | system:nodes | system:certificates.k8s.io:certificatesigningrequests:selfnodeclient(更新证书) |
2. APIServer访问Kubelet的证书配置
Kubelet 通过10250提供对外HTTPS访问,10255 提供工HTTP访问,默认情况下,Kubelet认证部分的配置文件如下(1.16.x):
|
|
同时开启时,WebHook和x509认证依次进行,有一个通过即可。
- 服务端证书和客户端证书都从集群CA签发:
- 从CA生成服务端证书kubelet-server.pem、kubelet-server-key.pem
- 从CA生产APIServer用的客户端证书kubelet-client.pem、kubelet-client-key.pem(CN为kubelet-client)
- 修改Kubelet和ApiServer的配置,指定证书
- Kubelet:authentication.x509.clientCAFile/tlsCertFile/tlsPrivateKeyFile
- ApiServer:kubelet-certificate-authority/kubelet-client-certificate/kubelet-client-key
- Kubelet的服务端证书使用自签名证书,API Server 从集群CA签发客户端证书:
- Kubelet的服务端证书是Kubelet自己生成的自签名证书,保存在cert-dir 目录中
- 这种情况下ApiServer没法确认Kubelet是否是合法的Server,但是Kubelet却可以认证ApiServer是否是合法的Client!!
- 通过TLS bootstrap机制分配服务端证书,API Server 从集群CA签发客户端证书,这种方式可以自动更新服务端证书
- APIServer Client分发过程类似,但是同时请求服务端和客户端证书,默认情况下这个配置是关闭的(参考kubelet的ServerTLSBootstrap配置)
3. Kubelet证书自动更新
使用kubeadm安装时,Kubelet证书的更新策略为:
-
客户端证书:自动更新
-
服务端证书使用上述第二种方式来生成,因此实际上服务端证书是会过期的!!!用户要手动更新!!!,但是实际生产中发现:即使服务端证书过期APIServer依然可以正常访问Kubelet!!??
- 上述场景执行以下操作,将自签证书替换成通过CSR签发的证书
1 2 3 4 5 6
cd /var/lib/kubelet/pki && tar -cf kubelet_server.tar kubelet.crt kubelet.key rm -rf kubelet.crt kubelet.key cd - echo "serverTLSBootstrap: true" >> /var/lib/kubelet/config.yaml systemctl restart kubelet kubectl certificate approve {csr_name} ## controller 默认不会自动签发服务端证书
- 生成的证书为 /var/lib/kubelet/pki/kubelet-server-current.pem (crt和key都在一个文件中)
4. 监控证书超期时间
- 方式一:
kubeadm alpha certs check-expiration
2. 其他认证方式
1. Bootstrap Tokens
Bootstrap Tokens 是一种比较简易的认证方式,官方文档中建议仅用来初始化Kubelet节点,以及ConfigMap 签名的场景,并且高版本的K8S还对 Bootstrap Tokens 进行了很多限制(参考)。
|
|
2. WebHook
略
附录1 :x509证书结构
- Serial Number :证书序列号
- Issuer:签发证书的CN(颁发者的CN)
- Subject:本证书的CN(使用者的CN)
- Subject Public Key Info (使用者公钥信息)
以下是 openssl x509 -in /etc/kubernetes/pki/apiserver.crt -noout -text 的输出
|
|
附录2 :生成APIServer的客户端证书
以下步骤生成一个只读的客户端证书文件用于访问API Server
- 创建只读ClusterRole并且绑定到User
|
|
- 创建x509证书CSR和Key(可以用openssl也可以用cfssl,甚至可以通过Web工具)
|
|
- 创建CSR(注意:以下CSR配置是1.16版本的,高版本的CSR细节可以参考官方网站)
|
|
- 批准CSR,并且生成conf文件
|
|
参考
文章作者 yoaz
上次更新 2020-11-13
许可协议 MIT