管理叢集中的 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 操場中的一個
你需要 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
的 Service。
如果你想為工作負載使用自定義證書頒發機構,你應該單獨生成該 CA,並使用 Pod 可以讀取的 ConfigMap 分發其 CA 證書。
請求證書
以下部分演示如何為透過 DNS 訪問的 Kubernetes Service 建立 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
是 Service 的叢集 IP,my-svc.my-namespace.svc.cluster.local
是 Service 的 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
此命令生成兩個檔案;它生成包含 PEM 編碼的 PKCS#10 認證請求的 server.csr
和包含尚待建立的證書的 PEM 編碼金鑰的 server-key.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>
獲取已批准的 CertificateSigningRequest
證書籤名請求的批准由自動化批准過程或叢集管理員一次性完成。如果你有權批准證書請求,則可以使用 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
這意味著證書請求已獲批准,正在等待請求的簽名者對其進行簽名。
簽署 CertificateSigningRequest
接下來,你將扮演證書籤名者的角色,頒發證書並將其上傳到 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 物件的 Status 中填充已簽名的證書
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
在 .status.certificate
欄位中填充 base64 編碼的內容。如果你沒有 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 的 Web 伺服器一起使用)。
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
批准 CertificateSigningRequest
Kubernetes 管理員(具有適當許可權)可以使用 kubectl certificate approve
和 kubectl certificate deny
命令手動批准(或拒絕)CertificateSigningRequest。但是,如果你打算大量使用此 API,你可能需要考慮編寫一個自動化證書控制器。
注意
批准 CSR 的能力決定了你的環境中誰信任誰。不應廣泛或輕易地授予批准 CSR 的能力。
在授予 approve
許可權之前,你應該確保你明確理解批准者應承擔的驗證要求以及頒發特定證書的後果。
無論是機器還是像上面那樣使用 kubectl 的人,**批准者** 的職責是驗證 CSR 是否滿足兩個要求
- CSR 的主題控制用於簽署 CSR 的私鑰。這解決了第三方冒充授權主題的威脅。在上面的例子中,這一步將驗證 Pod 控制用於生成 CSR 的私鑰。
- CSR 的主題被授權在請求的上下文中操作。這解決了不希望的主題加入叢集的威脅。在上面的例子中,這一步將驗證 Pod 是否被允許參與請求的服務。
當且僅當滿足這兩個要求時,批准者才應批准 CSR,否則應拒絕 CSR。
有關證書批准和訪問控制的更多資訊,請閱讀證書籤名請求參考頁面。
配置你的叢集以提供簽名
此頁面假設已設定簽名者來提供證書 API。Kubernetes 控制器管理器提供了簽名者的預設實現。要啟用它,請將 --cluster-signing-cert-file
和 --cluster-signing-key-file
引數以及證書頒發機構金鑰對的路徑傳遞給控制器管理器。