管理叢集中的 TLS 憑證

Kubernetes 提供 certificates.k8s.io API,可讓您佈建由您控制的憑證授權單位 (CA) 簽署的 TLS 憑證。您的工作負載可以使用這些 CA 和憑證來建立信任。

certificates.k8s.io API 使用類似於 ACME 草案的協定。

開始之前

您需要有一個 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 欄位。

請求憑證

以下章節示範如何為透過 DNS 存取的 Kubernetes 服務建立 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 -

一旦 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.crtserver-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 approvekubectl certificate deny 命令手動核准(或拒絕)憑證簽署請求。但是,如果你打算大量使用此 API,你可能會考慮編寫一個自動化的憑證控制器。

無論是機器還是以上述方式使用 kubectl 的人員,*核准者*的角色都是驗證 CSR 是否滿足以下兩個要求

  1. CSR 的主體控制用於簽署 CSR 的私密金鑰。這解決了第三方偽裝成授權主體的威脅。在上述範例中,此步驟將驗證 Pod 是否控制用於產生 CSR 的私密金鑰。
  2. CSR 的主體被授權在請求的上下文中執行動作。這解決了不期望的主體加入叢集的威脅。在上述範例中,此步驟將驗證 Pod 是否被允許參與請求的服務。

只有在滿足這兩個要求的情況下,核准者才應核准 CSR,否則應拒絕 CSR。

有關憑證核准和存取控制的更多資訊,請參閱憑證簽署請求參考頁面。

設定你的叢集以提供簽署功能

此頁面假設已設定簽署者以服務憑證 API。Kubernetes 控制器管理員提供了簽署者的預設實作。若要啟用它,請將 --cluster-signing-cert-file--cluster-signing-key-file 參數以及你的憑證授權單位金鑰對的路徑傳遞給控制器管理員。

上次修改時間:2023 年 10 月 2 日 晚上 11:58 PST:更新 jq 連結 (e822502654)