k8s TLS bootstrap解析-k8s TLS bootstrap流程分析
概述
當k8s集群開啟了TLS認證后,每個節點的kubelet組件都要使用由kube-apiserver的CA簽發的有效證書才能與kube-apiserver通信;當節點非常多的時候,為每個節點都單獨簽署證書是一件非常繁瑣而又耗時的事情。
此時k8s TLS bootstrap功能應運而生。
k8s TLS bootstrap功能就是讓kubelet先使用一個預先商定好的低權限的bootstrap token連接到kube-apiserver,向kube-apiserver申請證書,然后kube-controller-manager給kubelet動態簽署證書,后續kubelet都將通過動態簽署的證書與kube-apiserver通信。
TLS bootstrap涉及組件相關參數
1.kube-apiserver
(1)--client-ca-file:認證客戶端證書的CA證書;
(2)--enable-bootstrap-token-auth:設置為true則代表開啟TLS bootstrap特性;
2.kube-controller-manager
(1)--cluster-signing-cert-file、--cluster-signing-key-file:用來簽發kubelet證書的CA證書和私鑰,這里的kubelet證書指的是用來跟kube-apiserver通信,kube-apiserver認證kubelet身份的證書,所以--cluster-signing-cert-file指定的值與kube-apiserver的--client-ca-file指定值一致,而私鑰則也是對應的私鑰;
(2)--cluster-signing-duration:簽發給kubelet的證書有效期;
3.kubelet
(1)--bootstrap-kubeconfig:TLS bootstrap的配置文件,文件中一般包含bootstrap token和master url等信息;
(2)--kubeconfig:在kubelet的CSR被批復並被kubelet取回時,一個引用所生成的密鑰和所獲得證書的kubeconfig文件會被寫入到通過 --kubeconfig所指定的文件路徑下,而證書和密鑰文件會被放到--cert-dir所指定的目錄中;
(3)--rotate-certificates:開啟證書輪換,kubelet在其現有證書即將過期時通過創建新的CSR來輪換其客戶端證書。
詳細流程解析
下面以kubeadm使用k8s TLS bootstrap將一個node節點加入已有的master為例,對TLS bootstrap部分進行詳細流程解析。
1.RBAC相關操作
(1)生成bootstrap token,創建bootstrap token secret;
bootstrap token secret模板:
apiVersion: v1
data:
auth-extra-groups: system:bootstrappers:kubeadm:default-node-token
expiration: 2022-04-03T11:13:09+08:00
token-id: {token-id}
token-secret: {token-secret}
usage-bootstrap-authentication: "true"
usage-bootstrap-signing: "true"
kind: Secret
metadata:
name: bootstrap-token-{token-id}
namespace: kube-system
type: bootstrap.kubernetes.io/token
關於bootstrap token secret相關的格式說明:
secret的name格式為bootstrap-token-{token-id}的格式;
secret的type固定為bootstrap.kubernetes.io/token;
secret data中的token-id為6位數字字母組合字符串,token-secret為16位數字字母組合字符串;
secret data中的auth-extra-groups定義了bootstrap token所代表用戶所屬的的group,kubeadm使用了system:bootstrappers:kubeadm:default-node-token;
secret所對應的bootstrap token為{token-id}.{token-secret};
bootstrap token secret示例:
apiVersion: v1
data:
auth-extra-groups: system:bootstrappers:kubeadm:default-node-token
expiration: 2022-04-03T11:13:09+08:00
token-id: abcdef
token-secret: 0123456789abcdef
usage-bootstrap-authentication: "true"
usage-bootstrap-signing: "true"
kind: Secret
metadata:
name: bootstrap-token-abcdef
namespace: kube-system
type: bootstrap.kubernetes.io/token
上述secret示例中,kubeadm生成的bootstrap token為abcdef.0123456789abcdef,其代表的用戶所在用戶組為system:bootstrappers:kubeadm:default-node-token;
(2)授予bootstrap token創建CSR證書簽名請求的權限,即授予kubelet創建CSR證書簽名請求的權限;
即創建ClusterRoleBinding -- kubeadm:kubelet-bootstrap
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: kubeadm:kubelet-bootstrap
...
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:node-bootstrapper
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: system:bootstrappers:kubeadm:default-node-token
kubeadm生成的bootstrap token所代表的用戶所在用戶組為system:bootstrappers:kubeadm:default-node-token,所以這里綁定權限的時候將權限綁定給了用戶組system:bootstrappers:kubeadm:default-node-token;
接下來看下被授予的權限ClusterRole -- system:node-bootstrapper
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: system:node-bootstrapper
...
rules:
- apiGroups:
- certificates.k8s.io
resources:
- certificatesigningrequests
verbs:
- create
- get
- list
- watch
(3)授予bootstrap token權限,讓kube-controller-manager可以自動審批其發起的CSR;
即創建ClusterRoleBinding -- kubeadm:node-autoapprove-bootstrap
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: kubeadm:node-autoapprove-bootstrap
...
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:certificates.k8s.io:certificatesigningrequests:nodeclient
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: system:bootstrappers:kubeadm:default-node-token
kubeadm生成的bootstrap token所代表的用戶所在用戶組為system:bootstrappers:kubeadm:default-node-token,所以這里綁定權限的時候將權限綁定給了用戶組system:bootstrappers:kubeadm:default-node-token;
接下來看下被授予的權限ClusterRole -- system:certificates.k8s.io:certificatesigningrequests:nodeclient
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: system:certificates.k8s.io:certificatesigningrequests:nodeclient
...
rules:
- apiGroups:
- certificates.k8s.io
resources:
- certificatesigningrequests/nodeclient
verbs:
- create
(4)授予kubelet權限,讓kube-controller-manager自動批復kubelet的證書輪換請求;
即創建ClusterRoleBinding -- kubeadm:node-autoapprove-certificate-rotation
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: kubeadm:node-autoapprove-certificate-rotation
...
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:certificates.k8s.io:certificatesigningrequests:selfnodeclient
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: system:nodes
kubelet創建的CSR用戶名格式為system:node:<name>,用戶組為system:nodes,所以kube-controller-manager為kubelet生成的證書所代表的用戶所在用戶組為system:nodes,所以這里綁定權限的時候將權限綁定給了用戶組system:nodes;
接下來看下被授予的權限ClusterRole -- system:certificates.k8s.io:certificatesigningrequests:selfnodeclient
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: system:certificates.k8s.io:certificatesigningrequests:selfnodeclient
...
rules:
- apiGroups:
- certificates.k8s.io
resources:
- certificatesigningrequests/selfnodeclient
verbs:
- create
2.啟動kubelet,開始TLS bootstrap
(0)根據bootstrap token以及master url等信息生成bootstrap-kubeconfig文件;
(1)啟動kubelet,配置了kubeconfig文件目錄,但kubeconfig文件為空,再指定bootstrap-kubeconfig文件為上述步驟生成的bootstrap-kubeconfig文件;
(2)kubelet發現配置的kubeconfig文件為空,則加載bootstrap-kubeconfig文件,讀取其中的bootstrap token以及master url;
(3)kubelet使用bootstrap token與apiserver通信,創建CSR證書簽名請求;
(4)kube-controller-manager批復CSR證書簽名請求,為其簽發相關證書;
(5)kubelet取回kube-controller-manager生成的相關證書,默認存放在/var/lib/kubelet/pki 目錄下,然后根據證書生成kubeconfig文件,后續kubelet將使用該kubeconfig文件與kube-apiserver進行認證通信;
# ls /var/lib/kubelet/pki/
kubelet-client-2022-03-18-14-29-00.pem kubelet-client-current.pem kubelet.crt kubelet.key
kubelet-client-current.pem是個軟鏈,指向kubelet-client-2022-03-18-14-29-00.pem文件,kubelet-client-2022-03-18-14-29-00.pem文件名記錄的是證書創建時間,后續kubelet將會根據證書過期時間,在證書臨過期前向kube-apiserver重新申請證書,然后自動輪換該證書;
# cat /etc/kubernetes/kubelet.conf
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0F...
server: https://192.168.1.10:6443
name: test-cluster
contexts:
- context:
cluster: test-cluster
user: system:node:test-cluster-node-1
name: system:node:test-cluster-node-1
current-context: system:node:test-cluster-node-1
kind: Config
preferences: {}
users:
- name: system:node:test-cluster-node-1
user:
client-certificate: /var/lib/kubelet/pki/kubelet-client-current.pem
client-key: /var/lib/kubelet/pki/kubelet-client-current.pem
3.kubelet自動輪換證書
(1)kubelet在證書接近於過期時自動向kube-apiserver請求更新證書;
(2)kube-controller-manager自動批復,為其簽發新的證書;
(3)kubelet取回kube-controller-manager生成的相關證書,替換掉本地的舊證書,后續kubelet將使用新證書來與kube-apiserver進行認證通信;
總結
最后以一幅圖來總結一下k8s TLS bootstrap的整個流程。

