TLS 引導

在 Kubernetes 叢集中,工作節點上的元件(kubelet 和 kube-proxy)需要與 Kubernetes 控制平面元件(特別是 kube-apiserver)進行通訊。為了確保通訊的私密性、不被幹擾,並確保叢集中的每個元件都與另一個受信任的元件通訊,我們強烈建議在節點上使用客戶端 TLS 證書。

引導這些元件的正常過程,特別是需要證書才能安全地與 kube-apiserver 通訊的工作節點,可能是一個具有挑戰性的過程,因為它通常超出 Kubernetes 的範圍,需要大量的額外工作。這反過來又會使叢集的初始化或擴縮變得困難。

為了簡化此過程,Kubernetes 從 1.4 版開始引入了證書請求和簽名 API。該提案可以在此處找到。

本文件描述了節點初始化過程、如何為 kubelet 設定 TLS 客戶端證書引導以及其工作原理。

初始化過程

當工作節點啟動時,kubelet 會執行以下操作:

  1. 查詢其 kubeconfig 檔案
  2. kubeconfig 檔案中檢索 API 伺服器的 URL 和憑據,通常是 TLS 金鑰和簽名證書
  3. 嘗試使用憑據與 API 伺服器通訊。

假設 kube-apiserver 成功驗證了 kubelet 的憑據,它將把 kubelet 視為有效節點,並開始為其分配 Pod。

請注意,上述過程取決於:

  • kubeconfig 中本地主機上存在金鑰和證書
  • 證書已由 kube-apiserver 信任的證書頒發機構 (CA) 簽名

以下所有操作都是叢集設定者和管理者​​的職責:

  1. 建立 CA 金鑰和證書
  2. 將 CA 證書分發到執行 kube-apiserver 的控制平面節點
  3. 為每個 kubelet 建立一個金鑰和證書;強烈建議每個 kubelet 都有一個唯一的金鑰和證書,具有唯一的 CN
  4. 使用 CA 金鑰簽署 kubelet 證書
  5. 將 kubelet 金鑰和簽名證書分發到執行 kubelet 的特定節點

本文件中描述的 TLS 引導旨在簡化、部分甚至完全自動化步驟 3 及之後的步驟,因為這些步驟在初始化或擴縮叢集時最常見。

引導初始化

在引導初始化過程中,會發生以下情況:

  1. kubelet 啟動
  2. kubelet 發現它沒有 kubeconfig 檔案
  3. kubelet 搜尋並找到 bootstrap-kubeconfig 檔案
  4. kubelet 讀取其引導檔案,檢索 API 伺服器的 URL 和一個有限用途的“令牌”
  5. kubelet 連線到 API 伺服器,使用令牌進行身份驗證
  6. kubelet 現在擁有有限的憑據來建立和檢索證書籤名請求 (CSR)
  7. kubelet 為自己建立一個 CSR,並將 signerName 設定為 kubernetes.io/kube-apiserver-client-kubelet
  8. CSR 以兩種方式之一獲得批准:
    • 如果已配置,kube-controller-manager 會自動批准 CSR
    • 如果已配置,外部程序(可能是人)使用 Kubernetes API 或透過 kubectl 批准 CSR
  9. 為 kubelet 建立證書
  10. 證書頒發給 kubelet
  11. kubelet 檢索證書
  12. kubelet 使用金鑰和簽名證書建立一個適當的 kubeconfig
  13. kubelet 開始正常執行
  14. 可選:如果已配置,kubelet 會在其接近過期時自動請求續訂證書
  15. 續訂的證書根據配置自動或手動批准和頒發。

本文件的其餘部分描述了配置 TLS 引導的必要步驟及其侷限性。

配置

要配置 TLS 引導和可選的自動批准,您必須在以下元件上配置選項:

  • kube-apiserver
  • kube-controller-manager
  • kubelet
  • 叢集內資源:ClusterRoleBinding 和可能的 ClusterRole

