一、什么是 TLS Bootstrapping¶
在一个 Kubernetes 集群中,工作节点上的组件(kubelet 和 kube-proxy)需要与 Kubernetes 控制平面组件通信,尤其是 kube-apiserver。 为了确保通信本身是私密的、不被干扰,并且确保集群的每个组件都在与另一个可信的组件通信, 强烈建议使用节点上的客户端 TLS 证书。
启动引导这些组件的正常过程,尤其是需要证书来与 kube-apiserver 安全通信的工作节点, 可能会是一个具有挑战性的过程,因为这一过程通常不受 Kubernetes 控制,需要不少额外工作。 这也使得初始化或者扩缩一个集群的操作变得具有挑战性。为了简化这一过程,从 1.4 版本开始,Kubernetes 引入了一个证书请求和签名 API。
Kubernetes 的 "bootstrapping" 过程通常涉及以下几个关键方面:
- Master 节点初始化: 在 Kubernetes 集群中,Master 节点负责管理整个集群的控制平面。"Bootstrapping" 过程会初始化 Master 节点的各个组件,如 API Server、Controller Manager、Scheduler 等。这些组件的初始化需要确保它们能够相互通信并协同工作。
- Node 节点初始化: Node 节点是集群中的工作节点,负责运行容器和应用程序。"Bootstrapping" 过程会初始化 Node 节点,确保它们能够连接到 Master 节点,注册自己的存在,并准备好运行容器的环境。
- 证书和认证: Kubernetes 使用证书来确保集群中的通信安全性。"Bootstrapping" 过程涉及生成和分发证书,以及配置 Kubernetes 组件和节点来使用这些证书进行身份验证和安全通信。
- 配置初始化: 集群配置文件的初始化是 "bootstrapping" 的一部分,这些配置文件包括 API Server、etcd 数据库、网络插件、Pod 网络范围等的配置。
- 网络设置: 在 Kubernetes 中,Pod 和 Service 之间的网络通信是至关重要的。"Bootstrapping" 过程会确保网络插件的正确安装和配置,以及网络规则的初始化。
- 持久化存储: 一些应用程序可能需要使用持久化存储。"Bootstrapping" 过程会确保持久化存储卷(如 PV 和 PVC)的初始化和配置。
二、为什么会出现 TLS Bootstrapping¶
TLS bootstrapping 的出现原因是为了以下几个目的:
- 安全通信: Kubernetes 集群中的各个组件和节点之间需要进行安全的通信,以防止敏感数据在传输过程中被窃取或篡改。TLS 提供了一种加密通信的方式,确保数据在传输过程中是安全的。
- 身份验证: 为了确保集群中的每个组件和节点都是合法的,TLS 证书用于身份验证。在 TLS bootstrapping 过程中,每个组件和节点都会生成证书和密钥,这些证书用于在集群内部进行身份验证,防止未经授权的访问。
- 集群中的信任关系: 集群中的不同组件和节点需要互相信任,以便建立安全的通信连接。通过 TLS bootstrapping,集群中的证书可以被颁发和管理,建立起相互信任的关系。
- 自动化: TLS bootstrapping 可以自动化证书生成、分发和更新的过程,使得在扩展或更新集群时能够快速地引入新的节点或组件。
- 安全性增强: 通过使用 TLS,可以增强集群的安全性,减少潜在的漏洞和攻击面。
TLS bootstrapping 是 Kubernetes 集群中非常重要的一部分,用于建立安全的通信连接和身份验证,确保集群的安全性和稳定性。它通过自动化证书生成和分发,使得管理集群中的安全性变得更加容易。
三、Kubelet 启动过程¶
当工作节点启动时,kubelet 执行以下操作:
- 寻找自己的
kubeconfig文件,如果是二进制安装的话,一般存放路径为:/etc/kubernetes/kubelet.kubeconfig。其中kubelet.kubeconfig文件是根据bootstrap-kubelet.kubeconfig 文件自动生成的 - 检索 API 服务器的 URL 和凭据,通常是来自
kubeconfig文件中的 TLS 密钥和已签名证书 - 尝试使用这些凭据来与 API 服务器通信
如果想查看kubelet配置文件路径,具体如下
[root@k8s-node01 kubernetes]# cat /etc/systemd/system/kubelet.service.d/10-kubelet.conf
[Service]
Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.kubeconfig --kubeconfig=/etc/kubernetes/kubelet.kubeconfig"
Environment="KUBELET_SYSTEM_ARGS=--network-plugin=cni --cni-conf-dir=/etc/cni/net.d --cni-bin-dir=/opt/cni/bin --container-runtime=remote --runtime-request-timeout=15m --container-runtime-endpoint=unix:///run/containerd/containerd.sock --cgroup-driver=systemd"
Environment="KUBELET_CONFIG_ARGS=--config=/etc/kubernetes/kubelet-conf.yml"
Environment="KUBELET_EXTRA_ARGS=--node-labels=node.kubernetes.io/node='' "
ExecStart=
ExecStart=/usr/local/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELET_SYSTEM_ARGS $KUBELET_EXTRA_ARGS
当然,我们也可以查看集群的证书数据,具体如下
[root@k8s-node01 ~]# cd /etc/kubernetes
[root@k8s-node01 kubernetes]# more kubelet.kubeconfig

