Kubernetes客戶端認證(三)—— Kubernetes使用CertificateSigningRequest方式簽發客戶端證書

人艰不拆_zmc發表於2024-03-24

1、概述

  在《Kubernetes客戶端認證(一)—— 基於CA證書的雙向認證方式 》和《Kubernetes客戶端認證(二)—— 基於ServiceAccount的JWTToken認證》兩篇博文中詳細介紹了Kubernetes客戶端認證方式,包括以證書方式訪問的普通使用者或程序運維人員及 kubectl、 kubelet 等程序);以 ServiceAccount 方式(JWTToken)訪問的 Kubernetes 的內部服務程序,它是給執行在 Pod 裡的程序用的,它為 Pod 裡的程序提供了必要的身份證明,但它並不是給 Kubernetes 叢集的使用者(系統管理員、 運維人員、租戶使用者等)用的,對於Kubernetes叢集的使用者可以透過證書或者接入外部使用者系統來提供身份證明。而其中最簡單的方式便是為使用者簽發客戶端證書,簽發客戶端證書有兩種方式,一種是基於CA根證書籤發證書,另一個種是發起 CSR(Certificate Signing Requests)請求。
  在《Kubernetes客戶端認證(一)—— 基於CA證書的雙向認證方式 》這篇博文的3.2章節詳細介紹了基於CA根證書籤發證書,這種方式因為需要基於根CA證書、根CA私鑰進行證書籤發,一般需要在叢集的master節點上進行配置,但是生產環境下一般情況下我們都沒辦法進入到叢集的master節點機器,所以這種方式用的不多。但是一般情況我們都能拿到對應的一個kubeconfig檔案用來訪問k8s叢集,基於kubeconfig 檔案我們也可以進行證書的批准和授權,這就是k8s CSR機制,透過使用CSR方式簽發客戶端證書,這也是k8s推薦方式,本文主要講解如果透過k8s CSR機制來為使用者簽發客戶端證書。

2、CertificateSigningRequest(CSR)機制

  CertificateSigningRequest(CSR)資源用來向指定的簽名者申請證書籤名, 在最終簽名之前,申請可能被批准,也可能被拒絕。(特性狀態: Kubernetes v1.19 [stable])

2.1 請求籤名流程 

  CertificateSigningRequest 資源型別允許客戶端基於簽名請求申請發放 X.509 證書。 CertificateSigningRequest 物件在 spec.request 欄位中包含一個 PEM 編碼的 PKCS#10簽名請求。CertificateSigningRequest 使用 spec.signerName 欄位標示簽名者(請求的接收方)。 注意,spec.signerName 在 certificates.k8s.io/v1 之後的 API 版本是必填項。 在 Kubernetes v1.22 和以後的版本,客戶可以可選地設定 spec.expirationSeconds 欄位來為頒發的證書設定一個特定的有效期。該欄位的最小有效值是 600,也就是 10 分鐘。

建立完成的 CertificateSigningRequest,要先透過批准,然後才能簽名。 根據所選的簽名者,CertificateSigningRequest 可能會被控制器自動批准。 否則,就必須人工批准, 人工批准可以使用 REST API(或 go 客戶端),也可以執行 kubectl certificate approve 命令。 同樣,CertificateSigningRequest 也可能被駁回, 這就相當於通知了指定的簽名者,這個證書不能簽名。
對於已批准的證書,下一步是簽名。 對應的簽名控制器首先驗證簽名條件是否滿足,然後才建立證書。 簽名控制器然後更新 CertificateSigningRequest, 將新證書儲存到現有 CertificateSigningRequest 物件的 status.certificate 欄位中。 此時,欄位 status.certificate 要麼為空,要麼包含一個用 PEM 編碼的 X.509 證書。 直到簽名完成前,CertificateSigningRequest 的欄位 status.certificate 都為空。
一旦 status.certificate 欄位完成填充,請求既算完成, 客戶端現在可以從 CertificateSigningRequest 資源中獲取已簽名的證書的 PEM 資料。 當然如果不滿足簽名條件,簽名者可以拒籤。
為了減少叢集中遺留的過時的 CertificateSigningRequest 資源的數量, 一個垃圾收集控制器將會週期性地執行。 此垃圾收集器會清除在一段時間內沒有改變過狀態的 CertificateSigningRequests:
  • 已批准的請求:1 小時後自動刪除
  • 已拒絕的請求:1 小時後自動刪除
  • 已失敗的請求:1 小時後自動刪除
  • 掛起的請求:24 小時後自動刪除
  • 所有請求:在頒發的證書過期後自動刪除