此外,您還需要 Kubernetes 證書頒發機構 (CA)。

證書頒發機構

與非引導方式一樣,您將需要一個證書頒發機構 (CA) 金鑰和證書。與非引導方式一樣,這些將用於簽署 kubelet 證書。與之前一樣,您有責任將它們分發到控制平面節點。

為了本文件的目的,我們假設這些已分發到控制平面節點上的 /var/lib/kubernetes/ca.pem(證書)和 /var/lib/kubernetes/ca-key.pem(金鑰)。我們將這些稱為“Kubernetes CA 證書和金鑰”。

所有使用這些證書的 Kubernetes 元件(kubelet、kube-apiserver、kube-controller-manager)都假定金鑰和證書是 PEM 編碼的。

kube-apiserver 配置

kube-apiserver 啟用 TLS 引導有幾個要求:

  • 識別簽署客戶端證書的 CA
  • 將引導 kubelet 認證到 system:bootstrappers
  • 授權引導 kubelet 建立證書籤名請求 (CSR)

識別客戶端證書

這對於所有客戶端證書身份驗證都是正常的。如果尚未設定,請將 --client-ca-file=FILENAME 標誌新增到 kube-apiserver 命令以啟用客戶端證書身份驗證,引用包含簽名證書的證書頒發機構包,例如 --client-ca-file=/var/lib/kubernetes/ca.pem

初始引導身份驗證

為了讓引導 kubelet 連線到 kube-apiserver 並請求證書,它必須首先向伺服器進行身份驗證。您可以使用任何可以認證 kubelet 的身份驗證器

雖然任何身份驗證策略都可以用於 kubelet 的初始引導憑據,但建議使用以下兩種身份驗證器以簡化配置。

  1. 引導令牌
  2. 令牌認證檔案

使用引導令牌是一種更簡單、更易於管理的 kubelet 身份驗證方法,並且在啟動 kube-apiserver 時不需要任何額外的標誌。

無論您選擇哪種方法,要求是 kubelet 能夠以具有以下權利的使用者身份進行身份驗證:

  1. 建立和檢索 CSR
  2. 如果啟用了自動批准,則自動批准請求節點客戶端證書。

使用引導令牌進行身份驗證的 kubelet 以 system:bootstrappers 組中的使用者身份進行身份驗證,這是使用的標準方法。

隨著此功能的成熟,您應該確保令牌繫結到基於角色的訪問控制 (RBAC) 策略,該策略嚴格限制請求(使用引導令牌)僅限於與證書配置相關的客戶端請求。有了 RBAC,將令牌範圍限定到某個組可以提供很大的靈活性。例如,在完成節點配置後,您可以停用特定引導組的訪問許可權。

引導令牌

引導令牌的詳細資訊可在此處獲取。這些令牌作為 secret 儲存在 Kubernetes 叢集中,然後頒發給單個 kubelet。您可以為一個完整的叢集使用一個令牌,或者為每個工作節點頒發一個令牌。

這個過程分為兩部分:

  1. 建立包含令牌 ID、secret 和範圍的 Kubernetes secret。
  2. 將令牌頒發給 kubelet

從 kubelet 的角度來看,一個令牌與其他令牌沒有特殊意義。然而,從 kube-apiserver 的角度來看,引導令牌是特殊的。由於其 typenamespacename,kube-apiserver 將其識別為特殊令牌,並授予使用該令牌進行身份驗證的任何人特殊引導許可權,特別是將他們視為 system:bootstrappers 組的成員。這滿足了 TLS 引導的基本要求。

建立 secret 的詳細資訊可在此處獲取。

如果您想使用引導令牌,則必須使用以下標誌在 kube-apiserver 上啟用它:

--enable-bootstrap-token-auth=true

令牌認證檔案

kube-apiserver 能夠接受令牌作為身份驗證。這些令牌是任意的,但應至少包含從安全隨機數生成器(例如大多數現代 Linux 系統上的 /dev/urandom)派生的 128 位熵。您可以透過多種方式生成令牌。例如:

