這個寫得確實專業,node
轉一下收藏。git
https://mritd.me/2018/01/07/kubernetes-tls-bootstrapping-note/github
閱讀本文章前,請先閱讀一下本文參考的相關文檔:bootstrap
Kubernetes 在 1.4 版本(我記着是)推出了 TLS bootstrapping 功能;這個功能主要解決了如下問題:api
當集羣開啓了 TLS 認證後,每一個節點的 kubelet 組件都要使用由 apiserver 使用的 CA 簽發的有效證書才能與 apiserver 通信;此時若是節點多起來,爲每一個節點單獨簽署證書將是一件很是繁瑣的事情;TLS bootstrapping 功能就是讓 kubelet 先使用一個預約的低權限用戶鏈接到 apiserver,而後向 apiserver 申請證書,kubelet 的證書由 apiserver 動態簽署;在配合 RBAC 受權模型下的工做流程大體以下所示(不完整,下面細說)併發
在官方 TLS bootstrapping 文檔中屢次提到過 kubelet server
這個東西;在通過翻閱大量文檔以及 TLS bootstrapping 設計文檔後得出,kubelet server
指的應該是 kubelet 的 10250 端口;app
kubelet 組件在工做時,採用主動的查詢機制,即按期請求 apiserver 獲取本身所應當處理的任務,如哪些 pod 分配到了本身身上,從而去處理這些任務;同時 kubelet 本身還會暴露出兩個自己 api 的端口,用於將本身自己的私有 api 暴露出去,這兩個端口分別是 10250 與 10255;對於 10250 端口,kubelet 會在其上採用 TLS 加密以提供適當的鑑權功能;對於 10255 端口,kubelet 會以只讀形式暴露組件自己的私有 api,而且不作鑑權處理dom
總結一下,就是說 kubelet 上實際上有兩個地方用到證書,一個是用於與 API server 通信所用到的證書,另外一個是 kubelet 的 10250 私有 api 端口須要用到的證書測試
kubelet 發起的 CSR 請求都是由 controller manager 來作實際簽署的,對於 controller manager 來講,TLS bootstrapping 下 kubelet 發起的 CSR 請求大體分爲如下三種google
O=system:nodes
和 CN=system:node:(node name)
形式發起的 CSR 請求大白話加本身測試得出的結果: nodeclient 類型的 CSR 僅在第一次啓動時會產生,selfnodeclient 類型的 CSR 請求實際上就是 kubelet renew 本身做爲 client 跟 apiserver 通信時使用的證書產生的,selfnodeserver 類型的 CSR 請求則是 kubelet 首次申請或後續 renew 本身的 10250 api 端口證書時產生的
在說具體的引導過程以前先談一下 TLS 和 RBAC,由於這兩個事不整明白下面的都不用談;
衆所周知 TLS 的做用就是對通信加密,防止中間人竊聽;同時若是證書不信任的話根本就沒法與 apiserver 創建鏈接,更不用提有沒有權限向 apiserver 請求指定內容
當 TLS 解決了通信問題後,那麼權限問題就應由 RBAC 解決(可使用其餘權限模型,如 ABAC);RBAC 中規定了一個用戶或者用戶組(subject)具備請求哪些 api 的權限;在配合 TLS 加密的時候,實際上 apiserver 讀取客戶端證書的 CN 字段做爲用戶名,讀取 O 字段做爲用戶組
從以上兩點上能夠總結出兩點: 第一,想要與 apiserver 通信就必須採用由 apiserver CA 簽發的證書,這樣才能造成信任關係,創建 TLS 鏈接;第二,能夠經過證書的 CN、O 字段來提供 RBAC 所需的用戶與用戶組
看完上面的介紹,不知道有沒有人想過,既然 TLS bootstrapping 功能是讓 kubelet 組件去 apiserver 申請證書,而後用於鏈接 apiserver;那麼第一次啓動時沒有證書如何鏈接 apiserver ?
這個問題實際上能夠去查看一下 bootstrap.kubeconfig
和 token.csv
獲得答案: 在 apiserver 配置中指定了一個 token.csv
文件,該文件中是一個預設的用戶配置;同時該用戶的 Token 和 apiserver 的 CA 證書被寫入了 kubelet 所使用的 bootstrap.kubeconfig
配置文件中;這樣在首次請求時,kubelet 使用 bootstrap.kubeconfig
中的 apiserver CA 證書來與 apiserver 創建 TLS 通信,使用 bootstrap.kubeconfig
中的用戶 Token 來向 apiserver 聲明本身的 RBAC 受權身份,以下圖所示
在有些用戶首次啓動時,可能與遇到 kubelet 報 401 無權訪問 apiserver 的錯誤;這是由於在默認狀況下,kubelet 經過 bootstrap.kubeconfig
中的預設用戶 Token 聲明瞭本身的身份,而後建立 CSR 請求;可是不要忘記這個用戶在咱們不處理的狀況下他沒任何權限的,包括建立 CSR 請求;因此須要以下命令建立一個 ClusterRoleBinding,將預設用戶 kubelet-bootstrap
與內置的 ClusterRole system:node-bootstrapper
綁定到一塊兒,使其可以發起 CSR 請求
kubectl create clusterrolebinding kubelet-bootstrap \ --clusterrole=system:node-bootstrapper \ --user=kubelet-bootstrap
在 kubelet 首次啓動後,若是用戶 Token 沒問題,而且 RBAC 也作了相應的設置,那麼此時在集羣內應該能看到 kubelet 發起的 CSR 請求
出現 CSR 請求後,可使用 kubectl 手動簽發(容許) kubelet 的證書
當成功簽發證書後,目標節點的 kubelet 會將證書寫入到 --cert-dir=
選項指定的目錄中;注意此時若是不作其餘設置應當生成四個文件
而 kubelet 與 apiserver 通信所使用的證書爲 kubelet-client.crt
,剩下的 kubelet.crt
將會被用於 kubelet server
(10250) 作鑑權使用;注意,此時 kubelet.crt
這個證書是個獨立於 apiserver CA 的自籤 CA,而且刪除後 kubelet 組件會從新生成它
單獨把這部分拿出來寫,是由於我的以爲上面已經有點亂了;這部分實際上更復雜,只好單獨寫一下了,由於這部分涉及的東西比較多,因此也不想草率的幾筆帶過
首先…首先好幾回了…嗯,就是說 kubelet 所發起的 CSR 請求是由 controller manager 簽署的;若是想要是實現自動續期,就須要讓 controller manager 可以在 kubelet 發起證書請求的時候自動幫助其簽署證書;那麼 controller manager 不可能對全部的 CSR 證書申請都自動簽署,這時候就須要配置 RBAC 規則,保證 controller manager 只對 kubelet 發起的特定 CSR 請求自動批准便可;在 TLS bootstrapping 官方文檔中,針對上面 2.2 章節提出的 3 種 CSR 請求分別給出了 3 種對應的 ClusterRole,以下所示
# A ClusterRole which instructs the CSR approver to approve a user requesting # node client credentials. kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: approve-node-client-csr rules: - apiGroups: ["certificates.k8s.io"] resources: ["certificatesigningrequests/nodeclient"] verbs: ["create"] --- # A ClusterRole which instructs the CSR approver to approve a node renewing its # own client credentials. kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: approve-node-client-renewal-csr rules: - apiGroups: ["certificates.k8s.io"] resources: ["certificatesigningrequests/selfnodeclient"] verbs: ["create"] --- # A ClusterRole which instructs the CSR approver to approve a node requesting a # serving cert matching its client cert. kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: approve-node-server-renewal-csr rules: - apiGroups: ["certificates.k8s.io"] resources: ["certificatesigningrequests/selfnodeserver"] verbs: ["create"]
RBAC 中 ClusterRole 只是描述或者說定義一種集羣範圍內的能力,這三個 ClusterRole 在 1.7 以前須要本身手動建立,在 1.8 後 apiserver 會自動建立前兩個(1.8 之後名稱有改變,本身查看文檔);以上三個 ClusterRole 含義以下
因此,若是想要 kubelet 可以自動續期,那麼就應當將適當的 ClusterRole 綁定到 kubelet 自動續期時所所採用的用戶或者用戶組身上
在自動續期下引導過程與單純的手動批准 CSR 有點差別,具體的引導流程地址以下
從以上流程咱們能夠看出,咱們若是要建立 RBAC 規則,則至少能知足四種狀況:
基於以上四種狀況,咱們須要建立 3 個 ClusterRoleBinding,建立以下
# 自動批准 kubelet 的首次 CSR 請求(用於與 apiserver 通信的證書) kubectl create clusterrolebinding node-client-auto-approve-csr --clusterrole=approve-node-client-csr --group=system:bootstrappers # 自動批准 kubelet 後續 renew 用於與 apiserver 通信證書的 CSR 請求 kubectl create clusterrolebinding node-client-auto-renew-crt --clusterrole=approve-node-client-renewal-csr --group=system:nodes # 自動批准 kubelet 發起的用於 10250 端口鑑權證書的 CSR 請求(包括後續 renew) kubectl create clusterrolebinding node-server-auto-renew-crt --clusterrole=approve-node-server-renewal-csr --group=system:nodes
在 1.7 後,kubelet 啓動時增長 --feature-gates=RotateKubeletClientCertificate=true,RotateKubeletServerCertificate=true
選項,則 kubelet 在證書即將到期時會自動發起一個 renew 本身證書的 CSR 請求;同時 controller manager 須要在啓動時增長 --feature-gates=RotateKubeletServerCertificate=true
參數,再配合上面建立好的 ClusterRoleBinding,kubelet client 和 kubelet server 證才書會被自動簽署;
注意,1.7 版本設置自動續期參數後,新的 renew 請求不會當即開始,而是在證書總有效期的 70%~90%
的時間時發起;並且經測試 1.7 版本即便自動簽發了證書,kubelet 在不重啓的狀況下不會從新應用新證書;在 1.8 後 kubelet 組件在增長一個 --rotate-certificates
參數後,kubelet 纔會自動重載新證書
須要重複強調一個問題是: TLS bootstrapping 時的證書實際是由 kube-controller-manager 組件來簽署的,也就是說證書有效期是 kube-controller-manager 組件控制的;因此在 1.7 版本之後(我查文檔發現的從1.7開始有) kube-controller-manager 組件提供了一個 --experimental-cluster-signing-duration
參數來設置簽署的證書有效時間;默認爲 8760h0m0s
,將其改成 87600h0m0s
即 10 年後再進行 TLS bootstrapping 簽署證書便可。
kubelet 首次啓動經過加載 bootstrap.kubeconfig
中的用戶 Token 和 apiserver CA 證書發起首次 CSR 請求,這個 Token 被預先內置在 apiserver 節點的 token.csv 中,其身份爲 kubelet-bootstrap
用戶和 system:bootstrappers
用戶組;想要首次 CSR 請求能成功(成功指的是不會被 apiserver 401 拒絕),則須要先將 kubelet-bootstrap
用戶和 system:node-bootstrapper
內置 ClusterRole 綁定;
對於首次 CSR 請求能夠手動批准,也能夠將 system:bootstrappers
用戶組與 approve-node-client-csr
ClusterRole 綁定實現自動批准(1.8 以前這個 ClusterRole 須要手動建立,1.8 後 apiserver 自動建立,並改名爲 system:certificates.k8s.io:certificatesigningrequests:nodeclient
)
默認簽署的的證書只有 1 年有效期,若是想要調整證書有效期能夠經過設置 kube-controller-manager 的 --experimental-cluster-signing-duration
參數實現,該參數默認值爲 8760h0m0s
對於證書自動續簽,須要經過協調兩個方面實現;第一,想要 kubelet 在證書到期後自動發起續期請求,則須要在 kubelet 啓動時增長 --feature-gates=RotateKubeletClientCertificate=true,RotateKubeletServerCertificate=true
來實現;第二,想要讓 controller manager 自動批准續簽的 CSR 請求須要在 controller manager 啓動時增長 --feature-gates=RotateKubeletServerCertificate=true
參數,並綁定對應的 RBAC 規則;同時須要注意的是 1.7 版本的 kubelet 自動續簽後須要手動重啓 kubelet 以使其從新加載新證書,而 1.8 後只須要在 kublet 啓動時附帶 --rotate-certificates
選項就會自動從新加載新證書
該文件爲一個用戶的描述文件,基本格式爲 Token,用戶名,UID,用戶組
;這個文件在 apiserver 啓動時被 apiserver 加載,而後就至關於在集羣內建立了一個這個用戶;接下來就能夠用 RBAC 給他受權;持有這個用戶 Token 的組件訪問 apiserver 的時候,apiserver 根據 RBAC 定義的該用戶應當具備的權限來處理相應請求
該文件中內置了 token.csv 中用戶的 Token,以及 apiserver CA 證書;kubelet 首次啓動會加載此文件,使用 apiserver CA 證書創建與 apiserver 的 TLS 通信,使用其中的用戶 Token 做爲身份標識像 apiserver 發起 CSR 請求
該文件在 kubelet 完成 TLS bootstrapping 後生成,此證書是由 controller manager 簽署的,此後 kubelet 將會加載該證書,用於與 apiserver 創建 TLS 通信,同時使用該證書的 CN 字段做爲用戶名,O 字段做爲用戶組向 apiserver 發起其餘請求
該文件在 kubelet 完成 TLS bootstrapping 後而且沒有配置 --feature-gates=RotateKubeletServerCertificate=true
時纔會生成;這種狀況下該文件爲一個獨立於 apiserver CA 的自籤 CA 證書,有效期爲 1 年;被用做 kubelet 10250 api 端口
該文件在 kubelet 完成 TLS bootstrapping 後而且配置了 --feature-gates=RotateKubeletServerCertificate=true
時纔會生成;這種狀況下該證書由 apiserver CA 簽署,默認有效期一樣是 1 年,被用做 kubelet 10250 api 端口鑑權
這是一個軟鏈接文件,當 kubelet 配置了 --feature-gates=RotateKubeletClientCertificate=true
選項後,會在證書總有效期的 70%~90%
的時間內發起續期請求,請求被批准後會生成一個 kubelet-client-時間戳.pem
;kubelet-client-current.pem
文件則始終軟鏈接到最新的真實證書文件,除首次啓動外,kubelet 一直會使用這個證書同 apiserver 通信
一樣是一個軟鏈接文件,當 kubelet 配置了 --feature-gates=RotateKubeletServerCertificate=true
選項後,會在證書總有效期的 70%~90%
的時間內發起續期請求,請求被批准後會生成一個 kubelet-server-時間戳.pem
;kubelet-server-current.pem
文件則始終軟鏈接到最新的真實證書文件,該文件將會一直被用於 kubelet 10250 api 端口鑑權
apiserver 預先放置 token.csv,內容樣例以下
6df3c701f979cee17732c30958745947,kubelet-bootstrap,10001,"system:bootstrappers"
容許 kubelet-bootstrap 用戶建立首次啓動的 CSR 請求
kubectl create clusterrolebinding kubelet-bootstrap \ --clusterrole=system:node-bootstrapper \ --user=kubelet-bootstrap
配置 kubelet 自動續期,RotateKubeletClientCertificate 用於自動續期 kubelet 鏈接 apiserver 所用的證書(kubelet-client-xxxx.pem),RotateKubeletServerCertificate 用於自動續期 kubelet 10250 api 端口所使用的證書(kubelet-server-xxxx.pem)
KUBELET_ARGS="--cgroup-driver=cgroupfs \ --cluster-dns=10.254.0.2 \ --resolv-conf=/etc/resolv.conf \ --experimental-bootstrap-kubeconfig=/etc/kubernetes/bootstrap.kubeconfig \ --feature-gates=RotateKubeletClientCertificate=true,RotateKubeletServerCertificate=true \ --kubeconfig=/etc/kubernetes/kubelet.kubeconfig \ --fail-swap-on=false \ --cert-dir=/etc/kubernetes/ssl \ --cluster-domain=cluster.local. \ --hairpin-mode=promiscuous-bridge \ --serialize-image-pulls=false \ --pod-infra-container-image=gcr.io/google_containers/pause-amd64:3.0"
配置 controller manager 自動批准相關 CSR 請求,若是不配置 --feature-gates=RotateKubeletServerCertificate=true
參數,則即便配置了相關的 RBAC 規則,也只會自動批准 kubelet client 的 renew 請求
KUBE_CONTROLLER_MANAGER_ARGS="--address=0.0.0.0 \ --service-cluster-ip-range=10.254.0.0/16 \ --feature-gates=RotateKubeletServerCertificate=true \ --cluster-name=kubernetes \ --cluster-signing-cert-file=/etc/kubernetes/ssl/k8s-root-ca.pem \ --cluster-signing-key-file=/etc/kubernetes/ssl/k8s-root-ca-key.pem \ --service-account-private-key-file=/etc/kubernetes/ssl/k8s-root-ca-key.pem \ --root-ca-file=/etc/kubernetes/ssl/k8s-root-ca.pem \ --leader-elect=true \ --node-monitor-grace-period=40s \ --node-monitor-period=5s \ --pod-eviction-timeout=5m0s"
建立自動批准相關 CSR 請求的 ClusterRole
# A ClusterRole which instructs the CSR approver to approve a user requesting # node client credentials. kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: approve-node-client-csr rules: - apiGroups: ["certificates.k8s.io"] resources: ["certificatesigningrequests/nodeclient"] verbs: ["create"] --- # A ClusterRole which instructs the CSR approver to approve a node renewing its # own client credentials. kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: approve-node-client-renewal-csr rules: - apiGroups: ["certificates.k8s.io"] resources: ["certificatesigningrequests/selfnodeclient"] verbs: ["create"] --- # A ClusterRole which instructs the CSR approver to approve a node requesting a # serving cert matching its client cert. kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: approve-node-server-renewal-csr rules: - apiGroups: ["certificates.k8s.io"] resources: ["certificatesigningrequests/selfnodeserver"] verbs: ["create"]
將 ClusterRole 綁定到適當的用戶組,以完成自動批准相關 CSR 請求
# 自動批准 system:bootstrappers 組用戶 TLS bootstrapping 首次申請證書的 CSR 請求 kubectl create clusterrolebinding node-client-auto-approve-csr --clusterrole=approve-node-client-csr --group=system:bootstrappers # 自動批准 system:nodes 組用戶更新 kubelet 自身與 apiserver 通信證書的 CSR 請求 kubectl create clusterrolebinding node-client-auto-renew-crt --clusterrole=approve-node-client-renewal-csr --group=system:nodes # 自動批准 system:nodes 組用戶更新 kubelet 10250 api 端口證書的 CSR 請求 kubectl create clusterrolebinding node-server-auto-renew-crt --clusterrole=approve-node-server-renewal-csr --group=system:nodes
一切就緒後啓動 kubelet 組件便可,不過須要注意的是 1.7 版本 kubelet 不會自動重載 renew 的證書,須要本身手動重啓
apiserver 預先放置 token.csv,內容樣例以下
6df3c701f979cee17732c30958745947,kubelet-bootstrap,10001,"system:bootstrappers"
容許 kubelet-bootstrap 用戶建立首次啓動的 CSR 請求
kubectl create clusterrolebinding kubelet-bootstrap \ --clusterrole=system:node-bootstrapper \ --user=kubelet-bootstrap
配置 kubelet 自動續期,RotateKubeletClientCertificate 用於自動續期 kubelet 鏈接 apiserver 所用的證書(kubelet-client-xxxx.pem),RotateKubeletServerCertificate 用於自動續期 kubelet 10250 api 端口所使用的證書(kubelet-server-xxxx.pem),--rotate-certificates
選項使得 kubelet 可以自動重載新證書
KUBELET_ARGS="--cgroup-driver=cgroupfs \ --cluster-dns=10.254.0.2 \ --resolv-conf=/etc/resolv.conf \ --experimental-bootstrap-kubeconfig=/etc/kubernetes/bootstrap.kubeconfig \ --feature-gates=RotateKubeletClientCertificate=true,RotateKubeletServerCertificate=true \ --rotate-certificates \ --kubeconfig=/etc/kubernetes/kubelet.kubeconfig \ --fail-swap-on=false \ --cert-dir=/etc/kubernetes/ssl \ --cluster-domain=cluster.local. \ --hairpin-mode=promiscuous-bridge \ --serialize-image-pulls=false \ --pod-infra-container-image=gcr.io/google_containers/pause-amd64:3.0"
配置 controller manager 自動批准相關 CSR 請求,若是不配置 --feature-gates=RotateKubeletServerCertificate=true
參數,則即便配置了相關的 RBAC 規則,也只會自動批准 kubelet client 的 renew 請求
KUBE_CONTROLLER_MANAGER_ARGS="--address=0.0.0.0 \ --service-cluster-ip-range=10.254.0.0/16 \ --cluster-name=kubernetes \ --cluster-signing-cert-file=/etc/kubernetes/ssl/k8s-root-ca.pem \ --cluster-signing-key-file=/etc/kubernetes/ssl/k8s-root-ca-key.pem \ --service-account-private-key-file=/etc/kubernetes/ssl/k8s-root-ca-key.pem \ --feature-gates=RotateKubeletServerCertificate=true \ --root-ca-file=/etc/kubernetes/ssl/k8s-root-ca.pem \ --leader-elect=true \ --experimental-cluster-signing-duration 10m0s \ --node-monitor-grace-period=40s \ --node-monitor-period=5s \ --pod-eviction-timeout=5m0s"
建立自動批准相關 CSR 請求的 ClusterRole,相對於 1.7 版本,1.8 的 apiserver 自動建立了前兩條 ClusterRole,因此只須要建立一條就好了
# A ClusterRole which instructs the CSR approver to approve a node requesting a # serving cert matching its client cert. kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: system:certificates.k8s.io:certificatesigningrequests:selfnodeserver rules: - apiGroups: ["certificates.k8s.io"] resources: ["certificatesigningrequests/selfnodeserver"] verbs: ["create"]
將 ClusterRole 綁定到適當的用戶組,以完成自動批准相關 CSR 請求
# 自動批准 system:bootstrappers 組用戶 TLS bootstrapping 首次申請證書的 CSR 請求 kubectl create clusterrolebinding node-client-auto-approve-csr --clusterrole=system:certificates.k8s.io:certificatesigningrequests:nodeclient --group=system:bootstrappers # 自動批准 system:nodes 組用戶更新 kubelet 自身與 apiserver 通信證書的 CSR 請求 kubectl create clusterrolebinding node-client-auto-renew-crt --clusterrole=system:certificates.k8s.io:certificatesigningrequests:selfnodeclient --group=system:nodes # 自動批准 system:nodes 組用戶更新 kubelet 10250 api 端口證書的 CSR 請求 kubectl create clusterrolebinding node-server-auto-renew-crt --clusterrole=system:certificates.k8s.io:certificatesigningrequests:selfnodeserver --group=system:nodes
一切就緒後啓動 kubelet 組件便可,1.8 版本 kubelet 會自動重載證書,如下爲 1.8 版本在運行一段時間後的相關證書截圖
轉載請註明出處,本文采用 CC4.0 協議受權