一文帶你徹底厘清 Kubernetes 中的證書(shū)工作機(jī)制
本文轉(zhuǎn)載自微信公眾號(hào)「 趙化冰」,轉(zhuǎn)載本文請(qǐng)聯(lián)系 趙化冰公眾號(hào)。
目錄
- Kubernetes 組件的認(rèn)證方式
- Kubernetes 中使用到的CA和證書(shū)
- Kubernetes 中的證書(shū)配置
- etcd 證書(shū)配置
- kube-apiserver 證書(shū)配置
- 采用 kubeconfig 訪問(wèn) kube-apiserver
- Service Account 證書(shū)
- Kubernetes 證書(shū)簽發(fā)
- 使用 TLS bootstrapping 簡(jiǎn)化 Kubelet 證書(shū)制作
- 小結(jié)
- 參考文檔
Kubernetes 組件的認(rèn)證方式
首先讓我們來(lái)看一下 Kubernetes 中的組件:在 Kubernetes 中包含多個(gè)以獨(dú)立進(jìn)程形式運(yùn)行的組件,這些組件之間通過(guò) HTTP/GRPC 相互通信,以協(xié)同完成集群中應(yīng)用的部署和管理工作。
kubernetes 組件,圖片來(lái)源kubernetes.io
從圖中可以看到,Kubernetes 控制平面中包含了 etctd,kube-api-server,kube-scheduler,kube-controller-manager 等組件,這些組件會(huì)相互進(jìn)行遠(yuǎn)程調(diào)用,例如 kube-api-server 會(huì)調(diào)用 etcd 接口存儲(chǔ)數(shù)據(jù),kube-controller-manager 會(huì)調(diào)用 kube-api-server 接口查詢集群中的對(duì)象狀態(tài);同時(shí),kube-api-server 也會(huì)和在工作節(jié)點(diǎn)上的 kubelet 和 kube-proxy 進(jìn)行通信,以在工作節(jié)點(diǎn)上部署和管理應(yīng)用。
以上這些組件之間的相互調(diào)用都是通過(guò)網(wǎng)絡(luò)進(jìn)行的。在進(jìn)行網(wǎng)絡(luò)通信時(shí),通信雙方需要驗(yàn)證對(duì)方的身份,以避免惡意第三方偽造身份竊取信息或者對(duì)系統(tǒng)進(jìn)行攻擊。為了相互驗(yàn)證對(duì)方的身份,通信雙方中的任何一方都需要做下面兩件事情:
- 向?qū)Ψ教峁?biāo)明自己身份的一個(gè)證書(shū)
- 驗(yàn)證對(duì)方提供的身份證書(shū)是否合法,是否偽造的?
在 Kubernetes 中使用了數(shù)字證書(shū)來(lái)提供身份證明,我們可以把數(shù)字證書(shū)簡(jiǎn)單理解為我們?cè)谌粘I钪惺褂玫?ldquo;身份證”,上面標(biāo)注了證書(shū)擁有者的身份信息,例如名稱,所屬組織機(jī)構(gòu)等。為了保證證書(shū)的權(quán)威性,會(huì)采用一個(gè)通信雙方都信任的 CA(證書(shū)機(jī)構(gòu),Certificate Authority)來(lái)頒發(fā)證書(shū)。這就類(lèi)似于現(xiàn)實(shí)生活中頒發(fā)“身份證”的政府機(jī)構(gòu)。數(shù)字證書(shū)中最重要的內(nèi)容實(shí)際上是證書(shū)擁有者的公鑰,該公鑰代表了用戶的身份。本文假設(shè)讀者已經(jīng)了解數(shù)字證書(shū)和 CA 的基本原理,如果你對(duì)此不太清楚,或者希望重新溫習(xí)一下相關(guān)知識(shí),可以先閱讀一下這篇文章《數(shù)字證書(shū)原理》(https://zhaohuabing.com/post/2020-03-19-pki)。
CA (證書(shū)機(jī)構(gòu)),圖片來(lái)源www.trustauth.cn
在 Kubernetes 的組件之間進(jìn)行通信時(shí),數(shù)字證書(shū)的驗(yàn)證是在協(xié)議層面通過(guò) TLS 完成的,除了需要在建立通信時(shí)提供相關(guān)的證書(shū)和密鑰外,在應(yīng)用層面并不需要進(jìn)行特殊處理。采用 TLS 進(jìn)行驗(yàn)證有兩種方式:
- 服務(wù)器單向認(rèn)證:只需要服務(wù)器端提供證書(shū),客戶端通過(guò)服務(wù)器端證書(shū)驗(yàn)證服務(wù)的身份,但服務(wù)器并不驗(yàn)證客戶端的身份。這種情況一般適用于對(duì) Internet 開(kāi)放的服務(wù),例如搜索引擎網(wǎng)站,任何客戶端都可以連接到服務(wù)器上進(jìn)行訪問(wèn),但客戶端需要驗(yàn)證服務(wù)器的身份,以避免連接到偽造的惡意服務(wù)器。
- 雙向 TLS 認(rèn)證:除了客戶端需要驗(yàn)證服務(wù)器的證書(shū),服務(wù)器也要通過(guò)客戶端證書(shū)驗(yàn)證客戶端的身份。這種情況下服務(wù)器提供的是敏感信息,只允許特定身份的客戶端訪問(wèn)。
在 Kubernetes 中,各個(gè)組件提供的接口中包含了集群的內(nèi)部信息。如果這些接口被非法訪問(wèn),將影響集群的安全,因此組件之間的通信需要采用雙向 TLS 認(rèn)證。即客戶端和服務(wù)器端都需要驗(yàn)證對(duì)方的身份信息。在兩個(gè)組件進(jìn)行雙向認(rèn)證時(shí),會(huì)涉及到下面這些證書(shū)相關(guān)的文件:
- 服務(wù)器端證書(shū):服務(wù)器用于證明自身身份的數(shù)字證書(shū),里面主要包含了服務(wù)器端的公鑰以及服務(wù)器的身份信息。
- 服務(wù)器端私鑰:服務(wù)器端證書(shū)中包含的公鑰所對(duì)應(yīng)的私鑰。公鑰和私鑰是成對(duì)使用的,在進(jìn)行 TLS 驗(yàn)證時(shí),服務(wù)器使用該私鑰來(lái)向客戶端證明自己是服務(wù)器端證書(shū)的擁有者。
- 客戶端證書(shū):客戶端用于證明自身身份的數(shù)字證書(shū),里面主要包含了客戶端的公鑰以及客戶端的身份信息。
- 客戶端私鑰:客戶端證書(shū)中包含的公鑰所對(duì)應(yīng)的私鑰,同理,客戶端使用該私鑰來(lái)向服務(wù)器端證明自己是客戶端證書(shū)的擁有者。
- 服務(wù)器端 CA 根證書(shū):簽發(fā)服務(wù)器端證書(shū)的 CA 根證書(shū),客戶端使用該 CA 根證書(shū)來(lái)驗(yàn)證服務(wù)器端證書(shū)的合法性。
- 客戶端端 CA 根證書(shū):簽發(fā)客戶端證書(shū)的 CA 根證書(shū),服務(wù)器端使用該 CA 根證書(shū)來(lái)驗(yàn)證客戶端證書(shū)的合法性。
下面這張來(lái)自 《The magic of TLS, X509 and mutual authentication explained》 文章中的圖形象地解釋了雙向 TLS 認(rèn)證的原理。如果你需要了解更多關(guān)于 TLS 認(rèn)證的原理,可以閱讀一下 medium 上的原文(https://medium.com/sitewards/the-magic-of-tls-x509-and-mutual-authentication-explained-b2162dec4401)。
圖片來(lái)源The magic of TLS, X509 and mutual authentication explained
Kubernetes 中使用到的CA和證書(shū)
Kubernetes 中使用了大量的證書(shū),本文不會(huì)試圖覆蓋到所有可能使用到的證書(shū),但會(huì)討論到主要的證書(shū)。理解了這些證書(shū)的使用方法和原理后,也能很快理解其他可能遇到的證書(shū)文件。下圖標(biāo)識(shí)出了在 kubernetes 中主要使用到的證書(shū)和其使用的位置:
Kubernetes 中使用到的主要證書(shū)
上圖中使用序號(hào)對(duì)證書(shū)進(jìn)行了標(biāo)注。圖中的箭頭表明了組件的調(diào)用方向,箭頭所指方向?yàn)榉?wù)提供方,另一頭為服務(wù)調(diào)用方。為了實(shí)現(xiàn) TLS 雙向認(rèn)證,服務(wù)提供方需要使用一個(gè)服務(wù)器證書(shū),服務(wù)調(diào)用方則需要提供一個(gè)客戶端證書(shū),并且雙方都需要使用一個(gè) CA 證書(shū)來(lái)驗(yàn)證對(duì)方提供的證書(shū)。為了簡(jiǎn)明起見(jiàn),上圖中只標(biāo)注了證書(shū)使用方提供的證書(shū),并沒(méi)有標(biāo)注證書(shū)的驗(yàn)證方驗(yàn)證使用的 CA 證書(shū)。圖中標(biāo)注的這些證書(shū)的作用分別如下:
- etcd 集群中各個(gè)節(jié)點(diǎn)之間相互通信使用的證書(shū)。由于一個(gè) etctd 節(jié)點(diǎn)既為其他節(jié)點(diǎn)提供服務(wù),又需要作為客戶端訪問(wèn)其他節(jié)點(diǎn),因此該證書(shū)同時(shí)用作服務(wù)器證書(shū)和客戶端證書(shū)。
- etcd 集群向外提供服務(wù)使用的證書(shū)。該證書(shū)是服務(wù)器證書(shū)。
- kube-apiserver 作為客戶端訪問(wèn) etcd 使用的證書(shū)。該證書(shū)是客戶端證書(shū)。
- kube-apiserver 對(duì)外提供服務(wù)使用的證書(shū)。該證書(shū)是服務(wù)器證書(shū)。
- kube-controller-manager 作為客戶端訪問(wèn) kube-apiserver 使用的證書(shū),該證書(shū)是客戶端證書(shū)。
- kube-scheduler 作為客戶端訪問(wèn) kube-apiserver 使用的證書(shū),該證書(shū)是客戶端證書(shū)。
- kube-proxy 作為客戶端訪問(wèn) kube-apiserver 使用的證書(shū),該證書(shū)是客戶端證書(shū)。
- kubelet 作為客戶端訪問(wèn) kube-apiserver 使用的證書(shū),該證書(shū)是客戶端證書(shū)。
- 管理員用戶通過(guò) kubectl 訪問(wèn) kube-apiserver 使用的證書(shū),該證書(shū)是客戶端證書(shū)。
- kubelet 對(duì)外提供服務(wù)使用的證書(shū)。該證書(shū)是服務(wù)器證書(shū)。
- kube-apiserver 作為客戶端訪問(wèn) kubelet 采用的證書(shū)。該證書(shū)是客戶端證書(shū)。
- kube-controller-manager 用于生成和驗(yàn)證 service-account token 的證書(shū)。該證書(shū)并不會(huì)像其他證書(shū)一樣用于身份認(rèn)證,而是將證書(shū)中的公鑰/私鑰對(duì)用于 service account token 的生成和驗(yàn)證。kube-controller-manager 會(huì)用該證書(shū)的私鑰來(lái)生成 service account token,然后以 secret 的方式加載到 pod 中。pod 中的應(yīng)用可以使用該 token 來(lái)訪問(wèn) kube-apiserver, kube-apiserver 會(huì)使用該證書(shū)中的公鑰來(lái)驗(yàn)證請(qǐng)求中的 token。我們將在文中稍后部分詳細(xì)介紹該證書(shū)的使用方法。
通過(guò)這張圖,對(duì)證書(shū)機(jī)制比較了解的讀者可能已經(jīng)看出,我們其實(shí)可以使用多個(gè)不同的 CA 來(lái)頒發(fā)這些證書(shū)。只要在通信的組件中正確配置用于驗(yàn)證對(duì)方證書(shū)的 CA 根證書(shū),就可以使用不同的 CA 來(lái)頒發(fā)不同用途的證書(shū)。但我們一般建議采用統(tǒng)一的 CA 來(lái)頒發(fā) kubernetes 集群中的所有證書(shū),這是因?yàn)椴捎靡粋€(gè)集群根 CA 的方式比采用多個(gè) CA 的方式更容易管理,可以避免多個(gè)CA 導(dǎo)致的復(fù)雜的證書(shū)配置、更新等問(wèn)題,減少由于證書(shū)配置錯(cuò)誤導(dǎo)致的集群故障。
Kubernetes 中的證書(shū)配置
前面我們介紹了 Kubernetes 集群中主要使用到的證書(shū)。下面我們分別看一下如何將這些證書(shū)及其對(duì)應(yīng)的私鑰和 CA 根證書(shū)需要配置到 Kubernetes 中各個(gè)組件中,以供各個(gè)組件進(jìn)行使用。這里假設(shè)使用一個(gè)集群根 CA 來(lái)頒發(fā)所有相關(guān)證書(shū),因此涉及到 CA 的配置對(duì)應(yīng)的證書(shū)文件名都是相同的。
etcd 證書(shū)配置
需要在 etcd 的啟動(dòng)命令行中配置以下證書(shū)相關(guān)參數(shù):
- etcd 對(duì)外提供服務(wù)的服務(wù)器證書(shū)及私鑰。
- etcd 節(jié)點(diǎn)之間相互進(jìn)行認(rèn)證的 peer 證書(shū)、私鑰以及驗(yàn)證 peer 的 CA。
- etcd 驗(yàn)證訪問(wèn)其服務(wù)的客戶端的 CA。
- /usr/local/bin/etcd \\
- --cert-file=/etc/etcd/kube-etcd.pem \\ # 對(duì)外提供服務(wù)的服務(wù)器證書(shū)
- --key-file=/etc/etcd/kube-etcd-key.pem \\ # 服務(wù)器證書(shū)對(duì)應(yīng)的私鑰
- --peer-cert-file=/etc/etcd/kube-etcd-peer.pem \\ # peer 證書(shū),用于 etcd 節(jié)點(diǎn)之間的相互訪問(wèn)
- --peer-key-file=/etc/etcd/kube-etcd-peer-key.pem \\ # peer 證書(shū)對(duì)應(yīng)的私鑰
- --trusted-ca-file=/etc/etcd/cluster-root-ca.pem \\ # 用于驗(yàn)證訪問(wèn) etcd 服務(wù)器的客戶端證書(shū)的 CA 根證書(shū)
- --peer-trusted-ca-file=/etc/etcd/cluster-root-ca.pem\\ # 用于驗(yàn)證 peer 證書(shū)的 CA 根證書(shū)
- ...
kube-apiserver 證書(shū)配置
需要在 kube-apiserver 中配置以下證書(shū)相關(guān)參數(shù):
- kube-apiserver 對(duì)外提供服務(wù)的服務(wù)器證書(shū)及私鑰。
- kube-apiserver 訪問(wèn) etcd 所需的客戶端證書(shū)及私鑰。
- kube-apiserver 訪問(wèn) kubelet 所需的客戶端證書(shū)及私鑰。
- 驗(yàn)證訪問(wèn)其服務(wù)的客戶端的 CA。
- 驗(yàn)證 etcd 服務(wù)器證書(shū)的 CA 根證書(shū)。
- 驗(yàn)證 service account token 的公鑰。
- /usr/local/bin/kube-apiserver \\
- --tls-cert-file=/var/lib/kubernetes/kube-apiserver.pem \\ # 用于對(duì)外提供服務(wù)的服務(wù)器證書(shū)
- --tls-private-key-file=/var/lib/kubernetes/kube-apiserver-key.pem \\ # 服務(wù)器證書(shū)對(duì)應(yīng)的私鑰
- --etcd-certfile=/var/lib/kubernetes/kube-apiserver-etcd-client.pem \\ # 用于訪問(wèn) etcd 的客戶端證書(shū)
- --etcd-keyfile=/var/lib/kubernetes/kube-apiserver-etcd-client-key.pem \\ # 用于訪問(wèn) etcd 的客戶端證書(shū)的私鑰
- --kubelet-client-certificate=/var/lib/kubernetes/kube-apiserver-kubelet-client.pem \\ # 用于訪問(wèn) kubelet 的客戶端證書(shū)
- --kubelet-client-key=/var/lib/kubernetes/kube-apiserver-kubelet-client-key.pem \\ # 用于訪問(wèn) kubelet 的客戶端證書(shū)的私鑰
- --client-ca-file=/var/lib/kubernetes/cluster-root-ca.pem \\ # 用于驗(yàn)證訪問(wèn) kube-apiserver 的客戶端的證書(shū)的 CA 根證書(shū)
- --etcd-cafile=/var/lib/kubernetes/cluster-root-ca.pem \\ # 用于驗(yàn)證 etcd 服務(wù)器證書(shū)的 CA 根證書(shū)
- --kubelet-certificate-authority=/var/lib/kubernetes/cluster-root-ca.pem \\ # 用于驗(yàn)證 kubelet 服務(wù)器證書(shū)的 CA 根證書(shū)
- --service-account-key-file=/var/lib/kubernetes/service-account.pem \\ # 用于驗(yàn)證 service account token 的公鑰
- ...
采用 kubeconfig 訪問(wèn) kube-apiserver
Kubernetes 中的各個(gè)組件,包括kube-controller-mananger、kube-scheduler、kube-proxy、kubelet等,采用一個(gè)kubeconfig 文件中配置的信息來(lái)訪問(wèn) kube-apiserver。該文件中包含了 kube-apiserver 的地址,驗(yàn)證 kube-apiserver 服務(wù)器證書(shū)的 CA 證書(shū),自己的客戶端證書(shū)和私鑰等訪問(wèn)信息。
在一個(gè)使用 minikube 安裝的集群中,生成的 kubeconfig 配置文件如下所示,這四個(gè)文件分別為 admin 用戶, kube-controller-mananger、kubelet 和 kube-scheduler 的kubeconfig配置文件。
- $ ls /etc/kubernetes/
- admin.conf controller-manager.conf kubelet.conf scheduler.conf
我們打開(kāi) controller-manager.conf 來(lái)看一下。
- apiVersion: v1
- clusters:
- - cluster:
- # 用于驗(yàn)證 kube-apiserver 服務(wù)器證書(shū)的 CA 根證書(shū)
- certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM1ekNDQWMrZ0F3SUJBZ0lCQVRBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwdGFXNXAKYTNWaVpVTkJNQjRYRFRJd01ETXdOekF3TXpjeE1Wb1hEVE13TURNd05qQXdNemN4TVZvd0ZURVRNQkVHQTFVRQpBeE1LYldsdWFXdDFZbVZEUVRDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTTczCkdIMWxqNkxEUm1FLy9hQ2cvNUlmampKYy8zOGcyMVpITXJDMkx5RGVqZWhrdWUwZFB1WTJ0L2JjTjJYM1dGNEsKaWNzNmhhWnBDbFVxL3pteVRITWhhZnlmVVF5MDFJZmhDV2I5NXI4akpHZ2NyU3U3UUtXM3ZOd1Z1TmhJNmd6SApSWW45Ry82VHJKTjdOMWRjejNmMlU1OFRjUHVCQzZOUzVTc1JmemFSczVDZnd0UTNaa2czQUFVYTlQSDZFVmtDCkIvRGR1bXBialZGakMwSllOWlFVNTlGNUxDeHJ0bEYvOUJsSVhnZGw0ZlNCNzQ0ZW1UelcySEZQek9lTklYYnUKYTJPa0FFTDdJc3hSRTFBaEFKZ1h6cFNmdi9paDBuMEJpQ1VaV1hLZjg2UjZJL2xlK2docG51c21kTXUwbkNEUApHMm9laXhRTit5NzFQU2tGcGdzQ0F3RUFBYU5DTUVBd0RnWURWUjBQQVFIL0JBUURBZ0trTUIwR0ExVWRKUVFXCk1CUUdDQ3NHQVFVRkJ3TUNCZ2dyQmdFRkJRY0RBVEFQQmdOVkhSTUJBZjhFQlRBREFRSC9NQTBHQ1NxR1NJYjMKRFFFQkN3VUFBNElCQVFCaWpXYlpPNU9uaU9lNHRHUlQvRGFXaFBkY2ZwbE8vcVQ5WkFqU1hXZU41TStubExQZQpGV1NLRGRWU1NzajJ6UVdMU3A1Vjc3MkFoa2NYQlM0a2ZiY2ZCTUl2ejVsYXJZeHgxcnduTzZLbVZSTHdkNUNkCnRER2RjUjF0UzdqeTRSV05ISlAyNWZhZHB5TE9KVzJlZkdLRmRiSnZyRjljekV1ODR5a1drdThtVnNNa0RzTXkKbnVFNGtXblNvODgweFpxVG9QN01qM3hkRlNYYWdoNytwK3FMazk1VjhBNTRUNmRKa2VjSGg4SzdNYVRxdWVOVgpzOVhuZDA2WEJGQWFCVXRsSGZybmRXUzhmaTQ5dTY0NEFWOWJHclNYRnR1Q0lydnIxVkY2d0R3dEJYZi9UUStrCkx3Zk1oNVZDVWt1bEJqWEpqK1ZvRnBLZm5Qck9nbEExZzRtUgotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
- server: https://localhost:8443
- name: kubernetes
- contexts:
- - context:
- cluster: kubernetes
- user: system:kube-controller-manager
- name: system:kube-controller-manager@kubernetes
- current-context: system:kube-controller-manager@kubernetes
- kind: Config
- preferences: {}
- users:
- - name: system:kube-controller-manager
- user:
- # 用于訪問(wèn) kube-apiserver 的客戶端證書(shū)
- client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM1ekNDQWMrZ0F3SUJBZ0lJZVE4aDNXSlNmZEF3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2JXbHVhV3QxWW1WRFFUQWVGdzB5TURBek1EY3dNRE0zTVRGYUZ3MHlNVEExTVRrd05qVTNNemxhTUNreApKekFsQmdOVkJBTVRIbk41YzNSbGJUcHJkV0psTFdOdmJuUnliMnhzWlhJdGJXRnVZV2RsY2pDQ0FTSXdEUVlKCktvWklodmNOQVFFQkJRQURnZ0VQQURDQ0FRb0NnZ0VCQU5DTzJpTEZzNGRTTW9sR2plN2tjY1VFbURDVjEvbWQKV1p1cS9DT0RvV1p2Uy80clNrOXNsaFQvektIVTVkVmg3SFV4TGNWU1RkQXZScGEwN3dXK3h2eWlDR3Y5UmMyVAp0bkFnUFFhQ2VkOC8zZlFpMzI1QmZCZVl4UjRTTm8raEM1b0ZYYkhpdC9OWWlQTVMvM1hFOGVCc0dEZCtjd1pzCnhNTDZzc0pJNzVOSmNXckV3eXlMbzIrb1JSRmJ2TlpJWFRZekJpRGd3QkZxNUkzZVA5QTl2d29rUG5STFBSdlYKQU9SV3hUZDMyblJLOTY1SU9uV25mNzY0bHhSeEV6bHIyS09rSzc5NlVJWTlyL0lYOWdGQjNqbGZFK1lBOE5VLwpuV2x3cElNL0ZpMk9hL1hjNnQzNUJHSnNXcTR4bHQ5RDdqS3V2bTNONmJlanJPOFZNODU5QU44Q0F3RUFBYU1uCk1DVXdEZ1lEVlIwUEFRSC9CQVFEQWdXZ01CTUdBMVVkSlFRTU1Bb0dDQ3NHQVFVRkJ3TUNNQTBHQ1NxR1NJYjMKRFFFQkN3VUFBNElCQVFCZVg4QmVuTlJoUTVWaVpMMjRxcWxIMjRlMDVyYWVVTFZJQlQzWE90cmdQcXF1WXRGWgptRG9naEpuSW05aVVMcHFTTUxHMlJrQ0RBMEk2Rit0SGVFVHRMRDlNdjA2N1huQ2VCclhkTFVTYzkwaHNZWm1KClNsVG11c21TZGUxUXJsRnFxQVRZY2VCVWgwM0lSbXZIL1BtS21va1FUZDZER0paVVVhM3ducEN6Nko4aGcySGwKWlZFaURKcHNoeXNBaVdCUWZBN01TRlFlb0poSjhUdHgzdEhNZDlaaHlmcVVHOVByUGJkMUlBQTIrRlVudXRsNwpoRmdZdTBxbG5aZFZCWE9JM1dvZndWZ2dDTEQrbFVCeGgzNVhLNStxYXhWNVlDTit0ZTNFeDJERHVmRW1UV0FoCkwwUVNTc0RTZGd0Vi9TNFhvV2xQcXU0Q2lRVnZydUg3WHkxMwotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
- # 客戶端證書(shū)對(duì)應(yīng)的私鑰
- client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb3dJQkFBS0NBUUVBMEk3YUlzV3poMUl5aVVhTjd1Unh4UVNZTUpYWCtaMVptNnI4STRPaFptOUwvaXRLClQyeVdGUC9Nb2RUbDFXSHNkVEV0eFZKTjBDOUdsclR2QmI3Ry9LSUlhLzFGelpPMmNDQTlCb0o1M3ovZDlDTGYKYmtGOEY1akZIaEkyajZFTG1nVmRzZUszODFpSTh4TC9kY1R4NEd3WU4zNXpCbXpFd3ZxeXdranZrMGx4YXNURApMSXVqYjZoRkVWdTgxa2hkTmpNR0lPREFFV3JramQ0LzBEMi9DaVErZEVzOUc5VUE1RmJGTjNmYWRFcjNya2c2CmRhZC92cmlYRkhFVE9XdllvNlFydjNwUWhqMnY4aGYyQVVIZU9WOFQ1Z0R3MVQrZGFYQ2tnejhXTFk1cjlkenEKM2ZrRVlteGFyakdXMzBQdU1xNitiYzNwdDZPczd4VXp6bjBBM3dJREFRQUJBb0lCQVFDRDVMT2pKZkJoZGVRcgoySWpPT1g2Um9GUTI5YXgrV2JwZnJnU0MyUzNyUUJ1SkJBdWNxd2xIQW5hQktjaW41NlBJZ1c5MnlKUVpRcXliCmhwVmF4c25FM3h3QVgwNFRzb1MvNkVOdnFIZzJiWWVLYTd0dFdOQ0hnNysxUXNOcWxlaG1ZVnBkc3dtdVJhRm0KUis5eXBUaHFPeklkZGtSOEhiRlp0WDN6VEhqbVpYaUhGdlIvMFhYK1BVbDR6SllSWjlCbVBnY2Ric2tSTldScgo0Qk8wUmlQQWRKVEo2VHZLMGhxT1g1UHo4ekl3S1ZzYjdyYndUdXArTGs4eWNCVUd3Q1N3RzEyanVNQW1kYkJJClZmdmlFK1VYRHRIQXdLWXlnMEhCVitJVlEvcVNwSVJ1WXQ4SmY1MWVKN1VEbHhiN3ZRTStEYVNsNjVaMVNyWUcKQU9UTGpPVkJBb0dCQU5PYzB0OG5ybmhUR3V0MGhMdVp6SWs4ekFranhYYWtiSURlZi9XeXlQdW94Z3J2ZGMzcwpsbHV0U3hSOFV4WGVuQjBLZFpnYnNoc1ozeW9GbEI0YThTMzI1UFRsYm9xOVB0TDRaOFBzczQ3L0l1bHYxTk10CnZzZjdKZ1FuaFRCVndkdjN6OXFpdml6bjB4Mk9CdURxdzNSYXcvWEhwRy9RczJ5WmF4S29GNW9SQW9HQkFQeE8KQVBDUXQ2Q2swOFF2WTE4VjFLQXA0d2h1YWEyMS9MeC9rZUZJSURRd0tZZnFHRGdBWUYvQzJUbC9xc29TMXAvTwpFcFVkVkRBNHVpblFVbnFhNGg0a0JOYjRXTFhrSXhRdXdjWHdJNjRMNWR3ZWJHalhxUWUwbnkxQkhkTmU2Z0dqClorbit4OUJLWnJmcEliYkQ2blpYUUREbS9jZWYyWU5NVWRqVWpudnZBb0dBQnlIMUZhSi94ZngvSHNxWm9yMG4KWU1UVTE4WUY1TjdiN1dnU2hoU1ZvNjNucHZ5MVN0Q2JyTkZsZzNaQlVxNWpNck5ralZENXF1SXZYSG85cU5vZApvUC8rYmFiQ0dCa1M0Z2VQYjlJdHB6ZEFWUC80KzNsQ1FmbGNLYTJ2VnBhOVp3MnVTdDlMYTdZUXJxRlg2QUxoCnZhMUZoNlpJQzZETU8yL2NaUStYWkJFQ2dZQnNGMHNGeFNvMlU0YzZISWM1SEZRc2plVnJIa3ArRm1LQnF6R24KVDB3a3I2R0xUZm8wTzgwT0daOFFxQ1pXVGozTzF1MVZIdXlMZ0RJWmFkdDhGVkRjVXRnVDlPK2tkV21sNHVZMwpVOHNsYklsOGhUZ3lybm9IQ0JYTndJRHpwazBnaUk0alRIajBQbnZGUE1hcDAwTm1rYmk1ZXF5czBrblFtMmpSCk9UY1Yxd0tCZ0RNUWZSVlNNNXlGcjVIalJ4UXcwRDdrUWhONDlLbngrMWs2bWRORWJ6VG9rQ1RRcWlSeUJQdGgKcjlqZk0rRXFZcnZ1elRmRVpiS1VBMEZac09yeStxMHpXb29mTURLajFGV3BaTXJBSmdxdDFlcWtFbVFrVi8vSApQMzF3ejZDa1RneDdJby9iZ09PbmhsbUplU3NHaXpqenV2TjFEcWtjNVR3M3oxUSs1dmxmCi0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg==
可以看到,訪問(wèn) kube-apiserver 所需要的相關(guān)證書(shū)內(nèi)容已經(jīng)被采用 base64 編碼寫(xiě)入了文件中。其他幾個(gè)文件中的內(nèi)容也是類(lèi)似的,只是配置的用戶名和客戶端證書(shū)有所不同。
在啟動(dòng)這些組件時(shí),需要在參數(shù)中指出 kubeconfig 文件的路徑,例如 kube-controller-manager 的啟動(dòng)命令如下。
- /usr/local/bin/kube-controller-manager \\
- --kubeconfig=/etc/kubernetes/controller-manager.conf
- # 下面幾個(gè)證書(shū)和訪問(wèn) kube-apiserver 無(wú)關(guān),我們會(huì)在后面介紹到
- --cluster-signing-cert-file=/var/lib/kubernetes/cluster-root-ca.pem # 用于簽發(fā)證書(shū)的 CA 根證書(shū)
- --cluster-signing-key-file=/var/lib/kubernetes/cluster-root-ca-key.pem # 用于簽發(fā)證書(shū)的 CA 根證書(shū)的私鑰
- --service-account-private-key-file=/var/lib/kubernetes/service-account-key.pem # 用于對(duì) service account token 進(jìn)行簽名的私鑰
- ...
Service Account 證書(shū)
Kubernetes 中有兩類(lèi)用戶,一類(lèi)為 user account,一類(lèi)為 service account。service account 主要被 pod 用于訪問(wèn) kube-apiserver。在為一個(gè) pod 指定了 service account 后,kubernetes 會(huì)為該 service account 生成一個(gè) JWT token,并使用 secret 將該 service account token 加載到 pod 上。pod 中的應(yīng)用可以使用 service account token 來(lái)訪問(wèn) api server。service account 證書(shū)被用于生成和驗(yàn)證 service account token。該證書(shū)的用法和前面介紹的其他證書(shū)不同,因?yàn)閷?shí)際上使用的是其公鑰和私鑰,而并不需要對(duì)證書(shū)進(jìn)行驗(yàn)證。
我們可以看到 service account 證書(shū)的公鑰和私鑰分別被配置到了 kube-apiserver 和 kube-controller-manager 的命令行參數(shù)中,如下所示:
- /usr/local/bin/kube-apiserver \\
- --service-account-key-file=/var/lib/kubernetes/service-account.pem \\ # 用于驗(yàn)證 service account token 的公鑰
- ...
- /usr/local/bin/kube-controller-manager \\
- --service-account-private-key-file=/var/lib/kubernetes/service-account-key.pem # 用于對(duì) service account token 進(jìn)行簽名的私鑰
- ...
下圖展示了 kubernetes 中生成、使用和驗(yàn)證 service account token 的過(guò)程。
認(rèn)證方法:客戶端證書(shū)還是 token ?
從前面的介紹中我們可以看到,Kubernetes 提供了兩種客戶端認(rèn)證的方法,控制面組件采用的是客戶端數(shù)字證書(shū);而在集群中部署的應(yīng)用則采用了 service account token 的方式。為什么 Kubernetes 不為 service account 也生成一個(gè)證書(shū),并采用該證書(shū)進(jìn)行身份認(rèn)證呢?實(shí)際上 Istio 就是這樣做的,Istio 會(huì)自動(dòng)為每個(gè) service account 生成一個(gè)證書(shū),并使用該證書(shū)來(lái)在 pod 中的應(yīng)用之間建立雙向 tls 認(rèn)證。我沒(méi)有找到 Kubernetes 這個(gè)設(shè)計(jì)決策的相關(guān)說(shuō)明,如果你知道原因,歡迎和我聯(lián)系探討。
Kubernetes 證書(shū)簽發(fā)
Kubernetes 提供了一個(gè) certificates.k8s.io API,可以使用配置的 CA 根證書(shū)來(lái)簽發(fā)用戶證書(shū)。該 API 由 kube-controller-manager 實(shí)現(xiàn),其簽發(fā)證書(shū)使用的根證書(shū)在下面的命令行中進(jìn)行配置。我們希望 Kubernetes 采用集群根 CA 來(lái)簽發(fā)用戶證書(shū),因此在 kube-controller-manager 的命令行參數(shù)中將相關(guān)參數(shù)配置為了集群根 CA。
- /usr/local/bin/kube-controller-manager \\
- --cluster-signing-cert-file=/var/lib/kubernetes/cluster-root-ca.pem # 用于簽發(fā)證書(shū)的 CA 根證書(shū)
- --cluster-signing-key-file=/var/lib/kubernetes/cluster-root-ca-key.pem # 用于簽發(fā)證書(shū)的 CA 根證書(shū)的私鑰
- ...
關(guān)于更多 Kubernetes 證書(shū)簽發(fā) API 的內(nèi)容,可以參見(jiàn) 管理集群中的 TLS 認(rèn)證。
使用 TLS bootstrapping 簡(jiǎn)化 Kubelet 證書(shū)制作
在安裝 Kubernetes 時(shí),我們需要為每一個(gè)工作節(jié)點(diǎn)上的 Kubelet 分別生成一個(gè)證書(shū)。由于工作節(jié)點(diǎn)可能很多,手動(dòng)生成 Kubelet 證書(shū)的過(guò)程會(huì)比較繁瑣。為了解決這個(gè)問(wèn)題,Kubernetes 提供了 TLS bootstrapping (https://kubernetes.io/zh/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/) 的方式來(lái)簡(jiǎn)化 Kubelet 證書(shū)的生成過(guò)程。其原理是預(yù)先提供一個(gè) bootstrapping token,kubelet 通過(guò)該 kubelet 調(diào)用 kube-apiserver 的證書(shū)簽發(fā) API 來(lái)生成 自己需要的證書(shū)。要啟用該功能,需要在 kube-apiserver 中啟用 --enable-bootstrap-token-auth ,并創(chuàng)建一個(gè) kubelet 訪問(wèn) kube-apiserver 使用的 bootstrap token secret。如果使用 kubeadmin 安裝,可以使用 kubeadm token create命令來(lái)創(chuàng)建 token。
采用TLS bootstrapping 生成證書(shū)的流程如下:
- 調(diào)用 kube-apiserver 生成一個(gè) bootstrap token。
- 將該 bootstrap token 寫(xiě)入到一個(gè) kubeconfig 文件中,作為 kubelet 調(diào)用 kube-apiserver 的客戶端驗(yàn)證方式。
- 通過(guò) --bootstrap-kubeconfig 啟動(dòng)參數(shù)將 bootstrap token 傳遞給 kubelet 進(jìn)程。
- Kubelet 采用bootstrap token 調(diào)用 kube-apiserver API,生成自己所需的服務(wù)器和客戶端證書(shū)。
- 證書(shū)生成后,Kubelet 采用生成的證書(shū)和 kube-apiserver 進(jìn)行通信,并刪除本地的 kubeconfig 文件,以避免 bootstrap token 泄漏風(fēng)險(xiǎn)。
小結(jié)
Kubernetes 中使用了大量的證書(shū)來(lái)確保集群的安全,弄清楚這些證書(shū)的用途和配置方法將有助于我們深入理解 kubernetes 的安裝過(guò)程和組件的配置。本文是筆者在學(xué)習(xí) 過(guò)程中整理的 Kubernetes 集群中主要使用到的證書(shū),由于筆者對(duì) Kubernetes 的理解有限,文章中難免存在部分錯(cuò)誤,歡迎指正。
參考文檔
Kubernetes PKI 證書(shū)和要求 (https://kubernetes.io/zh/docs/setup/best-practices/certificates/)
kubernetes the hard way (https://github.com/kelseyhightower/kubernetes-the-hard-wa)
Kubernetes 之 二進(jìn)制安裝(二) 證書(shū)詳解(https://blog.51cto.com/13210651/2361208)
TLS bootstrapping (https://kubernetes.io/zh/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/)
數(shù)字證書(shū)原理 (https://zhaohuabing.com/post/2020-03-19-pki/)