head -c 16 /dev/urandom | od -An -t x | tr -d ' '

這將生成看起來像 02b50b05283e98dd0fd71db496ef01e8 的令牌。

令牌檔案應如下例所示,其中前三個值可以是任意的,引用的組名應如圖所示:

02b50b05283e98dd0fd71db496ef01e8,kubelet-bootstrap,10001,"system:bootstrappers"

--token-auth-file=FILENAME 標誌新增到 kube-apiserver 命令(可能在您的 systemd 單元檔案中)以啟用令牌檔案。有關更多詳細資訊,請參閱此處的文件。

授權 kubelet 建立 CSR

既然引導節點已作為 system:bootstrappers 組的一部分進行身份驗證,它還需要被授權建立證書籤名請求 (CSR) 並在完成後檢索它。幸運的是,Kubernetes 附帶了一個 ClusterRole,它精確地擁有這些(並且僅有這些)許可權:system:node-bootstrapper

為此,您只需建立一個 ClusterRoleBinding,將 system:bootstrappers 組繫結到叢集角色 system:node-bootstrapper

# enable bootstrapping nodes to create CSR
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: create-csrs-for-bootstrapping
subjects:
- kind: Group
  name: system:bootstrappers
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: system:node-bootstrapper
  apiGroup: rbac.authorization.k8s.io

kube-controller-manager 配置

雖然 apiserver 接收來自 kubelet 的證書請求並驗證這些請求,但 controller-manager 負責頒發實際的簽名證書。

controller-manager 透過證書頒發控制迴圈執行此功能。這採用 cfssl 本地簽名者的形式,使用磁碟上的資產。目前,所有頒發的證書都具有一年有效期和一組預設的金鑰用途。

為了讓 controller-manager 簽署證書,它需要以下內容:

  • 訪問您建立和分發的“Kubernetes CA 金鑰和證書”
  • 啟用 CSR 簽名

訪問金鑰和證書

如前所述,您需要建立 Kubernetes CA 金鑰和證書,並將其分發到控制平面節點。這些將由 controller-manager 用於簽署 kubelet 證書。

由於這些簽名證書將反過來被 kubelet 用作常規 kubelet 向 kube-apiserver 進行身份驗證,因此在此階段提供給 controller-manager 的 CA 必須也受 kube-apiserver 信任以進行身份驗證。這透過標誌 --client-ca-file=FILENAME 提供給 kube-apiserver(例如,--client-ca-file=/var/lib/kubernetes/ca.pem),如 kube-apiserver 配置部分所述。

要將 Kubernetes CA 金鑰和證書提供給 kube-controller-manager,請使用以下標誌:

--cluster-signing-cert-file="/etc/path/to/kubernetes/ca/ca.crt" --cluster-signing-key-file="/etc/path/to/kubernetes/ca/ca.key"

例如

--cluster-signing-cert-file="/var/lib/kubernetes/ca.pem" --cluster-signing-key-file="/var/lib/kubernetes/ca-key.pem"

簽名證書的有效期可以透過標誌配置:

--cluster-signing-duration

批准

為了批准 CSR,您需要告訴 controller-manager 它可以接受批准它們。這是透過授予 RBAC 許可權給正確的組來完成的。

許可權分為兩組:

  • nodeclient:如果一個節點正在為節點建立新證書,那麼它還沒有證書。它使用上面列出的令牌之一進行身份驗證,因此屬於 system:bootstrappers 組。
  • selfnodeclient:如果一個節點正在續訂其證書,那麼它已經擁有一個證書(根據定義),它會不斷使用該證書作為 system:nodes 組的一部分進行身份驗證。

要使 kubelet 能夠請求並接收新證書,請建立一個 ClusterRoleBinding,將引導節點所屬的組 system:bootstrappers 繫結到授予其許可權的 ClusterRole,即 system:certificates.k8s.io:certificatesigningrequests:nodeclient