2.2 Kubernetes 簽名者

  Kubernetes 提供了內建的簽名者,每個簽名者都有一個眾所周知的 signerName:

  • kubernetes.io/kube-apiserver-client:簽名的證書將被 API 伺服器視為客戶證書。 kube-controller-manager 不會自動批准它。
  • kubernetes.io/kube-apiserver-client-kubelet: 簽名的證書將被 kube-apiserver 視為客戶證書。 kube-controller-manager 可以自動批准它。
  • kubernetes.io/kubelet-serving: 簽名服務證書,該服務證書被 API 伺服器視為有效的 kubelet 服務證書, 但沒有其他保證。kube-controller-manager 不會自動批准它。
  • kubernetes.io/legacy-unknown: 不保證信任。Kubernetes 的一些第三方發行版可能會使用它簽署的客戶端證書。

  kube-controller-manager 為每個內建簽名者實現了控制平面簽名。 注意:所有這些故障僅在 kube-controller-manager 日誌中報告。

3、透過 CSR 簽發客戶端證書例項

1)生成使用者私鑰

openssl genrsa -out zmc.key 2048

2)生成證書請求檔案

// 基於使用者私鑰生成使用者證書籤名請求檔案zmc.csr,其中CN代表k8s使用者
openssl req -new -key zmc.key -subj "/CN=zmc" -out zmc.csr

3) 透過 kubectl 建立一個 CertificateSigningRequest 並將其提交到 Kubernetes 叢集

cat <<EOF | kubectl apply -f -
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  name: zmc
spec:
  request: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ1V6Q0NBVHNDQVFBd0RqRU1NQW9HQTFVRUF3d0RlbTFqTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQwpBUThBTUlJQkNnS0NBUUVBbWFLRWY5ODBIRkhneG9WdXVBL29oNHlvU1JPNG8vbEU1N1J4UmduT1ZlR0tDbXZoCjRSOWZ3bk9IRzZaUjFVdkd4RzdKY0duaFJFMlFlUFVvcXpVYkVxWnFtc0V4NmpmTHgycTRqd3RNRm9GMDFnaHMKY2RwU0p1WTNEeFlKdFhtbUhKM2h3Q1N1MEZPT1NNMHU2V3JWZ0FFVkRCUno2a0RRcE1lcjlscmQwenBIRTdkUgpJSFNYbWVuVTVFTHVuTGh3a0E5TUhuczAweHhkcEhiR2QrTUFTVEU4LzcrNzR5T3hkQmJZQVhRK04rV2pZQ1NWCm5JT1dVUktWSFpCVDJIKzZxMjFvNkVxK2JlczB2MkhBWmZPTjZhOVVoU2FpZjRQRm9vTXlyS21xSFRkMFdrZlkKY1FZZFVzR0tBUFI3YVZrbmx4cWFxVCtEbXNqM0pBVFdZVjZBV3dJREFRQUJvQUF3RFFZSktvWklodmNOQVFFTApCUUFEZ2dFQkFIOFhoZjJEeVlMRldkQmJtazMwY3FHMkI1Qlh5dEFZWU0vOHQ1Z2UvZjhlMUtEeWQ4aXNQbitXCll1ak5mMzFrNGllRGpZb2NPaDFKZFlTRUkrTmgwdkFiVXVWaU94OU1RY3RUZjBXb0hHTklwRlZ3SFVsNTE2R3MKazRMMEgyVXM5WnlNMUJXSGxVaG13MDJncGs5VjV2RDc3QjN6dnh3aUs4UnJyZlA2YWVScGtnbzdOcFg0bEVMWApRSVY0VzBUWExsTjF2Si9UaGVncHhRZVhPZHZMbjJxd084aEgyVmRSRnQzODNWS0RTNFR0UFdWNGw5WTJGSkxVCk01NlhsdEFhcFd2aDBnV3U4RWVjbzhJd0tSY2xvYzU2RUlob05OVzBHN2lUeDgxVW1LUWlPRXl3RVZVNllPaHAKa25wbXhreWFGUXo4QTdIeG1ON2ZIaTdwdUNCcGZDUT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUgUkVRVUVTVC0tLS0tCg==
  signerName: kubernetes.io/kube-apiserver-client
  #expirationSeconds: 86400  # one day
  usages:
  - client auth
