From b0b0162cb3b405a77455b1198aac34aaccae6801 Mon Sep 17 00:00:00 2001 From: Dmitry Kartsev Date: Wed, 22 Oct 2025 10:49:03 +0300 Subject: [PATCH 1/3] Adding docs for integrating Istio with ZTWIM (SPIFFE/SPIRE) Signed-off-by: Dmitry Kartsev --- .../spire/resources/bookinfo.yaml | 346 ++++++ docs/integrations/spire/spire.adoc | 1045 +++++++++++++++++ 2 files changed, 1391 insertions(+) create mode 100644 docs/integrations/spire/resources/bookinfo.yaml create mode 100644 docs/integrations/spire/spire.adoc diff --git a/docs/integrations/spire/resources/bookinfo.yaml b/docs/integrations/spire/resources/bookinfo.yaml new file mode 100644 index 000000000..99b23a2a0 --- /dev/null +++ b/docs/integrations/spire/resources/bookinfo.yaml @@ -0,0 +1,346 @@ +# Copyright Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +################################################################################################## +# This file defines the services, service accounts, and deployments for the Bookinfo sample. +# +# To apply all 4 Bookinfo services, their corresponding service accounts, and deployments: +# +# kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml +# +# Alternatively, you can deploy any resource separately: +# +# kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml -l service=reviews # reviews Service +# kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml -l account=reviews # reviews ServiceAccount +# kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml -l app=reviews,version=v3 # reviews-v3 Deployment +################################################################################################## + +################################################################################################## +# Details service +################################################################################################## +apiVersion: v1 +kind: Service +metadata: + name: details + labels: + app: details + service: details +spec: + ports: + - port: 9080 + name: http + selector: + app: details +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: bookinfo-details + labels: + account: details +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: details-v1 + labels: + app: details + version: v1 +spec: + replicas: 1 + selector: + matchLabels: + app: details + version: v1 + template: + metadata: + labels: + app: details + version: v1 + annotations: + inject.istio.io/templates: "sidecar,spireWithNativeSidecar" + spec: + serviceAccountName: bookinfo-details + containers: + - name: details + image: docker.io/istio/examples-bookinfo-details-v1:1.20.3 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9080 +--- +################################################################################################## +# Ratings service +################################################################################################## +apiVersion: v1 +kind: Service +metadata: + name: ratings + labels: + app: ratings + service: ratings +spec: + ports: + - port: 9080 + name: http + selector: + app: ratings +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: bookinfo-ratings + labels: + account: ratings +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ratings-v1 + labels: + app: ratings + version: v1 +spec: + replicas: 1 + selector: + matchLabels: + app: ratings + version: v1 + template: + metadata: + labels: + app: ratings + version: v1 + annotations: + inject.istio.io/templates: "sidecar,spireWithNativeSidecar" + spec: + serviceAccountName: bookinfo-ratings + containers: + - name: ratings + image: docker.io/istio/examples-bookinfo-ratings-v1:1.20.3 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9080 +--- +################################################################################################## +# Reviews service +################################################################################################## +apiVersion: v1 +kind: Service +metadata: + name: reviews + labels: + app: reviews + service: reviews +spec: + ports: + - port: 9080 + name: http + selector: + app: reviews +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: bookinfo-reviews + labels: + account: reviews +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: reviews-v1 + labels: + app: reviews + version: v1 +spec: + replicas: 1 + selector: + matchLabels: + app: reviews + version: v1 + template: + metadata: + labels: + app: reviews + version: v1 + annotations: + inject.istio.io/templates: "sidecar,spireWithNativeSidecar" + spec: + serviceAccountName: bookinfo-reviews + containers: + - name: reviews + image: docker.io/istio/examples-bookinfo-reviews-v1:1.20.3 + imagePullPolicy: IfNotPresent + env: + - name: LOG_DIR + value: "/tmp/logs" + ports: + - containerPort: 9080 + volumeMounts: + - name: tmp + mountPath: /tmp + - name: wlp-output + mountPath: /opt/ibm/wlp/output + volumes: + - name: wlp-output + emptyDir: {} + - name: tmp + emptyDir: {} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: reviews-v2 + labels: + app: reviews + version: v2 +spec: + replicas: 1 + selector: + matchLabels: + app: reviews + version: v2 + template: + metadata: + labels: + app: reviews + version: v2 + annotations: + inject.istio.io/templates: "sidecar,spireWithNativeSidecar" + spec: + serviceAccountName: bookinfo-reviews + containers: + - name: reviews + image: docker.io/istio/examples-bookinfo-reviews-v2:1.20.3 + imagePullPolicy: IfNotPresent + env: + - name: LOG_DIR + value: "/tmp/logs" + ports: + - containerPort: 9080 + volumeMounts: + - name: tmp + mountPath: /tmp + - name: wlp-output + mountPath: /opt/ibm/wlp/output + volumes: + - name: wlp-output + emptyDir: {} + - name: tmp + emptyDir: {} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: reviews-v3 + labels: + app: reviews + version: v3 +spec: + replicas: 1 + selector: + matchLabels: + app: reviews + version: v3 + template: + metadata: + labels: + app: reviews + version: v3 + annotations: + inject.istio.io/templates: "sidecar,spireWithNativeSidecar" + spec: + serviceAccountName: bookinfo-reviews + containers: + - name: reviews + image: docker.io/istio/examples-bookinfo-reviews-v3:1.20.3 + imagePullPolicy: IfNotPresent + env: + - name: LOG_DIR + value: "/tmp/logs" + ports: + - containerPort: 9080 + volumeMounts: + - name: tmp + mountPath: /tmp + - name: wlp-output + mountPath: /opt/ibm/wlp/output + volumes: + - name: wlp-output + emptyDir: {} + - name: tmp + emptyDir: {} +--- +################################################################################################## +# Productpage services +################################################################################################## +apiVersion: v1 +kind: Service +metadata: + name: productpage + labels: + app: productpage + service: productpage +spec: + ports: + - port: 9080 + name: http + selector: + app: productpage +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: bookinfo-productpage + labels: + account: productpage +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: productpage-v1 + labels: + app: productpage + version: v1 +spec: + replicas: 1 + selector: + matchLabels: + app: productpage + version: v1 + template: + metadata: + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "9080" + prometheus.io/path: "/metrics" + inject.istio.io/templates: "sidecar,spireWithNativeSidecar" + labels: + app: productpage + version: v1 + spec: + serviceAccountName: bookinfo-productpage + containers: + - name: productpage + image: docker.io/istio/examples-bookinfo-productpage-v1:1.20.3 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9080 + volumeMounts: + - name: tmp + mountPath: /tmp + volumes: + - name: tmp + emptyDir: {} +--- \ No newline at end of file diff --git a/docs/integrations/spire/spire.adoc b/docs/integrations/spire/spire.adoc new file mode 100644 index 000000000..666de1349 --- /dev/null +++ b/docs/integrations/spire/spire.adoc @@ -0,0 +1,1045 @@ +== SPIFFE and Spire and Sail Operator +Spire is a production-ready implementation of the https://spiffe.io/[SPIFFE] specification +that performs node and workload attestation in order to securely issue +cryptographic identities to workloads running in heterogeneous environments. +SPIRE can be configured as a source of cryptographic identities for Istio +workloads through an integration with Envoy’s SDS API. +Istio can detect the existence of a UNIX Domain +Socket that implements the Envoy SDS API on a defined socket path, +allowing Envoy to communicate and fetch identities directly from it. + +This integration with SPIRE provides flexible attestation options not +available with the default Istio identity management while harnessing Istio’s +powerful service management. For example, +SPIRE’s plugin architecture enables diverse workload attestation options +beyond the Kubernetes namespace and service account attestation offered by Istio. +SPIRE’s node attestation extends attestation to the physical or virtual hardware on +which workloads run. + +* <> +** <> +** <> +** <> +*** <> +*** <> +*** <> +*** <> +** <> +** <> +** <> +** <> +** <> + +[[installation]] +=== Installation +For simplicity, this guide uses K8s cluster created with Kind. +However, you are free to choose any other K8s +distribution that suite your setup. + +[[spire-installation]] + +=== Install Spire +The https://artifacthub.io/packages/helm/spiffe/spire[spire-server helm] chart will automatically install + +* Spire Server +* Spire Agent +* Spire Spiffe CSI Driver +* Spire OIDC Discovery Provider + +Define trust domain +[source,bash] +---- +export TRUST_DOMAIN=ocp.one +---- +Install spire helm hart +[source,bash] +---- +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/ \ + --set global.spire.trustDomain=$TRUST_DOMAIN +---- +Make sure the all the Spire components are up and running +[source,bash] +---- +kubectl get pods -nspire-server +---- + +[[verify-spire-installation]] +To verify Spire installation, +deploy client workload +and try to fetch workload SVID +[source,bash] +---- +cat < chain.pem +openssl x509 -in chain.pem -text | grep SPIRE +---- +Example output +[source,bash] +---- +Subject: C=US, O=SPIRE +---- +[[simple-istio-mutual-with-spire]] +=== Simple Istio ISTIO_MUTUAL with Spire +In this scenario we'll deploy client (curl) +and server (httpbin) and validate mTLS connectivity +between the two services. + +Create namespace +[source,bash] +---- +kubectl create namespace test-1 +kubectl label namespace test-1 istio-injection=enabled +---- +Create httpbin server +[source,bash] +---- +cat < Date: Sun, 30 Nov 2025 15:03:18 +0200 Subject: [PATCH 2/3] Adding docs for integrating Istio with ZTWIM (SPIFFE/SPIRE) Signed-off-by: Dmitry Kartsev --- docs/integrations/spire/spire.adoc | 111 +++++++++++++++-------------- 1 file changed, 57 insertions(+), 54 deletions(-) diff --git a/docs/integrations/spire/spire.adoc b/docs/integrations/spire/spire.adoc index 666de1349..481e86feb 100644 --- a/docs/integrations/spire/spire.adoc +++ b/docs/integrations/spire/spire.adoc @@ -1,4 +1,22 @@ -== SPIFFE and Spire and Sail Operator +link:../../README.adoc[Return to Project Root] + +== Table of Contents + +* <> +** <> +** <> +** <> +*** <> +*** <> +*** <> +*** <> +** <> +** <> +** <> +** <> +** <> + +== Spire and Sail Operator Spire is a production-ready implementation of the https://spiffe.io/[SPIFFE] specification that performs node and workload attestation in order to securely issue cryptographic identities to workloads running in heterogeneous environments. @@ -16,22 +34,8 @@ beyond the Kubernetes namespace and service account attestation offered by Istio SPIRE’s node attestation extends attestation to the physical or virtual hardware on which workloads run. -* <> -** <> -** <> -** <> -*** <> -*** <> -*** <> -*** <> -** <> -** <> -** <> -** <> -** <> - [[installation]] -=== Installation +=== Configuring Spire For simplicity, this guide uses K8s cluster created with Kind. However, you are free to choose any other K8s distribution that suite your setup. @@ -66,7 +70,7 @@ helm upgrade --install \ Make sure the all the Spire components are up and running [source,bash] ---- -kubectl get pods -nspire-server +kubectl get pods -n spire-server ---- [[verify-spire-installation]] @@ -131,18 +135,18 @@ CA #1 Valid Until: 2025-10-22 07:38:13 +0000 UTC [[instal-sail-operator]] -==== Install Sail Operator +==== Configure Spire on Sail Operator [source,bash] ---- helm repo add sail-operator https://istio-ecosystem.github.io/sail-operator helm repo update helm install sail-operator \ sail-operator/sail-operator \ - -nistio-system \ + -n istio-system \ --create-namespace ---- -[[create-istio-cni]] -==== Create Istio CNI CR +[[deploy-istio-cni]] +==== Deploy Istio CNI [source,bash] ---- kubectl create namespace istio-cni @@ -158,15 +162,16 @@ spec: namespace: istio-cni EOF ---- -[[create-istio-cr]] -==== Create Istio CR +[[configure-istio-cr]] +==== Configure Istio resource to work with Spire Create `Istio` CR. -_If you are using Kubernetes 1.33 and have not disabled +**Important**: _If you are using Kubernetes 1.33 and have not disabled support for native sidecars in the Istio control plane, you must use initContainers in the injection template for sidecars. This is required because native sidecar support changes how sidecars are injected. + NOTE: The SPIRE injection template for gateways should continue to use regular containers as before._ [source,bash] @@ -213,8 +218,9 @@ spec: readOnly: true EOF ---- -_A note about `sidecarInjectorWebhook`. -Spiffe Workload API exposed over unix socket. + +**About `sidecarInjectorWebhook`**: +_Spiffe Workload API exposed over unix socket. To avoid any host mounts we are using Spire CSI driver which is securely injecting the workload api socket. Thus, we must create sidecar injector template, @@ -224,19 +230,20 @@ socket as a volume to the envoy sidecar container._ Make sure the istiod up and running [source,bash] ---- -kubectl get deploy istiod -nistio-system +kubectl get deploy istiod -n istio-system ---- [[verify-istio-installation]] -==== Verify Istio Installation +==== Verify Istio Installation with Spire configuration Create a new namespace and enable automatic sidecar injection [source,bash] ---- -kubectl create namespace verify-istio-installation -kubectl label namespace verify-istio-installation istio-injection=enabled +kubectl create namespace test +kubectl label namespace test istio-injection=enabled ---- Create simple httpbin deployment and verify spiffe identity. -Note, in the inject template we are specifying `spire` template. + +**Note**: In the inject template, we are specifying `spire` template. The spire injection template is responsible for mounting the Spiffe Workload API socket into the sidecar container [source,bash] @@ -246,7 +253,7 @@ apiVersion: apps/v1 kind: Deployment metadata: name: httpbin - namespace: verify-istio-installation + namespace: test spec: replicas: 1 selector: @@ -272,8 +279,8 @@ EOF Check that the workload identity was issued by SPIRE [source,bash] ---- -HTTPBIN_POD=$(kubectl get pod -l app=httpbin -nverify-istio-installation -o jsonpath="{.items[0].metadata.name}") -istioctl proxy-config secret "$HTTPBIN_POD" -nverify-istio-installation -o json | jq -r \ +HTTPBIN_POD=$(kubectl get pod -l app=httpbin -n test -o jsonpath="{.items[0].metadata.name}") +istioctl proxy-config secret "$HTTPBIN_POD" -n test -o json | jq -r \ '.dynamicActiveSecrets[0].secret.tlsCertificate.certificateChain.inlineBytes' | base64 --decode > chain.pem openssl x509 -in chain.pem -text | grep SPIRE ---- @@ -282,8 +289,8 @@ Example output ---- Subject: C=US, O=SPIRE ---- -[[simple-istio-mutual-with-spire]] -=== Simple Istio ISTIO_MUTUAL with Spire +[[validate-simple-istio-mutual-with-spire]] +=== Validate simple Istio ISTIO_MUTUAL with Spire In this scenario we'll deploy client (curl) and server (httpbin) and validate mTLS connectivity between the two services. @@ -406,7 +413,7 @@ Currently, Istio configured with default PERMISSIVE mode. Try to make http call without mTLS first [source,bash] ---- -CURL_POD=$(kubectl get pod -l app=curl -ntest-1 -o jsonpath="{.items[0].metadata.name}") +CURL_POD=$(kubectl get pod -l app=curl -n test-1 -o jsonpath="{.items[0].metadata.name}") kubectl exec $CURL_POD -n test-1 -it -- curl -s -o /dev/null -w "%{http_code}" http://httpbin ---- You should get HTTP 200 status code. Now, lets enabled mTLS between two services. @@ -452,7 +459,7 @@ EOF Make the curl request again, you should get 200 response code. [source,bash] ---- -CURL_POD=$(kubectl get pod -l app=curl -ntest-1 -o jsonpath="{.items[0].metadata.name}") +CURL_POD=$(kubectl get pod -l app=curl -n test-1 -o jsonpath="{.items[0].metadata.name}") kubectl exec $CURL_POD -n test-1 -it -- curl -s -o /dev/null -w "%{http_code}" http://httpbin ---- If you receive an HTTP 200 code, it confirms that your mesh is configured with Spire correctly. Both services are able to fetch Spiffe link:https://github.com/spiffe/spiffe/blob/main/standards/X509-SVID.md[X.509 SVIDs], trust each other's identities, and can communicate securely. @@ -596,7 +603,7 @@ from the external client to a service running inside the mesh. [source,bash] ---- # get curl pod name -CURL_POD=$(kubectl get pod -l app=curl -ntest-2 -o jsonpath="{.items[0].metadata.name}") +CURL_POD=$(kubectl get pod -l app=curl -n test-2 -o jsonpath="{.items[0].metadata.name}") # fetch x509 SVID and store them on the disk kubectl exec $CURL_POD -n test-2 -it -- \ @@ -644,33 +651,31 @@ helm repo add istio https://istio-release.storage.googleapis.com/charts helm repo update # install the istio gateway helm chart -helm install istio-gateway -nistio-system \ +helm install istio-gateway -n istio-system \ istio/gateway --set-json \ 'podAnnotations={"inject.istio.io/templates":"gateway,spireWithoutNativeSidecar"}' ---- Make sure the istio gateway is up and running [source,bash] ---- -kubectl get deploy istio-gateway -nistio-system +kubectl get deploy istio-gateway -n istio-system ---- Create Istio Gateway CR for `httpbin` service in `test-1` namespace. -A note about the istio-gateway service: +**Note about the istio-gateway service:** This tutorial uses example.com as the placeholder domain. You should replace this with the correct domain for your setup. You must configure DNS to resolve your domain to the gateway: -Cloud (e.g., AWS): If your cluster is in a cloud environment that provides a hostname (like an ELB), create a CNAME record mapping your domain to that hostname. - -On-Premises/Bare-Metal: If your istio-gateway service has a LoadBalancerIP, create an A record mapping your domain to that external IP address. - -Alternative (nip.io): For quick testing, you can use nip.io. This method only works if your gateway service has an external IP address, not a CNAME. +* Cloud (e.g., AWS): If your cluster is in a cloud environment that provides a hostname (like an ELB), create a CNAME record mapping your domain to that hostname. +* On-Premises/Bare-Metal: If your istio-gateway service has a LoadBalancerIP, create an A record mapping your domain to that external IP address. +* Alternative (nip.io): For quick testing, you can use nip.io. This method only works if your gateway service has an external IP address, not a CNAME. ==== Local Testing -For a simple local test, you can bypass public DNS. Update your local /etc/hosts file and manually add entries for the services used in this tutorial. This should be sufficient for completing this guide. +For a simple local test, you can bypass public DNS. Update your local `/etc/hosts` file and manually add entries for the services used in this tutorial. This should be sufficient for completing this guide. -Example /etc/hosts entries: +Example `/etc/hosts` entries: .... [GATEWAY_IP] httpbin.example.com [GATEWAY_IP] bookinfo.example.com @@ -912,11 +917,9 @@ each other using mTLS, authenticated by SPIFFE X.509 SVIDs. To add support for JWT SVIDs to the Istio mesh, you must patch the Istio Custom Resource (CR). Add the following parameters: -`PILOT_JWT_ENABLE_REMOTE_JWKS: "true"` and `jwksResolverExtraRootCA` -The `jwksResolverExtraRootCA` parameter is required to -allow the Istio sidecar to establish secure HTTPS connections -to the remote JWKS server. And `PILOT_JWT_ENABLE_REMOTE_JWKS: "true"` -instruct Istio to use external JWKS server. +* `PILOT_JWT_ENABLE_REMOTE_JWKS: "true"`: instruct Istio to use an external JWKS server +* `jwksResolverExtraRootCA`: required to allow the Istio sidecar to establish secure HTTPS connections +to the remote JWKS server. _Note, you can omit extra root CA if your `SpireOIDCDiscovery` is using trusted by Istio CA certificates. Otherwise, you must provide the `jwksResolverExtraRootCA`. From 2eb610f240be49361e3a7e059b655e6f5ba0712f Mon Sep 17 00:00:00 2001 From: Dmitry Kartsev Date: Wed, 10 Dec 2025 14:58:17 +0200 Subject: [PATCH 3/3] Update docs/integrations/spire/spire.adoc Co-authored-by: Francisco Herrera --- docs/integrations/spire/spire.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/integrations/spire/spire.adoc b/docs/integrations/spire/spire.adoc index 481e86feb..7a5f4dbd3 100644 --- a/docs/integrations/spire/spire.adoc +++ b/docs/integrations/spire/spire.adoc @@ -763,7 +763,7 @@ kubectl get deployment ---- Deploy Istio `VirtualService` and `Gateway` CRs for the Bookinfo App. -Do not forget to export the `LB_IP` as mentioned previously +Do not forget to export the `BASE_DOMAIN` as mentioned previously when we define base domain for the Gateway [source,bash] ---- cat <