SPIRE
SPIRE 是 SPIFFE 規格的生產就緒實作,可執行節點和工作負載證明,以便安全地向異質環境中執行的工作負載發出加密身分。SPIRE 可以透過與 Envoy 的 SDS API 整合,設定為 Istio 工作負載的加密身分來源。Istio 可以偵測在定義的 Socket 路徑上是否存在實作 Envoy SDS API 的 UNIX 網域 Socket,允許 Envoy 直接與其通訊並擷取身分。
這個與 SPIRE 的整合提供了彈性的憑證選項,這些選項在使用預設 Istio 身分管理時無法取得,同時還能利用 Istio 強大的服務管理功能。例如,SPIRE 的外掛架構可以實現多樣化的工作負載憑證選項,而不僅限於 Istio 提供的 Kubernetes 命名空間和服務帳戶憑證。SPIRE 的節點憑證將憑證擴展到執行工作負載的實體或虛擬硬體上。
如需快速展示此 SPIRE 與 Istio 整合如何運作,請參閱透過 Envoy 的 SDS API 將 SPIRE 作為 CA 整合。
安裝 SPIRE
我們建議您遵循 SPIRE 的安裝說明和最佳實務來安裝 SPIRE,以及在生產環境中部署 SPIRE。
在本指南的範例中,將使用上游預設值的SPIRE Helm charts,以便專注於整合 SPIRE 和 Istio 所需的配置。
$ helm upgrade --install -n spire-server spire-crds spire-crds --repo https://spiffe.github.io/helm-charts-hardened/ --create-namespace
$ helm upgrade --install -n spire-server spire spire --repo https://spiffe.github.io/helm-charts-hardened/ --wait --set global.spire.trustDomain="example.org"
預設情況下,上述也會安裝
SPIFFE CSI 驅動程式,用於將與 Envoy 相容的 SDS Socket 掛載到代理中。Istio 和 SPIRE 強烈建議使用 SPIFFE CSI 驅動程式來掛載 SDS Socket,因為
hostMounts
的安全性風險較高,並且會造成操作上的障礙。本指南假設使用 SPIFFE CSI 驅動程式。SPIRE Controller Manager,簡化了工作負載的 SPIFFE 註冊建立。
註冊工作負載
根據設計,SPIRE 只會將身分授予已向 SPIRE 伺服器註冊的工作負載;這包括使用者工作負載以及 Istio 元件。一旦配置為與 SPIRE 整合,Istio Sidecar 和閘道就無法取得身分,因此除非事先為它們建立匹配的 SPIRE 註冊,否則它們無法達到 READY 狀態。
如需更多有關使用多個選擇器來加強憑證條件,以及可用的選擇器的資訊,請參閱SPIRE 文件中關於註冊工作負載的說明。
本節說明了在 SPIRE 伺服器中註冊 Istio 工作負載的可用選項,並提供了一些工作負載註冊的範例。
選項 1:使用 SPIRE 控制器管理員自動註冊
對於在 ClusterSPIFFEID 自訂資源中定義的選擇器匹配的每個新 Pod,都會自動註冊新的項目。
Istio Sidecar 和 Istio 閘道都需要向 SPIRE 註冊,以便它們可以請求身分。
Istio 閘道 ClusterSPIFFEID
以下程式碼將建立一個 ClusterSPIFFEID
,如果任何 Istio Ingress 閘道 Pod 被排程到 istio-system
命名空間,並且有一個名為 istio-ingressgateway-service-account
的服務帳戶,它將會自動向 SPIRE 註冊。這些選擇器僅用作簡單範例;如需更多詳細資訊,請參閱SPIRE Controller Manager 文件。
$ kubectl apply -f - <<EOF
apiVersion: spire.spiffe.io/v1alpha1
kind: ClusterSPIFFEID
metadata:
name: istio-ingressgateway-reg
spec:
spiffeIDTemplate: "spiffe://{{ .TrustDomain }}/ns/{{ .PodMeta.Namespace }}/sa/{{ .PodSpec.ServiceAccountName }}"
workloadSelectorTemplates:
- "k8s:ns:istio-system"
- "k8s:sa:istio-ingressgateway-service-account"
EOF
Istio Sidecar ClusterSPIFFEID
以下程式碼將建立一個 ClusterSPIFFEID
,它將自動向 SPIRE 註冊任何部署到 default
命名空間且具有 spiffe.io/spire-managed-identity: true
標籤的 Pod。這些選擇器僅用作簡單範例;如需更多詳細資訊,請參閱SPIRE Controller Manager 文件。
$ kubectl apply -f - <<EOF
apiVersion: spire.spiffe.io/v1alpha1
kind: ClusterSPIFFEID
metadata:
name: istio-sidecar-reg
spec:
spiffeIDTemplate: "spiffe://{{ .TrustDomain }}/ns/{{ .PodMeta.Namespace }}/sa/{{ .PodSpec.ServiceAccountName }}"
podSelector:
matchLabels:
spiffe.io/spire-managed-identity: "true"
workloadSelectorTemplates:
- "k8s:ns:default"
EOF
選項 2:手動註冊
如果您希望手動建立 SPIRE 註冊,而不是使用建議的選項中提到的 SPIRE Controller Manager,請參閱SPIRE 文件中關於手動註冊的說明。
以下是根據選項 1中的自動註冊所做的等效手動註冊。以下步驟假設您已依照 SPIRE 文件手動註冊您的 SPIRE 代理程式和節點憑證,並且您的 SPIRE 代理程式已使用 SPIFFE 身分 spiffe://example.org/ns/spire/sa/spire-agent
註冊。
取得
spire-server
Pod$ SPIRE_SERVER_POD=$(kubectl get pod -l statefulset.kubernetes.io/pod-name=spire-server-0 -n spire-server -o jsonpath="{.items[0].metadata.name}")
為 Istio Ingress 閘道 Pod 註冊一個項目
$ kubectl exec -n spire "$SPIRE_SERVER_POD" -- \ /opt/spire/bin/spire-server entry create \ -spiffeID spiffe://example.org/ns/istio-system/sa/istio-ingressgateway-service-account \ -parentID spiffe://example.org/ns/spire/sa/spire-agent \ -selector k8s:sa:istio-ingressgateway-service-account \ -selector k8s:ns:istio-system \ -socketPath /run/spire/sockets/server.sock Entry ID : 6f2fe370-5261-4361-ac36-10aae8d91ff7 SPIFFE ID : spiffe://example.org/ns/istio-system/sa/istio-ingressgateway-service-account Parent ID : spiffe://example.org/ns/spire/sa/spire-agent Revision : 0 TTL : default Selector : k8s:ns:istio-system Selector : k8s:sa:istio-ingressgateway-service-account
為注入 Istio Sidecar 的工作負載註冊一個項目
$ kubectl exec -n spire "$SPIRE_SERVER_POD" -- \ /opt/spire/bin/spire-server entry create \ -spiffeID spiffe://example.org/ns/default/sa/curl \ -parentID spiffe://example.org/ns/spire/sa/spire-agent \ -selector k8s:ns:default \ -selector k8s:pod-label:spiffe.io/spire-managed-identity:true \ -socketPath /run/spire/sockets/server.sock
安裝 Istio
使用針對 Ingress 閘道和
istio-proxy
的自訂修補程式建立 Istio 配置。Ingress 閘道元件包含spiffe.io/spire-managed-identity: "true"
標籤。$ cat <<EOF > ./istio.yaml apiVersion: install.istio.io/v1alpha1 kind: IstioOperator metadata: namespace: istio-system spec: profile: default meshConfig: trustDomain: example.org values: # This is used to customize the sidecar template. # It adds both the label to indicate that SPIRE should manage the # identity of this pod, as well as the CSI driver mounts. sidecarInjectorWebhook: templates: spire: | labels: spiffe.io/spire-managed-identity: "true" spec: containers: - name: istio-proxy volumeMounts: - name: workload-socket mountPath: /run/secrets/workload-spiffe-uds readOnly: true volumes: - name: workload-socket csi: driver: "csi.spiffe.io" readOnly: true components: ingressGateways: - name: istio-ingressgateway enabled: true label: istio: ingressgateway k8s: overlays: # This is used to customize the ingress gateway template. # It adds the CSI driver mounts, as well as an init container # to stall gateway startup until the CSI driver mounts the socket. - apiVersion: apps/v1 kind: Deployment name: istio-ingressgateway patches: - path: spec.template.spec.volumes.[name:workload-socket] value: name: workload-socket csi: driver: "csi.spiffe.io" readOnly: true - path: spec.template.spec.containers.[name:istio-proxy].volumeMounts.[name:workload-socket] value: name: workload-socket mountPath: "/run/secrets/workload-spiffe-uds" readOnly: true - path: spec.template.spec.initContainers value: - name: wait-for-spire-socket image: busybox:1.36 volumeMounts: - name: workload-socket mountPath: /run/secrets/workload-spiffe-uds readOnly: true env: - name: CHECK_FILE value: /run/secrets/workload-spiffe-uds/socket command: - sh - "-c" - |- echo "$(date -Iseconds)" Waiting for: ${CHECK_FILE} while [[ ! -e ${CHECK_FILE} ]] ; do echo "$(date -Iseconds)" File does not exist: ${CHECK_FILE} sleep 15 done ls -l ${CHECK_FILE} EOF
套用配置
$ istioctl install --skip-confirmation -f ./istio.yaml
檢查 Ingress 閘道 Pod 狀態
$ kubectl get pods -n istio-system NAME READY STATUS RESTARTS AGE istio-ingressgateway-5b45864fd4-lgrxs 1/1 Running 0 17s istiod-989f54d9c-sg7sn 1/1 Running 0 23s
Ingress 閘道 Pod 處於
Ready
狀態,因為已在 SPIRE 伺服器上為其自動建立對應的註冊項目。Envoy 能夠從 SPIRE 提取加密身分。此配置還會向閘道新增一個
initContainer
,它會在啟動istio-proxy
之前等待 SPIRE 建立 UNIX 網域 Socket。如果 SPIRE 代理程式尚未就緒,或未正確配置為使用相同的 Socket 路徑,則 Ingress 閘道initContainer
將永遠等待。部署一個範例工作負載
$ istioctl kube-inject --filename @samples/security/spire/curl-spire.yaml@ | kubectl apply -f -
除了需要
spiffe.io/spire-managed-identity
標籤之外,工作負載還需要 SPIFFE CSI 驅動程式磁碟區才能存取 SPIRE 代理程式 Socket。為了實現這一點,您可以利用安裝 Istio 章節中的spire
Pod 註解範本,或將 CSI 磁碟區新增至工作負載的部署規格。以下範例程式碼片段中會重點說明這兩種替代方法apiVersion: apps/v1 kind: Deployment metadata: name: curl spec: replicas: 1 selector: matchLabels: app: curl template: metadata: labels: app: curl # Injects custom sidecar template annotations: inject.istio.io/templates: "sidecar,spire" spec: terminationGracePeriodSeconds: 0 serviceAccountName: curl containers: - name: curl image: curlimages/curl command: ["/bin/sleep", "3650d"] imagePullPolicy: IfNotPresent volumeMounts: - name: tmp mountPath: /tmp securityContext: runAsUser: 1000 volumes: - name: tmp emptyDir: {} # CSI volume - name: workload-socket csi: driver: "csi.spiffe.io" readOnly: true
Istio 配置會與 Ingress 閘道以及將要注入到工作負載 Pod 上的 Sidecar 共用 spiffe-csi-driver
,使其能夠存取 SPIRE 代理程式的 UNIX 網域 Socket。
請參閱驗證是否為工作負載建立了身分,以檢查發出的身分。
驗證是否已為工作負載建立身分
使用以下命令確認是否為工作負載建立了身分
$ kubectl exec -t "$SPIRE_SERVER_POD" -n spire-server -c spire-server -- ./bin/spire-server entry show
Found 2 entries
Entry ID : c8dfccdc-9762-4762-80d3-5434e5388ae7
SPIFFE ID : spiffe://example.org/ns/istio-system/sa/istio-ingressgateway-service-account
Parent ID : spiffe://example.org/spire/agent/k8s_psat/demo-cluster/bea19580-ae04-4679-a22e-472e18ca4687
Revision : 0
X509-SVID TTL : default
JWT-SVID TTL : default
Selector : k8s:pod-uid:88b71387-4641-4d9c-9a89-989c88f7509d
Entry ID : af7b53dc-4cc9-40d3-aaeb-08abbddd8e54
SPIFFE ID : spiffe://example.org/ns/default/sa/curl
Parent ID : spiffe://example.org/spire/agent/k8s_psat/demo-cluster/bea19580-ae04-4679-a22e-472e18ca4687
Revision : 0
X509-SVID TTL : default
JWT-SVID TTL : default
Selector : k8s:pod-uid:ee490447-e502-46bd-8532-5a746b0871d6
檢查 Ingress-gateway Pod 狀態
$ kubectl get pods -n istio-system
NAME READY STATUS RESTARTS AGE
istio-ingressgateway-5b45864fd4-lgrxs 1/1 Running 0 60s
istiod-989f54d9c-sg7sn 1/1 Running 0 45s
在為 Ingress-gateway Pod 註冊項目後,Envoy 會收到 SPIRE 發出的身分,並將其用於所有 TLS 和 mTLS 通訊。
檢查工作負載身分是否由 SPIRE 發出
取得 Pod 資訊
$ CURL_POD=$(kubectl get pod -l app=curl -o jsonpath="{.items[0].metadata.name}")
使用 istioctl proxy-config secret 命令擷取 curl 的 SVID 身分文件
$ istioctl proxy-config secret "$CURL_POD" -o json | jq -r \ '.dynamicActiveSecrets[0].secret.tlsCertificate.certificateChain.inlineBytes' | base64 --decode > chain.pem
檢查憑證並驗證 SPIRE 是簽發者
$ openssl x509 -in chain.pem -text | grep SPIRE Subject: C = US, O = SPIRE, CN = curl-5f4d47c948-njvpk
SPIFFE 聯邦
SPIRE 伺服器能夠驗證來自不同信任網域的 SPIFFE 身分。這稱為 SPIFFE 聯合。
可以將 SPIRE 代理程式配置為透過 Envoy SDS API 將聯合套件推送至 Envoy,從而允許 Envoy 使用驗證內容來驗證對等憑證並信任來自另一個信任網域的工作負載。若要啟用 Istio 透過 SPIRE 整合來聯合 SPIFFE 身分,請參閱SPIRE 代理程式 SDS 配置,並為您的 SPIRE 代理程式設定檔設定以下 SDS 配置值。
設定 | 描述 | 資源名稱 |
---|---|---|
default_svid_name | 要與 Envoy SDS 搭配使用的預設 X509-SVID 的 TLS 憑證資源名稱 | 預設 |
default_bundle_name | 要與 Envoy SDS 搭配使用的預設 X.509 套件的驗證內容資源名稱 | null |
default_all_bundles_name | 要與 Envoy SDS 搭配使用的所有套件(包括聯合)的驗證內容資源名稱 | ROOTCA |
這將允許 Envoy 直接從 SPIRE 取得聯合套件。
建立聯邦註冊項目
如果使用 SPIRE Controller Manager,請透過將 ClusterSPIFFEID CR 的
federatesWith
欄位設定為您希望 Pod 與之聯合的信任網域,來建立工作負載的聯合項目apiVersion: spire.spiffe.io/v1alpha1 kind: ClusterSPIFFEID metadata: name: federation spec: spiffeIDTemplate: "spiffe://{{ .TrustDomain }}/ns/{{ .PodMeta.Namespace }}/sa/{{ .PodSpec.ServiceAccountName }}" podSelector: matchLabels: spiffe.io/spire-managed-identity: "true" federatesWith: ["example.io", "example.ai"]
如需手動註冊,請參閱為聯合建立註冊項目。
清除 SPIRE
透過解除安裝其 Helm charts 來移除 SPIRE
$ helm delete -n spire-server spire
$ helm delete -n spire-server spire-crds