trust-manager
trust-manager 是在 Kubernetes 和 OpenShift 叢集中管理信任套件的最簡單方法。
它協調受信任的 X.509 憑證套件,這些憑證主要用於在 TLS 握手期間驗證憑證,但也可以用於其他情況。
概述
trust-manager 是一個小型的 Kubernetes 運算子,旨在幫助減少在叢集中管理 TLS 信任套件的開銷。
它新增了 Bundle
自訂 Kubernetes 資源 (CRD),該資源可以從各種來源讀取輸入,並將產生的憑證合併到一個可供應用程式使用的套件中。
trust-manager 確保快速且容易地保持您的受信任憑證是最新的,並使叢集管理員能夠輕鬆地自動提供安全的套件,而無需擔心重建容器來更新信任儲存。
它旨在與 cert-manager 相輔相成,並且在從 cert-manager Issuer
或 ClusterIssuer
使用 CA 憑證時效果很好,但如果需要,可以完全獨立於 cert-manager 使用。
安裝
請參閱安裝指南以獲取有關如何安裝 trust-manager 的說明。
用法
trust-manager 的設計非常簡單,僅新增了一個 Kubernetes CustomResourceDefintion
:Bundle
。
Bundle
代表一組應在叢集中分發的 X.509 憑證。
所有 Bundle
都是叢集範圍的。
Bundle
包含一個 sources
列表,trust-manager 將從這些來源組裝最終套件,以及一個 target
,用於描述如何以及在何處寫入結果套件。
一個範例 Bundle
可能如下所示
apiVersion: trust.cert-manager.io/v1alpha1kind: Bundlemetadata:name: my-org.com # The bundle name will also be used for the targetspec:sources:# Include a bundle of publicly trusted certificates which can be# used to validate most TLS certificates on the internet, such as# those issued by Let's Encrypt, Google, Amazon and others.- useDefaultCAs: true# A Secret in the "trust" namespace; see "Trust Namespace" below for further details- secret:name: "my-db-tls"key: "ca.crt"# Here is another Secret source, but this time using a label selector instead of a Secret's name.- secret:selector:matchLabels:fruit: applekey: "ca.crt"# A ConfigMap in the "trust" namespace; see "Trust Namespace" below for further details- configMap:name: "my-org.net"key: "root-certs.pem"# Here is another ConfigMap source, but this time using a label selector instead of a ConfigMap's name.- configMap:selector:matchLabels:fruit: applekey: "ca.crt"# A manually specified string- inLine: |-----BEGIN CERTIFICATE-----MIIC5zCCAc+gAwIBAgIBADANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQDEwprdWJl....0V3NCaQrXoh+3xrXgX/vMdijYLUSo/YPEWmo-----END CERTIFICATE-----target:# Sync the bundle to a ConfigMap called `my-org.com` in every namespace which# has the label "linkerd.io/inject=enabled"# All ConfigMaps will include a PEM-formatted bundle, here named "root-certs.pem"# and in this case we also request binary formatted bundles in JKS and PKCS#12 formats,# here named "bundle.jks" and "bundle.p12".configMap:key: "root-certs.pem"additionalFormats:jks:key: "bundle.jks"pkcs12:key: "bundle.p12"namespaceSelector:matchLabels:linkerd.io/inject: "enabled"
Bundle
資源目前支援多種來源類型
configMap
- trust-manager 名稱空間中的ConfigMap
資源secret
- trust-manager 名稱空間中的Secret
資源inLine
- 手動指定的字串,其中包含至少一個憑證useDefaultCAs
- 通常,一組公開信任的憑證
ConfigMap
是預設目標類型,但從 v0.7.0 開始,trust-manager 也支援 Secret
資源作為目標。
必須在 trust-manager 控制器中明確啟用對 Secret
目標的支援;請參閱下方的「啟用 Secret 目標」瞭解詳細資訊。
ConfigMap
和 Secret
也都支援指定標籤選擇器以一次選取多個資源,這在僅在執行時才知道 ConfigMap
或 Secret
名稱的動態環境中很有用。新增來源時,無論是 ConfigMap
還是 Secret
類型,name
和 selector
欄位是互斥的:**必須**設定其中一個,但不能同時設定兩個。
所有來源和目標選項都記錄在 trust-manager API 參考文件中。
目標
所有 Bundle
目標都寫入名稱與 Bundle
名稱相同的 ConfigMap
(和/或 Secret
) 中,並且每個目標都包含一個 PEM 格式的套件。
使用者也可以選擇性地將 JKS/PKCS#12 格式的二進制信任儲存區寫入目標。JKS 自 v0.5.0 開始支援,而 PKCS#12 自 v0.7.0 開始支援。
使用 JKS 和 PKCS#12 信任儲存區的應用程式通常需要為了舊版原因而設定密碼。這些密碼通常是安全性劇場 - 它們要么使用非常弱的加密,要么密碼以純文字形式提供在它們加密的檔案旁邊,這使得它們加密的意義消失。
信任套件不包含私鑰,因此對於大多數使用案例而言,加密它們不會有任何安全性優勢。因此,預設情況下,信任儲存區的密碼對於 JKS 設定為 changeit
,而對於 PKCS#12 設定為 ""
(空字串或「無密碼」)。
最近的版本允許您透過設定套件 YAML 檔案 spec.target.additionalFormats.jks.password
和 spec.target.additionalFormats.pkcs12.password
來變更該密碼。
較舊的版本具有硬式編碼的目前預設值,並且無法變更。如需更多資訊,請閱讀為什麼密碼沒有幫助。
名稱空間選擇器
目標的 namespaceSelector
用於限制您的 Bundle
的目標應同步到哪些名稱空間。
namespaceSelector
支援 matchLabels
欄位。
請參閱Kubernetes 文件以瞭解有關如何設定標籤選擇器的更多資訊。
如果 namespaceSelector
為空,則 Bundle
的目標將會同步到所有命名空間。
⚠️ trust-manager 未來的更新將會變更此行為,使空的命名空間選擇器預設只會同步到 trust-manager 命名空間。
快速開始範例
讓我們開始建立我們自己的 Bundle
的範例!
首先,我們將建立一個示範叢集
git clone https://github.com/cert-manager/trust-manager trust-managercd trust-managermake demo
一旦我們有一個正在運行的叢集,我們就可以使用 trust-manager 啟動時設定的預設 CA 來建立一個 Bundle
。由於我們是使用 Helm 安裝 trust-manager,我們的預設 CA 套件包含來自 Debian 容器的公開信任憑證。
kubectl --kubeconfig ./bin/kubeconfig.yaml apply -f - <<EOFapiVersion: trust.cert-manager.io/v1alpha1kind: Bundlemetadata:name: example-bundlespec:sources:- useDefaultCAs: truetarget:configMap:key: "trust-bundle.pem"EOF
這很簡單!現在讓我們檢查一切是否同步正常,並且我們的 ConfigMap
是否已寫入
kubectl --kubeconfig ./bin/kubeconfig.yaml get bundle example-bundle | lesskubectl --kubeconfig ./bin/kubeconfig.yaml get configmap example-bundle -o "jsonpath={.data['trust-bundle\.pem']}" | less
太棒了 - 我們有一個信任捆綁包。我們可以立即將其用於我們的容器,但讓我們更進一步,建立一個虛擬「組織 CA」,我們希望將其包含在我們的 Bundle
中。
我們將使用 cert-manager 產生我們的虛擬組織憑證
kubectl --kubeconfig ./bin/kubeconfig.yaml apply -f - <<EOFapiVersion: cert-manager.io/v1kind: ClusterIssuermetadata:name: trust-manager-selfsigned-issuerspec:selfSigned: {}---apiVersion: cert-manager.io/v1kind: Certificatemetadata:name: trust-manager-example-canamespace: cert-managerspec:isCA: truecommonName: trust-manager-example-casecretName: trust-manager-example-ca-secretprivateKey:algorithm: ECDSAsize: 256issuerRef:name: trust-manager-selfsigned-issuerkind: ClusterIssuergroup: cert-manager.ioEOF
現在讓我們檢查 cert-manager 為我們建立的 Secret
kubectl --kubeconfig ./bin/kubeconfig.yaml get -n cert-manager secret trust-manager-example-ca-secret -o"jsonpath={.data['tls\.crt']}" | base64 -d# tls.crt will contain a PEM certificate, starting with -----BEGIN CERTIFICATE-----
🤔 想知道為什麼我們使用
tls.crt
而不是ca.crt
嗎?詳情請參閱下方。
最後,我們將更新我們的 Bundle
以包含我們新的私有 CA
kubectl --kubeconfig ./bin/kubeconfig.yaml apply -f - <<EOFapiVersion: trust.cert-manager.io/v1alpha1kind: Bundlemetadata:name: example-bundlespec:sources:- useDefaultCAs: true- secret:name: "trust-manager-example-ca-secret"key: "tls.crt"target:configMap:key: "trust-bundle.pem"EOF
我們完成了!example-bundle
ConfigMap
應該已經更新了。
如果您再次檢查 ConfigMap
,您在清單中看到的最後一個憑證應該是我們新的虛擬 CA。
安全地維護 trust-manager 安裝
如果您在任何 Bundle
資源上選擇 useDefaultCAs
來源,請務必保持您的預設 CA 套件映像檔為最新狀態。否則,就相當於在 Debian 容器中安裝公開信任捆綁包時,未能執行 apt-get upgrade ca-certificates
。
trust-manager 的設計方式是,任何版本的任何預設 CA 套件都應與任何支援預設 CA 的 trust-manager 版本(v0.4.0
及更高版本)搭配使用。升級不應對 trust-manager 的穩定性造成風險。
如果您使用官方 cert-manager 提供的 Debian CA 套件(預設),您應該檢查您擁有的版本,並與最新的套件版本進行比較。
版本可以使用 Helm 圖表上的 .defaultPackageImage.tag
值進行設定,並且該版本也會寫入到任何使用預設 CA 套件的同步 Bundle 資源上的 status
欄位。
使用 Helm 升級預設 CA 套件
假設我們想要將預設 CA 套件就地升級到標籤版本 XYZ
- 而不升級 trust-manager。
我們假設 Helm 版本名為「trust-manager」,並且我們已將其安裝到 cert-manager
命名空間中。
⚠️ 此升級過程假設它是唯一正在執行的項目。如果另一個使用者或程序在您執行此過程時變更了 Helm 值,您可能會覆寫他們的工作。
首先,我們將傾印我們目前的 Helm 值,以免遺失它們
helm get values -n cert-manager trust-manager -oyaml > values.yaml
接下來,如果 defaultPackageImage.tag
已在 values.yaml
中設定,請更新它。否則,請新增它。您可以在 quay.io
上找到可用的標籤。
# values.yaml...defaultPackageImage:tag: XYZ
這些預設套件映像檔標籤的版本直接來自 Debian 中 ca-certificates
套件的版本。
最後,套用回變更,請務必手動指定已安裝的 trust-manager 版本,以避免在更新預設 CA 套件的同時也更新 trust-manager 控制器
# Get the currently installed version. You could do this manually if you find that easier.TRUST_MANAGER_VER=$(helm list --filter "^trust-manager$" -n cert-manager -ojson | jq -r ".[0].app_version")# Check the version makes senseecho $TRUST_MANAGER_VER# Run the upgradehelm upgrade -f values.yaml -n cert-manager trust-manager jetstack/trust-manager --version $TRUST_MANAGER_VER
如果使用了不正確的標籤,您的部署將會失敗,而且您可能需要使用 helm rollback
返回到可運作的狀態。
為生產環境做準備
TLS 可能很複雜,而且有很多濫用 TLS 憑證的方法。
以下是在生產環境中運行 trust-manager 之前需要注意的一些潛在陷阱。
如果您打算在生產環境中運行 trust-manager,而且您使用的不只是預設 CA 套件,我們強烈建議您閱讀並了解本節。它可以讓您避免稍後發生中斷。
ℹ️ 這些陷阱並非 trust-manager 所特有,您可能會在使用任何管理 TLS 信任的方法時遇到任何陷阱!
捆綁中繼憑證
如果您曾經使用過 Let's Encrypt 用戶端,例如 Certbot,您可能會看到它產生了數個憑證檔案,例如 cert.pem
、chain.pem
和 fullchain.pem
。
提供這些各種檔案是為了支援各種不同的應用程式,這些應用程式可能需要憑證和鏈單獨提供。對於大多數使用者和應用程式而言,fullchain.pem
是唯一正確的選擇。
不幸的是,這些檔案的存在有一個不幸的副作用,那就是人們有時會假設 cert.pem
是正確的選擇,即使 fullchain.pem
才是正確的選擇。這表示在使用憑證時,不會傳送鏈中的其餘部分。
通常,此問題的一個快速修復方法是讓用戶端將鏈新增到其信任存放區中,這似乎可以在短期內修正憑證錯誤。這種「修復」很容易在某處作為其他人可以遵循的解決方案被嵌入。
這種「修復」很危險;這表示在必須更新所有包含該中繼憑證的信任存放區之前,無法安全地輪換中繼憑證。
在這種情況下,中繼憑證會成為事實上的根憑證,這完全破壞了最初使用中繼憑證的目的。
除非您完全確定應該包含中繼憑證,否則請盡可能避免在任何信任存放區中使用中繼憑證。一個可能是可以的情況的範例是交叉簽名,這在一般情況下不太可能需要。
最好是將根憑證複製到新的 ConfigMap
中,並將其用作來源,而不是信任中繼憑證。
cert-manager 整合:ca.crt
與 tls.crt
如果您將 trust-manager 指向包含 cert-manager 發行憑證的 Secret
,您會看到兩個相關的欄位:ca.crt
和 tls.crt
。(我們忽略 tls.key
- trust-manager 絕對不需要存取它)
這會產生一個明顯的問題:在 ca.crt
和 tls.crt
之間,我應該將哪個用於 trust-manager?
不幸的是,一般情況下無法判斷哪個欄位是正確使用的,但我們可以提供一些指引。
tls.crt
通常會包含多個憑證,這些憑證可能並非全部都是簽發者,並且其中一些很可能是中繼憑證。如果是這種情況,您不應該使用 tls.crt
作為來源。(詳細資訊請參閱上面的「綁定中繼憑證」)。
那麼 ca.crt
看起來似乎是更普遍正確的選擇,但重要的是要記住,它只能在盡力而為的基礎上填充。 ca.crt
的內容取決於 Issuer
是否正確配置,並且某些簽發者類型可能永遠無法為此欄位提供有用或正確的條目。
一般而言,您應該優先僅使用根憑證建立 Bundles
(同樣,請參閱上文),因此您應該只使用其中包含單個根憑證的欄位。請考慮閱讀以下內容,了解為何您可能不想直接依賴 cert-manager 發行的憑證。
cert-manager 整合:刻意複製 CA 憑證
在 Kubernetes 世界中,提出一個看似使基礎架構自動化更困難的步驟是很奇怪的,但在 TLS 信任儲存的情況下,這可能是一個明智的選擇。
假設您有一個 cert-manager Issuer
,其在 ca.crt
中具有您想要信任的根憑證。直接使用 Secret
並指向 ca.crt
似乎很吸引人,但最佳實務是將該根憑證複製到單獨的 ConfigMap
(或 Secret
)。
原因是 - 與許多 TLS 的陷阱一樣 - 憑證輪換。如果您輪換您的簽發者,使其從新的根憑證發出,trust-manager 將會看到 Secret
更新,並自動更新您的信任綑綁包以包含新的根憑證 - 立即不信任舊的根憑證。
這意味著如果任何服務仍然在使用由舊根憑證發行的憑證,它們將會被不信任並且會中斷。
輪換需要兩個根憑證同時被信任一段時間,或者所有已發行的憑證在舊根憑證之前或同時輪換。
已知問題
kubectl describe
useDefaultCAs
選項在 kubectl describe
內部遇到一個邊緣情況,並呈現為 Use Default C As: true
。這純粹是外觀上的問題。