k8s TLS bootstrap解析-k8s TLS bootstrap流程分析

良凱爾發表於2022-04-10

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的整個流程。

相關文章