使用 Kubernetes CSR 整合自訂 CA
此功能需要 Kubernetes 版本 >= 1.18。
此任務示範如何使用與 Kubernetes CSR API 整合的自訂憑證授權單位來佈建工作負載憑證。不同的工作負載可以從不同的憑證簽署者取得其簽署的憑證。每個憑證簽署者實際上都是不同的 CA。預期從同一個憑證簽署者發出的憑證的工作負載可以彼此進行 mTLS 通訊,而由不同簽署者簽署的工作負載則無法。此功能利用了 Chiron,這是一個與 Istiod 連接的輕量級元件,使用 Kubernetes CSR API 簽署憑證。
在此範例中,我們使用 開源的 cert-manager。從 1.4 版本開始,Cert-manager 添加了 對 Kubernetes CertificateSigningRequests
的實驗性支援。
在 Kubernetes 叢集中部署自訂 CA 控制器
請依照 安裝文件 部署 cert-manager。
$ helm repo add jetstack https://charts.jetstack.io $ helm repo update $ helm install cert-manager jetstack/cert-manager --namespace cert-manager --create-namespace --set featureGates="ExperimentalCertificateSigningRequestControllers=true" --set installCRDs=true
為 cert-manager 建立三個自我簽署的叢集發行者
istio-system
、foo
和bar
。注意:也可以使用命名空間發行者和其他類型的發行者。$ cat <<EOF > ./selfsigned-issuer.yaml apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: selfsigned-bar-issuer spec: selfSigned: {} --- apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: bar-ca namespace: cert-manager spec: isCA: true commonName: bar secretName: bar-ca-selfsigned issuerRef: name: selfsigned-bar-issuer kind: ClusterIssuer group: cert-manager.io --- apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: bar spec: ca: secretName: bar-ca-selfsigned --- apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: selfsigned-foo-issuer spec: selfSigned: {} --- apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: foo-ca namespace: cert-manager spec: isCA: true commonName: foo secretName: foo-ca-selfsigned issuerRef: name: selfsigned-foo-issuer kind: ClusterIssuer group: cert-manager.io --- apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: foo spec: ca: secretName: foo-ca-selfsigned --- apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: selfsigned-istio-issuer spec: selfSigned: {} --- apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: istio-ca namespace: cert-manager spec: isCA: true commonName: istio-system secretName: istio-ca-selfsigned issuerRef: name: selfsigned-istio-issuer kind: ClusterIssuer group: cert-manager.io --- apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: istio-system spec: ca: secretName: istio-ca-selfsigned EOF $ kubectl apply -f ./selfsigned-issuer.yaml
驗證是否為每個叢集簽發者建立密鑰
$ kubectl get secret -n cert-manager -l controller.cert-manager.io/fao=true
NAME TYPE DATA AGE
bar-ca-selfsigned kubernetes.io/tls 3 3m36s
foo-ca-selfsigned kubernetes.io/tls 3 3m36s
istio-ca-selfsigned kubernetes.io/tls 3 3m38s
匯出每個叢集簽發者的根憑證
$ export ISTIOCA=$(kubectl get clusterissuers istio-system -o jsonpath='{.spec.ca.secretName}' | xargs kubectl get secret -n cert-manager -o jsonpath='{.data.ca\.crt}' | base64 -d | sed 's/^/ /')
$ export FOOCA=$(kubectl get clusterissuers foo -o jsonpath='{.spec.ca.secretName}' | xargs kubectl get secret -n cert-manager -o jsonpath='{.data.ca\.crt}' | base64 -d | sed 's/^/ /')
$ export BARCA=$(kubectl get clusterissuers bar -o jsonpath='{.spec.ca.secretName}' | xargs kubectl get secret -n cert-manager -o jsonpath='{.data.ca\.crt}' | base64 -d | sed 's/^/ /')
使用預設憑證簽署者資訊部署 Istio
使用以下配置使用
istioctl
在叢集上部署 Istio。ISTIO_META_CERT_SIGNER
是工作負載的預設憑證簽署者。$ cat <<EOF > ./istio.yaml apiVersion: install.istio.io/v1alpha1 kind: IstioOperator spec: values: pilot: env: EXTERNAL_CA: ISTIOD_RA_KUBERNETES_API meshConfig: defaultConfig: proxyMetadata: ISTIO_META_CERT_SIGNER: istio-system caCertificates: - pem: | $ISTIOCA certSigners: - clusterissuers.cert-manager.io/istio-system - pem: | $FOOCA certSigners: - clusterissuers.cert-manager.io/foo - pem: | $BARCA certSigners: - clusterissuers.cert-manager.io/bar components: pilot: k8s: env: - name: CERT_SIGNER_DOMAIN value: clusterissuers.cert-manager.io - name: PILOT_CERT_PROVIDER value: k8s.io/clusterissuers.cert-manager.io/istio-system overlays: - kind: ClusterRole name: istiod-clusterrole-istio-system patches: - path: rules[-1] value: | apiGroups: - certificates.k8s.io resourceNames: - clusterissuers.cert-manager.io/foo - clusterissuers.cert-manager.io/bar - clusterissuers.cert-manager.io/istio-system resources: - signers verbs: - approve EOF $ istioctl install --skip-confirmation -f ./istio.yaml
建立
bar
和foo
命名空間。$ kubectl create ns bar $ kubectl create ns foo
在
bar
命名空間中部署proxyconfig-bar.yaml
,以定義bar
命名空間中工作負載的憑證簽署者。$ cat <<EOF > ./proxyconfig-bar.yaml apiVersion: networking.istio.io/v1beta1 kind: ProxyConfig metadata: name: barpc namespace: bar spec: environmentVariables: ISTIO_META_CERT_SIGNER: bar EOF $ kubectl apply -f ./proxyconfig-bar.yaml
在
foo
命名空間中部署proxyconfig-foo.yaml
,以定義foo
命名空間中工作負載的憑證簽署者。$ cat <<EOF > ./proxyconfig-foo.yaml apiVersion: networking.istio.io/v1beta1 kind: ProxyConfig metadata: name: foopc namespace: foo spec: environmentVariables: ISTIO_META_CERT_SIGNER: foo EOF $ kubectl apply -f ./proxyconfig-foo.yaml
在
foo
和bar
命名空間中部署httpbin
和curl
範例應用程式。$ kubectl label ns foo istio-injection=enabled $ kubectl label ns bar istio-injection=enabled $ kubectl apply -f samples/httpbin/httpbin.yaml -n foo $ kubectl apply -f samples/curl/curl.yaml -n foo $ kubectl apply -f samples/httpbin/httpbin.yaml -n bar
驗證同一命名空間內 httpbin
和 curl
之間的網路連線
當工作負載部署完成時,它們會發送帶有相關簽署者資訊的 CSR 請求。Istiod 將 CSR 請求轉發到自訂 CA 進行簽署。自訂 CA 將使用正確的叢集發行者簽回憑證。foo
命名空間下的工作負載將使用 foo
叢集發行者,而 bar
命名空間下的工作負載將使用 bar
叢集發行者。為了驗證它們確實是由正確的叢集發行者簽署的,我們可以驗證同一個命名空間下的工作負載可以進行通訊,而不同命名空間下的工作負載則無法通訊。
將
CURL_POD_FOO
環境變數設定為curl
Pod 的名稱。$ export CURL_POD_FOO=$(kubectl get pod -n foo -l app=curl -o jsonpath={.items..metadata.name})
檢查
foo
命名空間中服務curl
和httpbin
之間的網路連線能力。$ kubectl exec "$CURL_POD_FOO" -n foo -c curl -- curl http://httpbin.foo:8000/html <!DOCTYPE html> <html> <head> </head> <body> <h1>Herman Melville - Moby-Dick</h1> <div> <p> Availing himself of the mild... </p> </div> </body>
檢查
foo
命名空間中服務curl
和bar
命名空間中httpbin
之間的網路連線能力。$ kubectl exec "$CURL_POD_FOO" -n foo -c curl -- curl http://httpbin.bar:8000/html upstream connect error or disconnect/reset before headers. reset reason: connection failure, transport failure reason: TLS error: 268435581:SSL routines:OPENSSL_internal:CERTIFICATE_VERIFY_FAILED
清除
移除命名空間並解除安裝 Istio 和 cert-manager
$ kubectl delete ns foo $ kubectl delete ns bar $ istioctl uninstall --purge -y $ helm delete -n cert-manager cert-manager $ kubectl delete ns istio-system cert-manager $ unset ISTIOCA FOOCA BARCA $ rm -rf istio.yaml proxyconfig-foo.yaml proxyconfig-bar.yaml selfsigned-issuer.yaml
使用此功能的原因
自訂 CA 整合 - 通過在 Kubernetes CSR 請求中指定簽署者名稱,此功能允許 Istio 使用 Kubernetes CSR API 介面與自訂憑證授權單位整合。這確實需要自訂 CA 實作一個 Kubernetes 控制器來監控
CertificateSigningRequest
資源並對其採取行動。更好的多租戶 - 通過為不同的工作負載指定不同的憑證簽署者,不同租戶的工作負載憑證可以由不同的 CA 簽署。