将certificate-authority-data后面的数据使用base64进行解密,并保存到/root/kubeconfg-key
[root@k8s-node01 kubernetes]# echo '''
LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUQ1RENDQXN5Z0F3SUJBZ0lVQ3UvbjRHcHltSDNLOURuQnBnNWhRYys2OGNvd0RRWUpLb1pJaHZjTkFRRUwKQlFBd2R6RUxNQWtHQTFVRUJ
oTUNRMDR4RURBT0JnTlZCQWdUQjBKbGFXcHBibWN4RURBT0JnTlZCQWNUQjBKbAphV3BwYm1jeEV6QVJCZ05WQkFvVENrdDFZbVZ5Ym1WMFpYTXhHakFZQmdOVkJBc1RFVXQxWW1WeWJtVjBaWE10CmJXRnVkV0ZzTVJNd0VRWURWUVFERX
dwcmRXSmxjbTVsZEdWek1DQVhEVEl6TURNeE1URXdOVEF3TUZvWUR6SXgKTWpNd01qRTFNVEExTURBd1dqQjNNUXN3Q1FZRFZRUUdFd0pEVGpFUU1BNEdBMVVFQ0JNSFFtVnBhbWx1WnpFUQpNQTRHQTFVRUJ4TUhRbVZwYW1sdVp6RVRNQ
kVHQTFVRUNoTUtTM1ZpWlhKdVpYUmxjekVhTUJnR0ExVUVDeE1SClMzVmlaWEp1WlhSbGN5MXRZVzUxWVd3eEV6QVJCZ05WQkFNVENtdDFZbVZ5Ym1WMFpYTXdnZ0VpTUEwR0NTcUcKU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFR
Q1hiSUNrTDZhMHFzSVlMb1dNN1RadXVsMzRLZUJBdTkvcwpuV0V4Zkxtc0sweGx3L1BYTkM3L1N4MTdTQUFhQnBnc3JGeG5FeFp1MjRRTWw5MU1UQkZuYlB1SjBNdkJ2NFZRCkxwSjJtdWxvd2NYMFdHNmd0cS9mZndmQ0c4M1FlMnNVamV
LYmd5MHAyWGYwY0FpRzRYK0VPT2laangyNUt6bkgKN05CNWR3QXkxUDV1UGxXZ0crUE00cys2MHdXZHZhZmlJbm1ieGFiYVIvaDRUSTN0aWtocVMzYnZFWmZMWkszcgoxM296NTRzaThIUzcyWDRicVRjV2dwZDVYUzNKMkkyWkwrYzUrbG
9Wd3NhbWhkL25QcVNnRDE1L05vSmx6ZFZICk5kL0NWSXkxcWtZMEVWcSt6WlBHWGVGNHNTb2duMEJZa3BDdGRWVE5xTzNDK3luZFpzSDVBZ01CQUFHalpqQmsKTUE0R0ExVWREd0VCL3dRRUF3SUJCakFTQmdOVkhSTUJBZjhFQ0RBR0FRS
C9BZ0VDTUIwR0ExVWREZ1FXQkJSdgpEYllXTzl2bnRrK2pmS3VsbFBkdFIrbkUyVEFmQmdOVkhTTUVHREFXZ0JSdkRiWVdPOXZudGsramZLdWxsUGR0ClIrbkUyVEFOQmdrcWhraUc5dzBCQVFzRkFBT0NBUUVBSnFyekY3T09xQStUS1li
MU5UTmlVM09rMTNHUE5KekEKL2hNdWc4cFNzMEg0UTREWG0yZ045U05nRXI2UERGbk5rN2ZPSHZYbWVxWmNXN1lFUUNjRmFBQnNUcHEwdGp3Mgo3dThVSkRLSzljUExlczBmUkowYjFhYng0YlU5K20wSGlIVDFlei85Q2U4RHZHTDRwYXR
nYkc3L3JibTdpaDF4CmlBRHNmVDlobHNZLzFUUGxiK3lrcy82Q1lKcTVxT1A1QjN2ME9WOERJbXZJKzFZcFgvSmdWTXJLckxPWlFkM1IKNXNxeEN3VEFLTTN4d3ZCNzRSd1d6amlmWmJuV1lkMW91TjkwUEI4UldRbFNGVU5ITDdpRi95Qm
51MVRkQWdqYwpEMk5DaHpGb2oya0hmODkrclF4VEFYOXU4OERFNVlwa2V5UXBCelowWTd0Q1dMMlNzVXhSc3c9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==''' | base64 -d > /root/kubeconfg-key
此时,我们也可以使用OpenSSL即可查看证书过期时间
[root@k8s-node01 kubernetes]# openssl x509 -in /root/kubeconfg-key -noout -dates
notBefore=Mar 11 10:50:00 2023 GMT
notAfter=Feb 15 10:50:00 2123 GMT
四、TLS Bootstrapping 初始化¶
在启动引导初始化过程中,会发生以下事情:
1.kubelet 启动
2.Kubelet查看kubelet.kubeconfig文件,如果是二进制安装的话,一般存放路径为:/etc/kubernetes/kubelet.kubeconfig。
3.假设kubelet 看到自己没有对应的 kubeconfig 文件,会查看本地的bootstrap.kubeconfig。如果是二进制安装的话,一般存放路径为:/etc/kubernetes/bootstrap.kubeconfig。
4.Kubelet读取bootstrap.kubeconfig文件,检索apiserver的url和一个token,观察到本集群中token-id为c8ad9c,token密钥为2e4d610cf3e7426e
[root@k8s-node01 ~]# more /etc/kubernetes/bootstrap-kubelet.kubeconfig

5.Kubelet连接apiserver,使用这个token进行认证
(1)Apiserver会识别token-id,apiserver会查看该token-id对于的bootstrap的一个secret
[root@k8s-master01 ~]# kubectl get secret -n kube-system | grep c8ad9c
bootstrap-token-c8ad9c bootstrap.kubernetes.io/token 6 154d
详细查看这个secret内容
[root@k8s-master01 ~]# kubectl get secret bootstrap-token-c8ad9c -n kube-system -oyaml
apiVersion: v1
data:
auth-extra-groups: c3lzdGVtOmJvb3RzdHJhcHBlcnM6ZGVmYXVsdC1ub2RlLXRva2VuLHN5c3RlbTpib290c3RyYXBwZXJzOndvcmtlcixzeXN0ZW06Ym9vdHN0cmFwcGVyczppbmdyZXNz
description: VGhlIGRlZmF1bHQgYm9vdHN0cmFwIHRva2VuIGdlbmVyYXRlZCBieSAna3ViZWxldCAnLg==
token-id: YzhhZDlj
token-secret: MmU0ZDYxMGNmM2U3NDI2ZQ==
usage-bootstrap-authentication: dHJ1ZQ==
usage-bootstrap-signing: dHJ1ZQ==
kind: Secret
metadata:
creationTimestamp: "2023-03-11T13:19:57Z"
name: bootstrap-token-c8ad9c
namespace: kube-system
resourceVersion: "1921"
uid: d409daf1-33a6-4888-a5c8-cbbeccd513fe
type: bootstrap.kubernetes.io/token
当然我们可以进行验证,观察到token-id为c8ad9c,token密钥为2e4d610cf3e7426e
[root@k8s-master01 ~]# echo -n "YzhhZDlj" | base64 -d
c8ad9c
[root@k8s-master01 ~]# echo -n "MmU0ZDYxMGNmM2U3NDI2ZQ==" | base64 -d
2e4d610cf3e7426e
(2)找到这个secret中的一个auth-extra-groups字段,apiserver把这个token识别成一个username,名称是system:bootstrap:<token-id>,属于system:bootstrappers这个组,这个组具有申请csr的权限,该组的权限绑定在一个叫system:node-bootstrapper的clusterrole

[root@k8s-master01 ~]# echo "c3lzdGVtOmJvb3RzdHJhcHBlcnM6ZGVmYXVsdC1ub2RlLXRva2VuLHN5c3RlbTpib290c3RyYXBwZXJzOndvcmtlcixzeXN0ZW06Ym9vdHN0cmFwcGVyczppbmdyZXNz" | base64 -d
system:bootstrappers:default-node-token,system:bootstrappers:worker,system:bootstrappers:ingress
验证system:bootstrappers这个组具有申请csr的权限,观察到具有申请csr的权限
[root@k8s-master01 ~]# kubectl get clusterrole system:node-bootstrapper -oyaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
annotations:
rbac.authorization.kubernetes.io/autoupdate: "true"
creationTimestamp: "2023-03-11T12:54:21Z"
labels:
kubernetes.io/bootstrapping: rbac-defaults
name: system:node-bootstrapper
resourceVersion: "97"
uid: 208e214d-e69a-4a3c-b339-878d81ebc7f8
rules:
- apiGroups:
- certificates.k8s.io
resources:
- certificatesigningrequests
verbs:
- create
- get
- list
- watch
验证system:bootstrappers这个组的权限是否绑定在一个叫system:node-bootstrapper的clusterrole
[root@k8s-master01 ~]# kubectl get clusterrolebinding kubelet-bootstrap -oyaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
creationTimestamp: "2023-03-11T13:19:57Z"
name: kubelet-bootstrap
resourceVersion: "1922"
uid: 1ce9693b-fc89-4929-a766-19e17cc566ab
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:node-bootstrapper
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: system:bootstrappers:default-node-token
6.经过上面的认证,kubelet就有了一个创建和检索CSR的权限
7.Kubelet为自己创建一个CSR,并将其 signerName 设置为kubernetes.io/kube-apiserver-client-kubelet
8.CSR被允许有两种方式:
(1)K8s管理员使用kubectl手动的颁发证书
(2)如果配置了相关权限,kube-controller-manager会自动同意
-
Controller-manager有一个CSR的ApprovingController。他会校验kubelet发来的csr的username和group是否有创建csr的权限,而且还要验证签发者是否是kubernetes.io/kube-apiserver-client-kubelet
-
Controller-manager同意CSR请求
9.CSR被同意后,controller-manager创建kubelet的证书文件
10.Controller-manager将证书更新至csr的status字段
11.Kubelet从apiserver获取证书
12.Kubelet从获取到的key和证书文件创建kubelet.kubeconfig
13.Kubelet启动完成并正常工作
14.可选地,如果配置了自动续期,kubelet会在证书文件过期的时候利用之前的kubeconfig文件去申请一个新的证书,相当于续约
15.新的证书被同意或签发,自动完成或者手动完成取决于我们的配置
(1)Kubelet创建的CSR是属于一个O(证书中的一个字段,表示证书所属的组织或实体的名称):system:nodes
(2)CN(指的是SSL/TLS数字证书中的一个字段。它通常包含了证书所代表的实体,比如网站、服务器等的名称):system:nodes:主机名