EOF
  • request 欄位是 CSR 檔案內容的 base64 編碼值。 要得到該值,可以執行命令
cat zmc.csr | base64 | tr -d "\n"
  • expirationSeconds 證書過期時間(k8s 1.22版本之前沒有這個欄位,預設的過期時間是十年左右)
  • usage 欄位必須是 ‘client auth’,代表金鑰的用途

注意:下面的 csr 代表的是 certificatesigningrequests(是k8s裡面的一種資源),注意與上面的 certificate 區分開來。

檢視CertificateSigningRequest資源狀態

4)批准 CertificateSigningRequest

kubectl certificate approve zmc

檢視CertificateSigningRequest資源狀態

5)從 CertificateSigningRequest 匯出頒發的證書

kubectl get csr zmc -o jsonpath='{.status.certificate}'| base64 -d > zmc.crt

當前k8s叢集版本是1.21,可以看到預設的過期時間是十年左右。

驗證新簽發使用者證書也是由kuberntests叢集ca證書籤發的。

6)使用簽發的使用者證書訪問k8s叢集資源

配置使用者資訊到到對應的 kubeconfig 上下文中。

將客戶端證書檔案 zmc.crt 和客戶端金鑰檔案 zmc.key 設定為名為 zmc 的使用者憑證,並將這些證書和金鑰嵌入到 kubeconfig 檔案中
kubectl config set-credentials zmc --client-certificate=zmc.crt  --client-key=zmc.key  --embed-certs=true

檢視kubeconfig最新配置。

kubectl config view

為當前叢集和使用者zmc配置kubeconfi上下文。

kubectl config set-context zmc@cluster.local --cluster=cluster.local --user=zmc

切換上下文為當前新建立的使用者。

kubectl config use-context zmc@cluster.local

再次檢視kubeconfig最新配置。

使用簽發的使用者證書訪問k8s叢集資源。

注意: 如果訪問資源沒有許可權就為使用者當前k8s叢集維護對應資源的RBAC許可權,這塊詳細步驟可以參見《Kubernetes客戶端認證(一)—— 基於CA證書的雙向認證方式 》和《Kubernetes客戶端認證(二)—— 基於ServiceAccount的JWTToken認證》這兩篇博文,本文不再贅餘。

4、總結

  本文詳細講解了Kubernetes使用CertificateSigningRequest方式簽發客戶端證書詳細步驟,基於kubectl和k8s叢集互動為示例,當然也可以透過client-go與kube-apiserver互動管理CertificateSigningRequest資源簽發客戶端證書,並且對於可信客戶端證書頒發請求還可以透過開發自定義控制器自動進行證書審批工作。

參考:K8S叢集安全機制

參考:證書和證書籤名請求 (詳細步驟參加k8s官方文件)

相關文章