使用 trust-manager 管理 Kubernetes 中的公眾信任
上次驗證:2023 年 6 月 19 日
在本教學中,我們將逐步介紹如何使用 trust-manager 在 Kubernetes 叢集內部分發公開信任的憑證授權單位 (CA) 憑證。一旦分發完成,我們還會展示
- 當您的信任捆綁包變更時,如何自動重新載入應用程式
- 如何強制應用程式使用您分發的 CA 捆綁包
從這裡,我們將使用一個簡單的 curl
Pod,來展示如何自動掛載信任的 CA Bundle
,以便無需手動設定 curl 即可使用。這模擬了應用程式如何無需任何額外設定即可使用您信任的 CA 憑證捆綁包。
在本教學中,我們將把變更的範圍限制為僅影響 team-a
命名空間。為了充分利用這些功能,您需要移除此限制。
注意: 提供的所有資源都僅供示範,在生產環境中使用之前應仔細審查。
先決條件
💻 軟體
- kubectl:Kubernetes 的命令列工具,可讓您設定 Kubernetes 叢集。
- helm:Kubernetes 的套件管理器。
- yq:用於解析 YAML 的命令列工具,具有有用的色彩標記。
分發公開 CA 信任
讓我們先設定 trust-manager,並將我們的公開 CA 分發到我們的示範命名空間:team-a
。
設定應用程式與捆綁包
-
依照此處的指示安裝 trust-manager。
-
建立您的第一個
Bundle
資源,僅包含公開 CA 憑證apiVersion: trust.cert-manager.io/v1alpha1kind: Bundlemetadata:name: public-bundlespec:sources:- useDefaultCAs: truetarget:configMap:key: "ca-certificates.crt"namespaceSelector:matchLabels:trust: enabledkubectl apply -f - <<EOFapiVersion: trust.cert-manager.io/v1alpha1kind: Bundlemetadata:name: public-bundlespec:sources:- useDefaultCAs: truetarget:configMap:key: "ca-certificates.crt"namespaceSelector:matchLabels:trust: enabledEOF -
讓我們建立一個應用程式將在其中執行的命名空間
kubectl apply -f - <<EOFapiVersion: v1kind: Namespacemetadata:labels:trust: enabledname: team-aEOF請注意,此命名空間已標記為
trust: enabled
,這與Bundle
資源中的namespaceSelector
標準相符namespaceSelector:matchLabels:trust: enabled注意:這是為了將我們的信任捆綁包的範圍限制為僅限於
team-a
命名空間,如先前所述。 -
驗證 trust-manager 控制器是否已正確地將 CA 捆綁包傳播到命名空間
kubectl get configmap -n team-a public-bundle -o yaml請注意,此輸出應該相當長。這是因為我們使用的預設公開捆綁包中包含許多公開 CA。
使用自動使用方式將信任捆綁包掛載到應用程式
若要使用我們信任的 CA,我們將它們掛載到應用程式中的預設位置,大多數應用程式都期望在此位置找到 ca-certificates.crt
檔案。這種方法的好處是,容器內的大多數應用程式碼都會預設使用此檔案,而無需任何額外設定。還有一個額外的好處,就是您將掛載在 /etc/ssl/certs
的頂部,這將移除現有的 CA 憑證,這些憑證通常來自容器基礎映像或在 CI 組建期間拉入。
警告: 在此範例中,我們選擇了一個眾所周知的位置,該位置由 alpine 和
curl
用於取得信任的 CA。這不是唯一可以使用的位置,因此容器可能還有其他預設位置。如果您想查看預設 CA 的位置,可以使用 paranoia 來檢查組建的容器映像。
-
套用應用程式部署
apiVersion: apps/v1kind: Deploymentmetadata:labels:app: sleep-autoname: sleep-autonamespace: team-aspec:replicas: 1revisionHistoryLimit: 3selector:matchLabels:app: sleep-autostrategy: {}template:metadata:labels:app: sleep-autospec:containers:- command:- /bin/sh- -c- sleep 1dimage: quay.io/zenlab/curl:latestname: curlresources: {}volumeMounts:- mountPath: /etc/ssl/certs/name: ca-certificate-onlyreadOnly: truevolumes:- name: ca-certificate-onlyconfigMap:name: public-bundledefaultMode: 0644optional: falseitems:- key: ca-certificates.crtpath: ca-certificates.crtkubectl apply -f - <<EOFapiVersion: apps/v1kind: Deploymentmetadata:labels:app: sleep-autoname: sleep-autonamespace: team-aspec:replicas: 1revisionHistoryLimit: 3selector:matchLabels:app: sleep-autotemplate:metadata:labels:app: sleep-autospec:containers:- command:- /bin/sh- -c- sleep 1dimage: quay.io/zenlab/curl:latestname: curlvolumeMounts:- mountPath: /etc/ssl/certs/name: ca-certificate-onlyreadOnly: truevolumes:- name: ca-certificate-onlyconfigMap:name: public-bundledefaultMode: 0644optional: falseitems:- key: ca-certificates.crtpath: ca-certificates.crtEOF -
在正在執行的 Pod 中建立 Shell
kubectl exec -n team-a -ti $(kubectl get po -n team-a -l app=sleep-auto -o jsonpath='{.items[0].metadata.name}') -- /bin/sh -
列出
/etc/ssl/certs/
的內容,以驗證僅存在您信任的ca-certificates.crt
。ls -ltr /etc/ssl/certs/輸出應類似於
~ $ ls -ltr /etc/ssl/certs/total 0lrwxrwxrwx 1 root root 26 Apr 14 15:12 ca-certificates.crt -> ..data/ca-certificates.crt請注意,通常此容器映像的輸出會如下所示,當沒有磁碟區覆寫此目錄時
~ $ ls -ltr /etc/ssl/certs/total 608-rw-r--r-- 1 root root 214222 Apr 14 01:11 ca-certificates.crtlrwxrwxrwx 1 root root 52 Apr 14 01:11 ca-cert-vTrus_Root_CA.pem -> /usr/share/ca-certificates/mozilla/vTrus_Root_CA.crtlrwxrwxrwx 1 root root 56 Apr 14 01:11 ca-cert-vTrus_ECC_Root_CA.pem -> /usr/share/ca-certificates/mozilla/vTrus_ECC_Root_CA.crt...lrwxrwxrwx 1 root root 53 Apr 14 01:11 02265526.0 -> ca-cert-Entrust_Root_Certification_Authority_-_G2.pemlrwxrwxrwx 1 root root 31 Apr 14 01:11 002c0b4f.0 -> ca-cert-GlobalSign_Root_R46.pem -
撥打 HTTPS 電話到一個知名的網站,以驗證
curl
是否正常運作,而無需傳遞額外的--cacert
旗標curl -v https://bbc.co.uk/news成功將產生有效的 TLS 連線,例如
* Trying 151.101.0.81:443...* Connected to bbc.co.uk (151.101.0.81) port 443 (#0)* ALPN: offers h2,http/1.1* TLSv1.3 (OUT), TLS handshake, Client hello (1):* CAfile: /etc/ssl/certs/ca-certificates.crt* CApath: none* TLSv1.3 (IN), TLS handshake, Server hello (2):* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):* TLSv1.3 (IN), TLS handshake, Certificate (11):* TLSv1.3 (IN), TLS handshake, CERT verify (15):* TLSv1.3 (IN), TLS handshake, Finished (20):* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):* TLSv1.3 (OUT), TLS handshake, Finished (20):* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256* ALPN: server accepted h2* Server certificate:* subject: C=GB; ST=London; L=London; O=BRITISH BROADCASTING CORPORATION; CN=www.bbc.com* start date: Mar 14 06:16:13 2023 GMT* expire date: Apr 14 06:16:12 2024 GMT* subjectAltName: host "bbc.co.uk" matched cert's "bbc.co.uk"* issuer: C=BE; O=GlobalSign nv-sa; CN=GlobalSign RSA OV SSL CA 2018* SSL certificate verify ok.
- 結束容器:
exit
設定實際應用程式
根據上述範例,Kubernetes 能夠掛載在預設的 CA 憑證捆綁包之上。如果您知道它們從何處檢索 CA 憑證的預設位置,則可以將此用於應用程式。
例如,對於 Go
,您的應用程式可以設定為使用 SSL_CERT_FILE
或 SSL_CERT_DIR
來指向預設的 CA 憑證檔案位置。
請參閱此處以瞭解更多詳細資訊,並查看此處以瞭解各種作業系統基礎上的預設位置
// Possible certificate files; stop after finding one.var certFiles = []string{"/etc/ssl/certs/ca-certificates.crt", // Debian/Ubuntu/Gentoo etc."/etc/pki/tls/certs/ca-bundle.crt", // Fedora/RHEL 6"/etc/ssl/ca-bundle.pem", // OpenSUSE"/etc/pki/tls/cacert.pem", // OpenELEC"/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", // CentOS/RHEL 7"/etc/ssl/cert.pem", // Alpine Linux}// Possible directories with certificate files; all will be read.var certDirectories = []string{"/etc/ssl/certs", // SLES10/SLES11, https://go.dev.org.tw/issue/12139"/etc/pki/tls/certs", // Fedora/RHEL"/
在檢查 Python 時,ssl
程式庫使用相同的兩個環境變數來尋找信任的 CA:SSL_CERT_DIR
和/或 SSL_CERT_FILE
。您可以在說明文件中和 python3
執行階段中驗證這一點
>>> import ssl>>> ssl.get_default_verify_paths()DefaultVerifyPaths(cafile=None, capath='/usr/lib/ssl/certs', openssl_cafile_env='SSL_CERT_FILE', openssl_cafile='/usr/lib/ssl/cert.pem', openssl_capath_env='SSL_CERT_DIR', openssl_capath='/usr/lib/ssl/certs')
這應該表示,任何掛載在檔案中的 CA 和任何下列檔案都將受到任何 Python 應用程式執行階段的信任,與 Go
類似
- '/usr/lib/ssl/cert.pem'
- '/usr/lib/ssl/certs/*'
類似的內容也可以透過其他語言實現。
自動化與強制執行
現在我們已經手動掛載了 trust-manager 的捆綁包,您可能會想
- 如果 CA 捆綁包變更,我該如何將該變更傳遞給我的應用程式?
- 我該如何確保我的 CA 捆綁包掛載到叢集中的所有應用程式,而無需向我的租戶請求變更?
讓我們使用其他開源工具來解決這兩種情況。
推出 CA 捆綁包變更
如果您的 CA 捆綁包變更,這些變更將會非常快速地同步到命名空間。此變更將反映在附加到容器的磁碟區中,但大多數應用程式不會注意到檔案系統變更。常見的方法是透過使用 kubectl rollout restart deployment <DEPLOY_NAME>
來重新啟動用戶端應用程式部署。有一個選項可以透過協力廠商的開源軟體來自動執行此程序。
使用 Stakater Reloader,可以在 ConfigMap
或 Secret
變更時重新載入或部署應用程式。因此,每當 Bundle
的目標同步時,Reloader 元件可以偵測到此變更,並部署掛載這些資源作為磁碟區或環境變數的應用程式。
請注意,您可以在應用程式容器中綁定或編寫許多替代軟體。它們只需監看檔案系統的變更並觸發應用程式程序重新載入。這種方法需要容器映像或程式碼變更,並且對於許多租戶來說可能難以實作。這裡使用 reloader 的優勢在於它是一個通用的解決方案,適用於叢集中運行的所有應用程式。
-
繼續使用 reloader,它可以透過 helm 安裝
helm repo add stakater https://stakater.github.io/stakater-chartshelm repo updatehelm install reloader stakater/reloader -n stakater-reloader --create-namespace --set fullnameOverride=reloader -
我們可以重複使用上一節的部署
sleep-auto
,並將其設定為啟用重新載入功能kubectl annotate deployment -n team-a sleep-auto reloader.stakater.com/auto="true"請注意,有多種配置選項可用於配置 reloader 工具,這僅是最基本的範例。如需更詳細的範例,請參閱文件。
-
在另一個終端機中監看應用程式部署
kubectl get po -n team-a -w -
為了測試此變更,我們可以編輯我們的
Bundle
資源,移除所有預設的公開 CA 憑證,而只提供一個 CA 憑證apiVersion: trust.cert-manager.io/v1alpha1kind: Bundlemetadata:name: public-bundlespec:sources:- inLine: |-----BEGIN CERTIFICATE-----MIIETjCCAzagAwIBAgINAe5fFp3/lzUrZGXWajANBgkqhkiG9w0BAQsFADBXMQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEQMA4GA1UECxMHUm9vdCBDQTEbMBkGA1UEAxMSR2xvYmFsU2lnbiBSb290IENBMB4XDTE4MDkxOTAwMDAwMFoXDTI4MDEyODEyMDAwMFowTDEgMB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDMJXaQeQZ4Ihb1wIO2hMoonv0FdhHFrYhy/EYCQ8eyip0EXyTLLkvhYIJG4VKrDIFHcGzdZNHr9SyjD4I9DCuul9e2FIYQebs7E4B3jAjhSdJqYi8fXvqWaN+JJ5U4nwbXPsnLJlkNc96wyOkmDoMVxu9bi9IEYMpJpij2aTv2y8gokeWdimFXN6x0FNx04Druci8unPvQu7/1PQDhBjPogiuuU6Y6FnOM3UEOIDrAtKeh6bJPkC4yYOlXy7kEkmho5TgmYHWyn3f/kRTvriBJ/K1AFUjRAjFhGV64l++td7dkmnq/X8ET75ti+w1s4FRpFqkD2m7pg5NxdsZphYIXAgMBAAGjggEiMIIBHjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUj/BLf6guRSSuTVD6Y5qL3uLdG7wwHwYDVR0jBBgwFoAUYHtmGkUNl8qJUC99BM00qP/8/UswPQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwOi8vb2NzcC5nbG9iYWxzaWduLmNvbS9yb290cjEwMwYDVR0fBCwwKjAooCagJIYiaHR0cDovL2NybC5nbG9iYWxzaWduLmNvbS9yb290LmNybDBHBgNVHSAEQDA+MDwGBFUdIAAwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93d3cuZ2xvYmFsc2lnbi5jb20vcmVwb3NpdG9yeS8wDQYJKoZIhvcNAQELBQADggEBACNw6c/ivvVZrpRCb8RDM6rNPzq5ZBfyYgZLSPFAiAYXof6r0V88xjPy847dHx0+zBpgmYILrMf8fpqHKqV9D6ZX7qw7aoXW3r1AY/itpsiIsBL89kHfDwmXHjjqU5++BfQ+6tOfUBJ2vgmLwgtIfR4uUfaNU9OrH0Abio7tfftPeVZwXwzTjhuzp3ANNyuXlava4BJrHEDOxcd+7cJiWOx37XMiwor1hkOIreoTbv3Y/kIvuX1erRjvlJDKPSerJpSZdcfL03v3ykzTr1EhkluEfSufFT90y1HonoMOFm8b50bOI7355KKL0jlrqnkckSziYSQtjipIcJDEHsXo4HA=-----END CERTIFICATE-----target:configMap:key: "ca-certificates.crt"namespaceSelector:matchLabels:trust: enabledkubectl apply -f - <<EOFapiVersion: trust.cert-manager.io/v1alpha1kind: Bundlemetadata:name: public-bundlespec:sources:- inLine: |-----BEGIN CERTIFICATE-----MIIETjCCAzagAwIBAgINAe5fFp3/lzUrZGXWajANBgkqhkiG9w0BAQsFADBXMQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEQMA4GA1UECxMHUm9vdCBDQTEbMBkGA1UEAxMSR2xvYmFsU2lnbiBSb290IENBMB4XDTE4MDkxOTAwMDAwMFoXDTI4MDEyODEyMDAwMFowTDEgMB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDMJXaQeQZ4Ihb1wIO2hMoonv0FdhHFrYhy/EYCQ8eyip0EXyTLLkvhYIJG4VKrDIFHcGzdZNHr9SyjD4I9DCuul9e2FIYQebs7E4B3jAjhSdJqYi8fXvqWaN+JJ5U4nwbXPsnLJlkNc96wyOkmDoMVxu9bi9IEYMpJpij2aTv2y8gokeWdimFXN6x0FNx04Druci8unPvQu7/1PQDhBjPogiuuU6Y6FnOM3UEOIDrAtKeh6bJPkC4yYOlXy7kEkmho5TgmYHWyn3f/kRTvriBJ/K1AFUjRAjFhGV64l++td7dkmnq/X8ET75ti+w1s4FRpFqkD2m7pg5NxdsZphYIXAgMBAAGjggEiMIIBHjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUj/BLf6guRSSuTVD6Y5qL3uLdG7wwHwYDVR0jBBgwFoAUYHtmGkUNl8qJUC99BM00qP/8/UswPQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwOi8vb2NzcC5nbG9iYWxzaWduLmNvbS9yb290cjEwMwYDVR0fBCwwKjAooCagJIYiaHR0cDovL2NybC5nbG9iYWxzaWduLmNvbS9yb290LmNybDBHBgNVHSAEQDA+MDwGBFUdIAAwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93d3cuZ2xvYmFsc2lnbi5jb20vcmVwb3NpdG9yeS8wDQYJKoZIhvcNAQELBQADggEBACNw6c/ivvVZrpRCb8RDM6rNPzq5ZBfyYgZLSPFAiAYXof6r0V88xjPy847dHx0+zBpgmYILrMf8fpqHKqV9D6ZX7qw7aoXW3r1AY/itpsiIsBL89kHfDwmXHjjqU5++BfQ+6tOfUBJ2vgmLwgtIfR4uUfaNU9OrH0Abio7tfftPeVZwXwzTjhuzp3ANNyuXlava4BJrHEDOxcd+7cJiWOx37XMiwor1hkOIreoTbv3Y/kIvuX1erRjvlJDKPSerJpSZdcfL03v3ykzTr1EhkluEfSufFT90y1HonoMOFm8b50bOI7355KKL0jlrqnkckSziYSQtjipIcJDEHsXo4HA=-----END CERTIFICATE-----target:configMap:key: "ca-certificates.crt"namespaceSelector:matchLabels:trust: enabledEOF您應該立即在另一個終端機中看到應用程式部署已重新部署。
-
新的 Pod 執行後,使用以下命令確認您只有一個 CA 憑證
ca-certificates.crt
檔案,也就是我們剛套用的那個kubectl exec -ti -n team-a $(kubectl get po -n team-a -l app=sleep-auto -o jsonpath='{.items[0].metadata.name}') -- cat /etc/ssl/certs/ca-certificates.crt您應該會得到完全相同的輸出
-----BEGIN CERTIFICATE-----MIIETjCCAzagAwIBAgINAe5fFp3/lzUrZGXWajANBgkqhkiG9w0BAQsFADBXMQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEQMA4GA1UECxMHUm9vdCBDQTEbMBkGA1UEAxMSR2xvYmFsU2lnbiBSb290IENBMB4XDTE4MDkxOTAwMDAwMFoXDTI4MDEyODEyMDAwMFowTDEgMB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDMJXaQeQZ4Ihb1wIO2hMoonv0FdhHFrYhy/EYCQ8eyip0EXyTLLkvhYIJG4VKrDIFHcGzdZNHr9SyjD4I9DCuul9e2FIYQebs7E4B3jAjhSdJqYi8fXvqWaN+JJ5U4nwbXPsnLJlkNc96wyOkmDoMVxu9bi9IEYMpJpij2aTv2y8gokeWdimFXN6x0FNx04Druci8unPvQu7/1PQDhBjPogiuuU6Y6FnOM3UEOIDrAtKeh6bJPkC4yYOlXy7kEkmho5TgmYHWyn3f/kRTvriBJ/K1AFUjRAjFhGV64l++td7dkmnq/X8ET75ti+w1s4FRpFqkD2m7pg5NxdsZphYIXAgMBAAGjggEiMIIBHjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUj/BLf6guRSSuTVD6Y5qL3uLdG7wwHwYDVR0jBBgwFoAUYHtmGkUNl8qJUC99BM00qP/8/UswPQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwOi8vb2NzcC5nbG9iYWxzaWduLmNvbS9yb290cjEwMwYDVR0fBCwwKjAooCagJIYiaHR0cDovL2NybC5nbG9iYWxzaWduLmNvbS9yb290LmNybDBHBgNVHSAEQDA+MDwGBFUdIAAwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93d3cuZ2xvYmFsc2lnbi5jb20vcmVwb3NpdG9yeS8wDQYJKoZIhvcNAQELBQADggEBACNw6c/ivvVZrpRCb8RDM6rNPzq5ZBfyYgZLSPFAiAYXof6r0V88xjPy847dHx0+zBpgmYILrMf8fpqHKqV9D6ZX7qw7aoXW3r1AY/itpsiIsBL89kHfDwmXHjjqU5++BfQ+6tOfUBJ2vgmLwgtIfR4uUfaNU9OrH0Abio7tfftPeVZwXwzTjhuzp3ANNyuXlava4BJrHEDOxcd+7cJiWOx37XMiwor1hkOIreoTbv3Y/kIvuX1erRjvlJDKPSerJpSZdcfL03v3ykzTr1EhkluEfSufFT90y1HonoMOFm8b50bOI7355KKL0jlrqnkckSziYSQtjipIcJDEHsXo4HA=-----END CERTIFICATE----- -
此 CA 憑證可用於驗證網站
https://bbc.co.uk
的真實性。我們可以從該容器中使用curl
進行驗證kubectl exec -ti -n team-a $(kubectl get po -n team-a -l app=sleep-auto -o jsonpath='{.items[0].metadata.name}') -- curl -v https://bbc.co.uk我們也可以驗證從這個 Pod,我們無法再與 google.com 通訊。
kubectl exec -ti -n team-a $(kubectl get po -n team-a -l app=sleep-auto -o jsonpath='{.items[0].metadata.name}') -- curl -v https://google.comTLS 失敗範例
* Trying 142.250.200.46:443...* Connected to google.com (142.250.200.46) port 443 (#0)* ALPN: offers h2,http/1.1* TLSv1.3 (OUT), TLS handshake, Client hello (1):* CAfile: /etc/ssl/certs/ca-certificates.crt* CApath: none* TLSv1.3 (IN), TLS handshake, Server hello (2):* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):* TLSv1.3 (IN), TLS handshake, Certificate (11):* TLSv1.3 (OUT), TLS alert, unknown CA (560):* SSL certificate problem: unable to get local issuer certificate* Closing connection 0curl: (60) SSL certificate problem: unable to get local issuer certificateMore details here: https://curl.se/docs/sslcerts.htmlcurl failed to verify the legitimacy of the server and therefore could notestablish a secure connection to it. To learn more about this situation andhow to fix it, please visit the web page mentioned above.command terminated with exit code 60
強制使用您的 CA 憑證包
使用諸如 Gatekeeper 和 Kyverno 之類的工具,我們可以要求在應用程式部署到 Kubernetes 時,強制執行特定的 volume
和 volumeMount
配置。透過這種方法,叢集管理員可以設定規則,將相關配置自動插入到每個 Pod 中。這可能有利於強制執行配置,但對於叢集的應用程式團隊或租戶來說可能更不透明。
在本教學中,我們將展示如何使用 Gatekeeper
Gatekeeper
請參閱 Gatekeeper 目錄,其中包含兩個範例 Assign
原則,旨在強制將 CA 憑證包從 trust-manager 在每個命名空間中產生的 configMap
掛載到所有 Pod 上。
-
將 Gatekeeper 安裝到您的叢集
helm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/chartshelm repo updatehelm install gatekeeper/gatekeeper --name-template=gatekeeper --namespace gatekeeper-system --create-namespace --version v3.11.0 -
建立一個適用於
team-a
命名空間中所有pod
資源的原則,該原則會將必要的volumes
配置套用至Pod
資源apiVersion: mutations.gatekeeper.sh/v1kind: Assignmetadata:name: demo-trust-ca-volumespec:applyTo:- groups: [""]kinds: ["Pod"]versions: ["v1"]match:scope: Namespacedkinds:- apiGroups: ["*"]kinds: ["Pod"]namespaces: ["team-a"]excludedNamespaces: ["kube-system", "public", "kyverno", "gatekeeper-system"]# Mounting the volume named "ca-certificates" from ConfigMaplocation: "spec.volumes[name:ca-certificates]"parameters:assign:value:name: ca-certificatesconfigMap:name: public-bundledefaultMode: 0644optional: falseitems:- key: ca-certificates.crtpath: ca-certificates.crtkubectl apply -f gatekeeper/gatekeeper-trust-pod-ca-volume.yaml -
建立一個適用於
team-a
命名空間中所有pod
資源的原則,該原則會將必要的volumeMounts
配置套用至這些資源apiVersion: mutations.gatekeeper.sh/v1kind: Assignmetadata:name: demo-trust-ca-volumemountspec:applyTo:- groups: [""]kinds: ["Pod"]versions: ["v1"]match:scope: Namespacedkinds:- apiGroups: ["*"]kinds: ["Pod"]namespaces: ["team-a"]excludedNamespaces: ["kube-system", "public", "kyverno", "gatekeeper-system"]# All containers in a pod mounting to volumeMount named "ca-certificates"location: "spec.containers[name:*].volumeMounts[name:ca-certificates]"parameters:assign:value:mountPath: /etc/ssl/certs/name: ca-certificatesreadOnly: truekubectl apply -f gatekeeper/gatekeeper-trust-pod-ca-volumemount.yaml -
切換到
team-a
命名空間,並建立沒有先前volume
或volumeMount
配置的部署,以查看 Pod 執行後生效的變更apiVersion: apps/v1kind: Deploymentmetadata:labels:app: test-assignname: test-assignnamespace: team-aspec:replicas: 1revisionHistoryLimit: 3selector:matchLabels:app: test-assignstrategy: {}template:metadata:labels:app: test-assignspec:containers:- command:- /bin/sh- -c- sleep 1dimage: quay.io/zenlab/curl:latestname: curlresources: {}volumeMounts: []volumes: []kubectl apply -f gatekeeper/deploy-novol.yaml -
套用後,驗證
volume
和volumeMount
是否已套用kubectl get po -n team-a -l app=test-assign -o yaml | yq '.items[0].spec' - -
在 Pod 中執行 Shell,並嘗試與任何公開信任的網站建立 HTTPS 連線,例如:
https://bbc.co.uk
kubectl exec -n team-a -ti $(kubectl get pod -n team-a -l app=test-assign -o jsonpath='{.items[0].metadata.name}') -- curl -v https://bbc.co.uk成功看起來像是從網頁返回有效的 200 回應。
請注意,現在應該可以在沒有任何額外配置的情況下運作。如果在這一點出現 SSL 錯誤,請檢查
volumes
區段中是否參考了正確的configMap
。 -
最後,我們可以套用一個類似的 Pod,只是這次 CA 憑證已明確掛載。這是為了說明,如果相關配置已存在,Gatekeeper 原則不會執行任何動作
apiVersion: apps/v1kind: Deploymentmetadata:labels:app: test-assign-noopname: test-assign-noopnamespace: team-aspec:replicas: 1revisionHistoryLimit: 3selector:matchLabels:app: test-assign-nooptemplate:metadata:labels:app: test-assign-noopspec:containers:- command:- /bin/sh- -c- sleep 1dimage: quay.io/zenlab/curl:latestname: curlvolumeMounts:- mountPath: /etc/ssl/certs/name: ca-certificatesreadOnly: truevolumes:- name: ca-certificatesconfigMap:name: exampledefaultMode: 0644optional: falseitems:- key: ca-certificates.crtpath: ca-certificates.crtkubectl apply -f gatekeeper/deploy-withvol.yamlkubectl exec -n team-a -ti $(kubectl get pod -n team-a -l app=test-assign-noop -o jsonpath='{.items[0].metadata.name}') -- curl -v https://bbc.co.uk
注意:如果您的 Assign
原則資源有問題,請嘗試檢查 Kubernetes 事件 (kubectl get events
) 是否有問題。
使用 trust-manager 的公開信任
在本教學中,我們展示了如何使用 trust-manager 在叢集層級管理憑證授權單位憑證,以及如何手動或透過使用 Gatekeeper 強制執行來使用此受信任的 Bundle
。我們已經了解如何設定應用程式,使其在受信任的 CA 變更時自動部署。
儘管這對於目前在您的環境中「正常運作」的項目來說似乎需要更多的工作,但請考慮此解決方案如何讓您在不再信任特定憑證授權單位的情況下進行處理。
下次我們將研究將私人憑證授權單位整合到此信任管理流程中有多簡單。
清除
若要移除在本教學中部署的所有資源
kubectl delete deployment -n team-a sleep-auto test-assign test-assign-noopkubectl delete bundle public-bundlekubectl delete assign demo-trust-ca-volume demo-trust-ca-volumemounthelm uninstall -n gatekeeper-system gatekeeperhelm uninstall -n stakater-reloader reloaderhelm uninstall -n cert-manager trust-managerhelm uninstall -n cert-manager cert-managerkubectl delete namespace cert-manager team-a stakater-reloader gatekeeper-systemkubectl delete crd -l gatekeeper.sh/system=yes