TLS 啟動引導程序
在 Kubernetes 叢集中,工作節點上的元件 - kubelet 和 kube-proxy - 需要與 Kubernetes 控制平面元件(特別是 kube-apiserver)進行通訊。為了確保通訊的私密性、不受干擾,並確保叢集的每個元件都與另一個受信任的元件通話,我們強烈建議在節點上使用用戶端 TLS 憑證。
啟動這些元件的正常程序,特別是需要憑證的工作節點,以便它們可以安全地與 kube-apiserver 通訊,這可能是一個具有挑戰性的過程,因為它通常超出 Kubernetes 的範圍,並且需要大量額外的工作。反過來,這可能會使初始化或擴展叢集變得具有挑戰性。
為了簡化此過程,從 1.4 版本開始,Kubernetes 引入了憑證請求和簽署 API。提案可以在這裡找到。
本文檔描述了節點初始化過程、如何為 kubelet 設定 TLS 用戶端憑證啟動引導程序,以及其運作方式。
初始化過程
當工作節點啟動時,kubelet 會執行以下操作
- 尋找其
kubeconfig
檔案 - 從
kubeconfig
檔案中檢索 API 伺服器的 URL 和憑證,通常是 TLS 金鑰和簽署的憑證 - 嘗試使用憑證與 API 伺服器通訊。
假設 kube-apiserver 成功驗證了 kubelet 的憑證,它將把 kubelet 視為有效的節點,並開始將 Pod 指派給它。
請注意,上述過程取決於
- 本機主機上的
kubeconfig
中存在金鑰和憑證 - 憑證已由 kube-apiserver 信任的憑證授權機構 (CA) 簽署
以下所有事項均由設定和管理叢集的人員負責
- 建立 CA 金鑰和憑證
- 將 CA 憑證分發到控制平面節點,kube-apiserver 在這些節點上執行
- 為每個 kubelet 建立金鑰和憑證;強烈建議為每個 kubelet 提供唯一的金鑰和憑證,以及唯一的 CN
- 使用 CA 金鑰簽署 kubelet 憑證
- 將 kubelet 金鑰和簽署的憑證分發到執行 kubelet 的特定節點上
本文檔中描述的 TLS 啟動引導程序旨在簡化,以及部分甚至完全自動化步驟 3 之後的步驟,因為這些步驟是初始化或擴展叢集時最常見的步驟。
啟動引導初始化
在啟動引導初始化過程中,會發生以下情況
- kubelet 開始
- kubelet 看到它沒有
kubeconfig
檔案 - kubelet 搜尋並找到
bootstrap-kubeconfig
檔案 - kubelet 讀取其啟動引導檔案,檢索 API 伺服器的 URL 和有限用途的「權杖」
- kubelet 連接到 API 伺服器,使用權杖進行驗證
- kubelet 現在具有有限的憑證,可以建立和檢索憑證簽署請求 (CSR)
- kubelet 為自己建立 CSR,並將 signerName 設定為
kubernetes.io/kube-apiserver-client-kubelet
- CSR 以兩種方式之一核准
- 如果已設定,kube-controller-manager 會自動核准 CSR
- 如果已設定,外部程序(可能是人員)使用 Kubernetes API 或透過
kubectl
核准 CSR
- 為 kubelet 建立憑證
- 憑證已發行給 kubelet
- kubelet 檢索憑證
- kubelet 使用金鑰和簽署的憑證建立正確的
kubeconfig
- kubelet 開始正常運作
- 選用:如果已設定,kubelet 會在憑證接近到期時自動請求續約
- 續約的憑證會根據組態自動或手動核准和發行。
本文檔的其餘部分描述了設定 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 的初始啟動引導憑證,但建議使用以下兩種驗證器,以便於佈建。
使用 Bootstrap 權杖是一種更簡單且更易於管理的方法來驗證 kubelet,並且在啟動 kube-apiserver 時不需要任何額外的旗標。
無論您選擇哪種方法,要求是 kubelet 能夠以具有以下權限的使用者身分進行驗證
- 建立和檢索 CSR
- 如果啟用自動核准,則自動核准請求節點用戶端憑證。
使用 Bootstrap 權杖進行驗證的 kubelet 會以 system:bootstrappers
群組中的使用者身分進行驗證,這是要使用的標準方法。
隨著此功能的成熟,您應確保權杖已繫結至基於角色的存取控制 (RBAC) 策略,該策略嚴格限制與憑證佈建相關的用戶端請求(使用啟動引導權杖)。在 RBAC 就位的情況下,將權杖限定於群組可提供極大的彈性。例如,您可以在完成節點佈建後停用特定啟動引導群組的存取權。
Bootstrap 權杖
Bootstrap 權杖在此處詳細描述。這些權杖以密鑰形式儲存在 Kubernetes 叢集中,然後發行給個別 kubelet。您可以為整個叢集使用單一權杖,或為每個工作節點發行一個權杖。
該過程分為兩個部分
- 使用權杖 ID、密鑰和範圍建立 Kubernetes 密鑰。
- 將權杖發行給 kubelet
從 kubelet 的角度來看,所有的權杖都一樣,沒有特別的意義。然而,從 kube-apiserver 的角度來看,啟動引導權杖 (bootstrap token) 是特別的。由於其 type
、namespace
和 name
,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 用於向 kube-apiserver 驗證身分,因此重要的是,在此階段提供給 controller-manager 的 CA 也必須受到 kube-apiserver 的信任以進行身分驗證。這是透過 --client-ca-file=FILENAME
標記 (例如,--client-ca-file=/var/lib/kubernetes/ca.pem
) 提供給 kube-apiserver 的,如 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
csrapproving
控制器作為 kube-controller-manager 的一部分提供,並且預設為啟用。控制器使用 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 的 URLtoken
:要使用的權杖
權杖的格式並不重要,只要它符合 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 啟動引導提供的用戶端憑證僅針對 用戶端驗證
進行簽署,因此不能用作伺服器憑證或 伺服器驗證
。
但是,您可以透過憑證輪換至少部分地啟用其伺服器憑證。
憑證輪換
Kubernetes v1.8 及更高版本的 kubelet 實作了啟用其用戶端和/或伺服器憑證輪換的功能。請注意,伺服器憑證輪換是一項 beta 功能,需要在 kubelet 上啟用 RotateKubeletServerCertificate
功能閘道 (預設為啟用)。
您可以透過在現有憑證到期時建立新的 CSR 來設定 kubelet 輪換其用戶端憑證。若要啟用此功能,請使用 kubelet 設定檔 的 rotateCertificates
欄位,或將以下命令列引數傳遞給 kubelet (已棄用)
--rotate-certificates
啟用 RotateKubeletServerCertificate
會導致 kubelet 在啟動引導其用戶端憑證後請求伺服器憑證,並輪換該憑證。若要啟用此行為,請使用 kubelet 設定檔 的 serverTLSBootstrap
欄位,或將以下命令列引數傳遞給 kubelet (已棄用)
--rotate-server-certificates
注意
核心 Kubernetes 中實作的 CSR 核准控制器基於 安全原因,不核准節點伺服器憑證。若要使用 RotateKubeletServerCertificate
,運算子需要執行自訂核准控制器,或手動核准伺服器憑證請求。
kubelet 伺服器憑證的特定部署核准程序通常應僅核准符合以下條件的 CSR
- 由節點請求 (確保
spec.username
欄位的格式為system:node:<nodeName>
且spec.groups
包含system:nodes
) - 請求用於伺服器憑證的用法 (確保
spec.usages
包含server auth
,可選地包含digital signature
和key encipherment
,並且不包含其他用法) - 只有屬於請求節點的 IP 和 DNS subjectAltNames,且沒有 URI 和 Email subjectAltNames (剖析
spec.request
中的 x509 憑證簽署請求以驗證subjectAltNames
)
其他身分驗證元件
本文檔中描述的所有 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。