# Approve all CSRs for the group "system:bootstrappers"
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: auto-approve-csrs-for-group
subjects:
- kind: Group
  name: system:bootstrappers
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: system:certificates.k8s.io:certificatesigningrequests:nodeclient
  apiGroup: rbac.authorization.k8s.io

要使 kubelet 能夠續訂其自身的客戶端證書,請建立一個 ClusterRoleBinding,將功能齊全的節點所屬的組 system:nodes 繫結到授予其許可權的 ClusterRole,即 system:certificates.k8s.io:certificatesigningrequests:selfnodeclient

# Approve renewal CSRs for the group "system:nodes"
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: auto-approve-renewals-for-nodes
subjects:
- kind: Group
  name: system:nodes
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: system:certificates.k8s.io:certificatesigningrequests:selfnodeclient
  apiGroup: rbac.authorization.k8s.io

作為 kube-controller-manager 的一部分提供的 csrapproving 控制器預設啟用。該控制器使用 SubjectAccessReview API 來確定給定使用者是否被授權請求 CSR,然後根據授權結果進行批准。為了防止與其他審批者發生衝突,內建審批者不會明確拒絕 CSR。它只忽略未經授權的請求。該控制器還會作為垃圾回收的一部分清除過期證書。

kubelet 配置

最後,在控制平面節點正確設定並所有必要的身份驗證和授權到位後,我們可以配置 kubelet。

kubelet 需要以下配置才能進行引導:

  • 用於儲存它生成的金鑰和證書的路徑(可選,可以使用預設值)
  • 尚未存在的 kubeconfig 檔案的路徑;它將在此處放置引導配置檔案
  • 引導 kubeconfig 檔案的路徑,用於提供伺服器的 URL 和引導憑據,例如引導令牌
  • 可選:證書輪換說明

引導 kubeconfig 應該位於 kubelet 可訪問的路徑中,例如 /var/lib/kubelet/bootstrap-kubeconfig

其格式與正常的 kubeconfig 檔案相同。示例檔案可能如下所示:

apiVersion: v1
kind: Config
clusters:
- cluster:
    certificate-authority: /var/lib/kubernetes/ca.pem
    server: https://my.server.example.com:6443
  name: bootstrap
contexts:
- context:
    cluster: bootstrap
    user: kubelet-bootstrap
  name: bootstrap
current-context: bootstrap
preferences: {}
users:
- name: kubelet-bootstrap
  user:
    token: 07401b.f395accd246ae52d

需要注意的重要元素是:

  • certificate-authority:CA 檔案的路徑,用於驗證 kube-apiserver 提供的伺服器證書
  • server:kube-apiserver 的 URL
  • token:要使用的令牌

令牌的格式無關緊要,只要它與 kube-apiserver 期望的匹配即可。在上面的示例中,我們使用了引導令牌。如前所述,任何有效的身份驗證方法都可以使用,而不僅僅是令牌。

由於引導 kubeconfig 一個標準 kubeconfig,您可以使用 kubectl 生成它。要建立上面的示例檔案:

kubectl config --kubeconfig=/var/lib/kubelet/bootstrap-kubeconfig set-cluster bootstrap --server='https://my.server.example.com:6443' --certificate-authority=/var/lib/kubernetes/ca.pem
kubectl config --kubeconfig=/var/lib/kubelet/bootstrap-kubeconfig set-credentials kubelet-bootstrap --token=07401b.f395accd246ae52d
kubectl config --kubeconfig=/var/lib/kubelet/bootstrap-kubeconfig set-context bootstrap --user=kubelet-bootstrap --cluster=bootstrap
kubectl config --kubeconfig=/var/lib/kubelet/bootstrap-kubeconfig use-context bootstrap

要指示 kubelet 使用引導 kubeconfig,請使用以下 kubelet 標誌:

--bootstrap-kubeconfig="/var/lib/kubelet/bootstrap-kubeconfig" --kubeconfig="/var/lib/kubelet/kubeconfig"

