管理叢集中的 TLS 憑證
Kubernetes 提供 certificates.k8s.io
API,可讓您佈建由您控制的憑證授權單位 (CA) 簽署的 TLS 憑證。您的工作負載可以使用這些 CA 和憑證來建立信任。
certificates.k8s.io
API 使用類似於 ACME 草案的協定。
注意
使用certificates.k8s.io
API 建立的憑證是由專用 CA 簽署的。您可以將叢集設定為使用叢集根 CA 來達到此目的,但您永遠不應依賴此設定。請勿假設這些憑證將針對叢集根 CA 進行驗證。開始之前
您需要有一個 Kubernetes 叢集,並且必須設定 kubectl 命令列工具以與您的叢集通訊。建議在至少有兩個節點且未充當控制平面主機的叢集上執行本教學課程。如果您還沒有叢集,可以使用 minikube 建立一個叢集,或者您可以使用下列 Kubernetes playground 之一
您需要 cfssl
工具。您可以從 https://github.com/cloudflare/cfssl/releases 下載 cfssl
。
本頁中的某些步驟使用 jq
工具。如果您沒有 jq
,可以透過作業系統的軟體來源安裝,或從 https://jqlang.github.io/jq/ 取得。
信任叢集中的 TLS
從以 Pod 形式執行的應用程式信任自訂 CA 通常需要一些額外的應用程式組態。您需要將 CA 憑證組合新增至 TLS 用戶端或伺服器信任的 CA 憑證清單。例如,您可以使用 golang TLS 組態來執行此操作,方法是剖析憑證鏈,並將剖析後的憑證新增至 tls.Config
結構中的 RootCAs
欄位。
注意
即使自訂 CA 憑證可能包含在檔案系統中 (在 ConfigMap kube-root-ca.crt
中),您也不應將該憑證授權單位用於驗證內部 Kubernetes 端點以外的任何目的。內部 Kubernetes 端點的一個範例是預設命名空間中名為 kubernetes
的服務。
如果您想要為您的工作負載使用自訂憑證授權單位,您應該分別產生該 CA,並使用您的 Pod 可以存取的 ConfigMap 分發其 CA 憑證。
請求憑證
以下章節示範如何為透過 DNS 存取的 Kubernetes 服務建立 TLS 憑證。
注意
本教學課程使用 CFSSL:Cloudflare 的 PKI 和 TLS 工具組 按一下這裡 以瞭解更多資訊。建立憑證簽署請求
執行以下命令來產生私密金鑰和憑證簽署請求 (或 CSR)
cat <<EOF | cfssl genkey - | cfssljson -bare server
{
"hosts": [
"my-svc.my-namespace.svc.cluster.local",
"my-pod.my-namespace.pod.cluster.local",
"192.0.2.24",
"10.0.34.2"
],
"CN": "my-pod.my-namespace.pod.cluster.local",
"key": {
"algo": "ecdsa",
"size": 256
}
}
EOF
其中 192.0.2.24
是服務的叢集 IP,my-svc.my-namespace.svc.cluster.local
是服務的 DNS 名稱,10.0.34.2
是 Pod 的 IP,而 my-pod.my-namespace.pod.cluster.local
是 Pod 的 DNS 名稱。您應該會看到類似以下的輸出
2022/02/01 11:45:32 [INFO] generate received request
2022/02/01 11:45:32 [INFO] received CSR
2022/02/01 11:45:32 [INFO] generating key: ecdsa-256
2022/02/01 11:45:32 [INFO] encoded CSR
此命令會產生兩個檔案;它會產生 server.csr
,其中包含 PEM 編碼的 PKCS#10 憑證請求,以及 server-key.pem
,其中包含 PEM 編碼的憑證金鑰,該憑證仍待建立。
建立 CertificateSigningRequest 物件以傳送至 Kubernetes API
產生 CSR 清單 (以 YAML 格式),並將其傳送至 API 伺服器。您可以執行以下命令來執行此操作
cat <<EOF | kubectl apply -f -
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: my-svc.my-namespace
spec:
request: $(cat server.csr | base64 | tr -d '\n')
signerName: example.com/serving
usages:
- digital signature
- key encipherment
- server auth
EOF
請注意,步驟 1 中建立的 server.csr
檔案已進行 base64 編碼,並隱藏在 .spec.request
欄位中。您也正在請求一個具有「數位簽章」、「金鑰加密」和「伺服器驗證」金鑰用途的憑證,該憑證由範例 example.com/serving
簽署者簽署。必須請求特定的 signerName
。如需更多資訊,請檢視支援的簽署者名稱的文件。
CSR 現在應該可以從 API 中看到,處於 Pending 狀態。您可以透過執行以下命令來查看它
kubectl describe csr my-svc.my-namespace
Name: my-svc.my-namespace
Labels: <none>
Annotations: <none>
CreationTimestamp: Tue, 01 Feb 2022 11:49:15 -0500
Requesting User: yourname@example.com
Signer: example.com/serving
Status: Pending
Subject:
Common Name: my-pod.my-namespace.pod.cluster.local
Serial Number:
Subject Alternative Names:
DNS Names: my-pod.my-namespace.pod.cluster.local
my-svc.my-namespace.svc.cluster.local
IP Addresses: 192.0.2.24
10.0.34.2
Events: <none>
取得憑證簽署請求的核准
核准憑證簽署請求可以透過自動核准程序完成,或是由叢集管理員一次性完成。如果你有權限核准憑證請求,你可以使用 kubectl
手動執行;例如:
kubectl certificate approve my-svc.my-namespace
certificatesigningrequest.certificates.k8s.io/my-svc.my-namespace approved
現在你應該會看到以下內容
kubectl get csr
NAME AGE SIGNERNAME REQUESTOR REQUESTEDDURATION CONDITION
my-svc.my-namespace 10m example.com/serving yourname@example.com <none> Approved
這表示憑證請求已核准,正在等待請求的簽署者簽署。
簽署憑證簽署請求
接下來,你將扮演憑證簽署者的角色,簽發憑證,並將其上傳到 API。
簽署者通常會監看 CertificateSigningRequest API 中 signerName
的物件,檢查這些物件是否已核准,為這些請求簽署憑證,並使用已簽發的憑證更新 API 物件狀態。
建立憑證授權單位
你需要一個授權單位來為新的憑證提供數位簽章。
首先,執行以下命令建立簽署憑證
cat <<EOF | cfssl gencert -initca - | cfssljson -bare ca
{
"CN": "My Example Signer",
"key": {
"algo": "rsa",
"size": 2048
}
}
EOF
你應該會看到類似以下的輸出
2022/02/01 11:50:39 [INFO] generating a new CA key and certificate from CSR
2022/02/01 11:50:39 [INFO] generate received request
2022/02/01 11:50:39 [INFO] received CSR
2022/02/01 11:50:39 [INFO] generating key: rsa-2048
2022/02/01 11:50:39 [INFO] encoded CSR
2022/02/01 11:50:39 [INFO] signed certificate with serial number 263983151013686720899716354349605500797834580472
這會產生一個憑證授權單位金鑰檔案 (ca-key.pem
) 和憑證 (ca.pem
)。
簽發憑證
{
"signing": {
"default": {
"usages": [
"digital signature",
"key encipherment",
"server auth"
],
"expiry": "876000h",
"ca_constraint": {
"is_ca": false
}
}
}
}
使用 server-signing-config.json
簽署組態以及憑證授權單位金鑰檔案和憑證來簽署憑證請求
kubectl get csr my-svc.my-namespace -o jsonpath='{.spec.request}' | \
base64 --decode | \
cfssl sign -ca ca.pem -ca-key ca-key.pem -config server-signing-config.json - | \
cfssljson -bare ca-signed-server
你應該會看到類似以下的輸出
2022/02/01 11:52:26 [INFO] signed certificate with serial number 576048928624926584381415936700914530534472870337
這會產生一個已簽署的伺服器憑證檔案 ca-signed-server.pem
。
上傳已簽署的憑證
最後,將已簽署的憑證填入 API 物件的狀態中
kubectl get csr my-svc.my-namespace -o json | \
jq '.status.certificate = "'$(base64 ca-signed-server.pem | tr -d '\n')'"' | \
kubectl replace --raw /apis/certificates.k8s.io/v1/certificatesigningrequests/my-svc.my-namespace/status -f -
注意
這使用命令列工具jq
將 base64 編碼的內容填入 .status.certificate
欄位。如果你沒有 jq
,你也可以將 JSON 輸出儲存到檔案中,手動填入此欄位,然後上傳產生的檔案。一旦 CSR 獲得核准且已上傳簽署的憑證,請執行
kubectl get csr
輸出結果會類似於
NAME AGE SIGNERNAME REQUESTOR REQUESTEDDURATION CONDITION
my-svc.my-namespace 20m example.com/serving yourname@example.com <none> Approved,Issued
下載憑證並使用它
現在,作為請求使用者,你可以下載已簽發的憑證,並透過執行以下命令將其儲存到 server.crt
檔案中
kubectl get csr my-svc.my-namespace -o jsonpath='{.status.certificate}' \
| base64 --decode > server.crt
現在你可以將 server.crt
和 server-key.pem
填入 Secret 中,稍後你可以將其掛載到 Pod 中(例如,與提供 HTTPS 服務的網頁伺服器一起使用)。
kubectl create secret tls server --cert server.crt --key server-key.pem
secret/server created
最後,你可以將 ca.pem
填入 ConfigMap 中,並將其用作信任根憑證以驗證伺服器憑證
kubectl create configmap example-serving-ca --from-file ca.crt=ca.pem
configmap/example-serving-ca created
核准憑證簽署請求
Kubernetes 管理員(具有適當權限)可以使用 kubectl certificate approve
和 kubectl certificate deny
命令手動核准(或拒絕)憑證簽署請求。但是,如果你打算大量使用此 API,你可能會考慮編寫一個自動化的憑證控制器。
注意
核准 CSR 的能力決定了你的環境中誰信任誰。不應廣泛或輕易地授予核准 CSR 的能力。
在授予 approve
權限之前,你應確保自己充分理解核准者應履行的驗證要求,**以及**簽發特定憑證的後果。
無論是機器還是以上述方式使用 kubectl 的人員,*核准者*的角色都是驗證 CSR 是否滿足以下兩個要求
- CSR 的主體控制用於簽署 CSR 的私密金鑰。這解決了第三方偽裝成授權主體的威脅。在上述範例中,此步驟將驗證 Pod 是否控制用於產生 CSR 的私密金鑰。
- CSR 的主體被授權在請求的上下文中執行動作。這解決了不期望的主體加入叢集的威脅。在上述範例中,此步驟將驗證 Pod 是否被允許參與請求的服務。
只有在滿足這兩個要求的情況下,核准者才應核准 CSR,否則應拒絕 CSR。
有關憑證核准和存取控制的更多資訊,請參閱憑證簽署請求參考頁面。
設定你的叢集以提供簽署功能
此頁面假設已設定簽署者以服務憑證 API。Kubernetes 控制器管理員提供了簽署者的預設實作。若要啟用它,請將 --cluster-signing-cert-file
和 --cluster-signing-key-file
參數以及你的憑證授權單位金鑰對的路徑傳遞給控制器管理員。