Kubernetes 管理集群中的TLS認(rèn)證

2022-06-17 11:24 更新

管理集群中的 TLS 認(rèn)證

Kubernetes 提供 ?certificates.k8s.io? API,可讓你配置由你控制的證書頒發(fā)機(jī)構(gòu)(CA) 簽名的 TLS 證書。 你的工作負(fù)載可以使用這些 CA 和證書來建立信任。

?certificates.k8s.io? API使用的協(xié)議類似于 ACME 草案。

說明:
使用 ?certificates.k8s.io? API 創(chuàng)建的證書由指定 CA 頒發(fā)。 將集群配置為使用集群根目錄 CA 可以達(dá)到這個(gè)目的,但是你永遠(yuǎn)不要依賴這一假定。 不要以為這些證書將針對(duì)群根目錄 CA 進(jìn)行驗(yàn)證。

在開始之前

你必須擁有一個(gè) Kubernetes 的集群,同時(shí)你的 Kubernetes 集群必須帶有 kubectl 命令行工具。 建議在至少有兩個(gè)節(jié)點(diǎn)的集群上運(yùn)行本教程,且這些節(jié)點(diǎn)不作為控制平面主機(jī)。 如果你還沒有集群,你可以通過 Minikube 構(gòu)建一個(gè)你自己的集群,或者你可以使用下面任意一個(gè) Kubernetes 工具構(gòu)建:

你需要 ?cfssl ?工具。 你可以從 https://github.com/cloudflare/cfssl/releases 下載 ?cfssl?。

本文中某些步驟使用 ?jq ?工具。如果你沒有 ?jq?,你可以通過操作系統(tǒng)的軟件源安裝, 或者從 https://stedolan.github.io/jq/ 獲取。

集群中的 TLS 信任

信任 Pod 中運(yùn)行的應(yīng)用程序所提供的自定義 CA 通常需要一些額外的應(yīng)用程序配置。 你需要將 CA 證書包添加到 TLS 客戶端或服務(wù)器信任的 CA 證書列表中。 例如,你可以使用 Golang TLS 配置通過解析證書鏈并將解析的證書添加到 ?tls.Config? 結(jié)構(gòu)中的 ?RootCAs ?字段中。

說明:
即使自定義 CA 證書可能包含在文件系統(tǒng)中(在 ConfigMap ?kube-root-ca.crt? 中), 除了驗(yàn)證內(nèi)部 Kubernetes 端點(diǎn)之外,你不應(yīng)將該證書頒發(fā)機(jī)構(gòu)用于任何目的。 內(nèi)部 Kubernetes 端點(diǎn)的一個(gè)示例是默認(rèn)命名空間中名為 ?kubernetes ?的服務(wù)。
如果你想為你的工作負(fù)載使用自定義證書頒發(fā)機(jī)構(gòu),你應(yīng)該單獨(dú)生成該 CA, 并使用你的 Pod 有讀權(quán)限的 ConfigMap 分發(fā)該 CA 證書。

請(qǐng)求證書

以下部分演示如何為通過 DNS 訪問的 Kubernetes 服務(wù)創(chuàng)建 TLS 證書。

說明: 本教程使用 CFSSL:Cloudflare's PKI 和 TLS 工具包 點(diǎn)擊此處了解更多信息。

創(chuàng)建證書簽名請(qǐng)求 