當啟動 kubelet 時,如果透過 --kubeconfig 指定的檔案不存在,則使用透過 --bootstrap-kubeconfig 指定的引導 kubeconfig 從 API 伺服器請求客戶端證書。在證書請求獲得批准並由 kubelet 接收後,一個引用生成的金鑰和獲得的證書的 kubeconfig 檔案將被寫入由 --kubeconfig 指定的路徑。證書和金鑰檔案將放置在由 --cert-dir 指定的目錄中。

客戶端和服務證書

上述所有內容都與 kubelet 客戶端證書有關,特別是 kubelet 用於向 kube-apiserver 進行身份驗證的證書。

kubelet 也可以使用服務證書。kubelet 本身暴露了一個 HTTPS 端點以實現某些功能。為了保護這些,kubelet 可以執行以下操作之一:

  • 透過 --tls-private-key-file--tls-cert-file 標誌使用提供的金鑰和證書
  • 如果未提供金鑰和證書,則建立自簽名金鑰和證書
  • 透過 CSR API 從叢集伺服器請求服務證書

TLS 引導提供的客戶端證書預設只用於 client auth 簽名,因此不能用作服務證書或 server auth

但是,您可以透過證書輪換至少部分啟用其伺服器證書。

證書輪換

Kubernetes v1.8 及更高版本的 kubelet 實現了啟用其客戶端和/或服務證書輪換的功能。請注意,服務證書的輪換是測試版功能,並且需要在 kubelet 上使用 RotateKubeletServerCertificate 功能標誌(預設啟用)。

您可以配置 kubelet,使其在現有憑據過期時透過建立新的 CSR 來輪換其客戶端證書。要啟用此功能,請使用 kubelet 配置檔案rotateCertificates 欄位或向 kubelet 傳遞以下命令列引數(已棄用)

--rotate-certificates

啟用 RotateKubeletServerCertificate 會導致 kubelet 在引導其客戶端憑據後請求服務證書,輪換該證書。要啟用此行為,請使用 kubelet 配置檔案serverTLSBootstrap 欄位或向 kubelet 傳遞以下命令列引數(已棄用)

--rotate-server-certificates

其他身份驗證元件

本文件中描述的所有 TLS 引導都與 kubelet 相關。然而,其他元件可能需要直接與 kube-apiserver 通訊。值得注意的是 kube-proxy,它是 Kubernetes 節點元件的一部分,執行在每個節點上,但也可能包括其他元件,例如監控或網路。

像 kubelet 一樣,這些其他元件也需要一種向 kube-apiserver 進行身份驗證的方法。您有幾種生成這些憑據的選項:

  • 舊方法:以您在 TLS 引導之前為 kubelet 所做的方式建立和分發證書
  • DaemonSet:由於 kubelet 本身載入在每個節點上,並且足以啟動基礎服務,因此您可以將 kube-proxy 和其他特定於節點的服務作為 DaemonSet 而不是獨立程序執行在 kube-system 名稱空間中。由於它將在叢集內,您可以為其提供適當的服務帳戶和執行其活動的相應許可權。這可能是配置此類服務的最簡單方法。

kubectl 批准

CSR 可以在控制器管理器內建的審批流程之外獲得批准。

簽名控制器不會立即簽署所有證書請求。相反,它會等到它們被具有適當許可權的使用者標記為“已批准”狀態。此流程旨在允許由外部審批控制器或核心控制器管理器中實現的審批控制器處理自動批准。但是,叢集管理員也可以使用 kubectl 手動批准證書請求。管理員可以使用 kubectl get csr 列出 CSR,並使用 kubectl describe csr <name> 詳細描述一個 CSR。管理員可以使用 kubectl certificate approve <name>kubectl certificate deny <name> 批准或拒絕 CSR。

上次修改於 2023 年 10 月 06 日 太平洋標準時間下午 7:24:清理 kubelet-tls-bootstrapping.md (318ff2e797)