通過運(yùn)行以下命令生成私鑰和證書簽名請(qǐng)求(或 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? 是服務(wù)的集群 IP,?my-svc.my-namespace.svc.cluster.local? 是服務(wù)的 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

此命令生成兩個(gè)文件;它生成包含 PEM 編碼 PKCS#10 證書請(qǐng)求的 ?server.csr?, 以及 PEM 編碼密鑰的 ?server-key.pem?,用于待生成的證書。

創(chuàng)建證書簽名請(qǐng)求(CSR)對(duì)象發(fā)送到 Kubernetes API

使用以下命令創(chuàng)建 CSR YAML 文件,并發(fā)送到 API 服務(wù)器:

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

請(qǐng)注意,在步驟 1 中創(chuàng)建的 ?server.csr? 文件是 base64 編碼并存儲(chǔ)在 ?.spec.request? 字段中的。你還要求提供 “digital signature(數(shù)字簽名)”, “密鑰加密(key encipherment)” 和 “服務(wù)器身份驗(yàn)證(server auth)” 密鑰用途, 由 ?example.com/serving? 示例簽名程序簽名的證書。 你也可以要求使用特定的 ?signerName?。

在 API server 中可以看到這些 CSR 處于 Pending 狀態(tài)。執(zhí)行下面的命令你將可以看到:

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>

批準(zhǔn)證書簽名請(qǐng)求(CSR) 

證書簽名請(qǐng)求 的批準(zhǔn)或者是通過自動(dòng)批準(zhǔn)過程完成的,或由集群管理員一次性完成。 如果你被授權(quán)批準(zhǔn)證書請(qǐng)求,你可以使用 ?kubectl ?來手動(dòng)完成此操作;例如:

kubectl certificate approve my-svc.my-namespace
certificatesigningrequest.certificates.k8s.io/my-svc.my-namespace approved

你現(xiàn)在應(yīng)該能看到如下輸出:

kubectl get csr
NAME                  AGE   SIGNERNAME            REQUESTOR              REQUESTEDDURATION   CONDITION
my-svc.my-namespace   10m   example.com/serving   yourname@example.com   <none>              Approved

這意味著證書請(qǐng)求已被批準(zhǔn),并正在等待請(qǐng)求的簽名者對(duì)其簽名。

簽名證書簽名請(qǐng)求(CSR) 

接下來,你將扮演證書簽署者的角色,頒發(fā)證書并將其上傳到 API 服務(wù)器。

簽名者通常會(huì)使用其 ?signerName ?查看對(duì)象的 CertificateSigningRequest API, 檢查它們是否已被批準(zhǔn),為這些請(qǐng)求簽署證書,并使用已頒發(fā)的證書更新 API 對(duì)象狀態(tài)。

創(chuàng)建證書頒發(fā)機(jī)構(gòu) 

你需要授權(quán)在新證書上提供數(shù)字簽名。

首先,通過運(yùn)行以下命令創(chuàng)建簽名證書:

cat <<EOF | cfssl gencert -initca - | cfssljson -bare ca
{
  "CN": "My Example Signer",
  "key": {
    "algo": "rsa",
    "size": 2048
  }
}
EOF

你應(yīng)該看到類似于以下的輸出:

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

這會(huì)產(chǎn)生一個(gè)證書頒發(fā)機(jī)構(gòu)密鑰文件(?ca-key.pem?)和證書(?ca.pem?)。

頒發(fā)證書

{
    "signing": {
        "default": {
            "usages": [
                "digital signature",
                "key encipherment",
                "server auth"
            ],
            "expiry": "876000h",
            "ca_constraint": {
                "is_ca": false
            }
        }
    }
}

使用 ?server-signing-config.json? 簽名配置、證書頒發(fā)機(jī)構(gòu)密鑰文件和證書來簽署證書請(qǐng)求:

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

你應(yīng)該看到類似于以下的輸出:

2022/02/01 11:52:26 [INFO] signed certificate with serial number 576048928624926584381415936700914530534472870337

這會(huì)生成一個(gè)簽名的服務(wù)證書文件,?ca-signed-server.pem?。

上傳簽名證書

最后,在 API 對(duì)象的狀態(tài)中填充簽名證書:

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 編碼的內(nèi)容。 如果你沒有 ?jq ?工具,你還可以將 JSON 輸出保存到文件中,手動(dòng)填充此字段,然后上傳結(jié)果文件。

批準(zhǔn) CSR 并上傳簽名證書后,運(yùn)行:

kubectl get csr

輸入類似于:

NAME                  AGE   SIGNERNAME            REQUESTOR              REQUESTEDDURATION   CONDITION
my-svc.my-namespace   20m   example.com/serving   yourname@example.com   <none>              Approved,Issued

下載證書并使用它

現(xiàn)在,作為請(qǐng)求用戶,你可以通過運(yùn)行以下命令下載頒發(fā)的證書并將其保存到 ?server.crt? 文件中:

CSR 被簽署并獲得批準(zhǔn)后,你應(yīng)該看到以下內(nèi)容:

kubectl get csr my-svc.my-namespace -o jsonpath='{.status.certificate}' \
    | base64 --decode > server.crt

現(xiàn)在你可以將 ?server.crt? 和 ?server-key.pem? 填充到 Secret 中, 稍后你可以將其掛載到 Pod 中(例如,用于提供 HTTPS 的網(wǎng)絡(luò)服務(wù)器)。

kubectl create secret tls server --cert server.crt --key server-key.pem
secret/server created

最后,你可以將 ?ca.pem? 填充到 ConfigMap 并將其用作信任根來驗(yàn)證服務(wù)證書:

kubectl create configmap example-serving-ca --from-file ca.crt=ca.pem
configmap/example-serving-ca created

批準(zhǔn)證書簽名請(qǐng)求(CSR) 

Kubernetes 管理員(具有適當(dāng)權(quán)限)可以使用 ?kubectl certificate approve? 和 ?kubectl certificate deny? 命令手動(dòng)批準(zhǔn)(或拒絕)證書簽名請(qǐng)求(CSR)。 但是,如果你打算大量使用此 API,則可以考慮編寫自動(dòng)化的證書控制器。

注意:
批準(zhǔn)證書 CSR 的能力決定了在你的環(huán)境中誰信任誰。 不應(yīng)廣泛或輕率地授予批準(zhǔn) CSR 的能力。
在授予 ?approve ?權(quán)限之前,你應(yīng)該確保自己充分了解批準(zhǔn)人的驗(yàn)證要求和頒發(fā)特定證書的后果。

無論上述機(jī)器或人使用 kubectl,“批準(zhǔn)者”的作用是驗(yàn)證 CSR 滿足如下兩個(gè)要求:

  1. CSR 的 subject 控制用于簽署 CSR 的私鑰。這解決了偽裝成授權(quán)主體的第三方的威脅。 在上述示例中,此步驟將驗(yàn)證該 Pod 控制了用于生成 CSR 的私鑰。
  2. CSR 的 subject 被授權(quán)在請(qǐng)求的上下文中執(zhí)行。 這點(diǎn)用于處理不期望的主體被加入集群的威脅。 在上述示例中,此步驟將是驗(yàn)證該 Pod 是否被允許加入到所請(qǐng)求的服務(wù)中。

當(dāng)且僅當(dāng)滿足這兩個(gè)要求時(shí),審批者應(yīng)該批準(zhǔn) CSR,否則拒絕 CSR。

給集群管理員的一個(gè)建議

本頁面假設(shè)已經(jīng)為 certificates API 配置了簽名者。 Kubernetes 控制器管理器提供了一個(gè)簽名者的默認(rèn)實(shí)現(xiàn)。要啟用它,請(qǐng)為控制器管理器設(shè)置 ?--cluster-signing-cert-file? 和 ?--cluster-signing-key-file? 參數(shù), 使之取值為你的證書機(jī)構(gòu)的密鑰對(duì)的路徑。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)