Chapter 7. SPIRE integration for mesh security
The SPIFFE Runtime Environment (SPIRE), supported by the OpenShift Zero Trust Workload Identity Manager, provides cryptographic identity management for your service mesh. SPIRE validates platform and runtime attributes to securely authenticate workloads across hybrid infrastructure.
SPIRE integration with OpenShift Service Mesh is a Technology Preview feature only. Technology Preview features are not supported with Red Hat production service level agreements (SLAs) and might not be functionally complete. Red Hat does not recommend using them in production. These features provide early access to upcoming product features, enabling customers to test functionality and provide feedback during the development process.
For more information about the support scope of Red Hat Technology Preview features, see Technology Preview Features Support Scope.
You can deploy SPIRE as a standalone solution or integrate it with cert-manager. When used together, cert-manager acts as the root Certificate Authority (CA), automatically issuing intermediate signing certificates to SPIRE, while SPIRE handles workload identity for mesh communication.
7.1. About SPIRE and SPIFFE Copy linkLink copied to clipboard!
SPIRE implements the Secure Production Identity Framework for Everyone (SPIFFE) open standards. It issues short-lived cryptographic credentials, called SPIFFE Verifiable Identity Documents (SVIDs), to workloads and service mesh components. The architecture uses a central server and node agents to integrate with the OpenShift Service Mesh data plane through a local UNIX domain socket API.
Before issuing an SVID, SPIRE enforces rigorous verification. Node attestation verifies the underlying host platform, while workload attestation inspects runtime attributes such as pod namespaces and service accounts. This process ensures cryptographically verified identities and strong workload authentication before any communication across the mesh begins.
7.2. Benefits of SPIRE Copy linkLink copied to clipboard!
SPIRE provides the following key benefits:
- Zero-trust architecture: Every workload interaction requires cryptographic verification based on attested identity, with no implicit trust zones.
- Cross-platform authentication: Uses SPIFFE identities for workload authentication across clouds, virtual machines, and bare-metal environments.
- Network-independent security: Authentication does not depend on network boundaries, IP addresses, or firewall rules.
- Automatic credential management: Automatically issues and rotates credentials for workloads, eliminating embedded passwords, API keys, and certificates.
Currently, only single-cluster sidecar deployments of OpenShift Service Mesh integrate with SPIRE.
7.3. Install the Operator and components for SPIRE Copy linkLink copied to clipboard!
Before you integrate the SPIFFE Runtime Environment (SPIRE) security framework with OpenShift Service Mesh, you must install the Zero Trust Workload Identity Manager Operator. It manages SPIRE components on your OpenShift Container Platform cluster.
SPIRE integration with OpenShift Service Mesh is a Technology Preview feature only. Technology Preview features are not supported with Red Hat production service level agreements (SLAs) and might not be functionally complete. Red Hat does not recommend using them in production. These features provide early access to upcoming product features, enabling customers to test functionality and provide feedback during the development process.
For more information about the support scope of Red Hat Technology Preview features, see Technology Preview Features Support Scope.
Prerequisites
- You have deployed a cluster on OpenShift Container Platform 4.18 or later.
Procedure
Install the Operator by following the steps in Installing the Zero Trust Workload Identity Manager (which is OpenShift Container Platform documentation).
You can install the Zero Trust Workload Identity Manager by using either the web console or CLI.
Configure the Operator to work in
CreateOnlymode by running the following command:$ oc -n zero-trust-workload-identity-manager patch subscription \ openshift-zero-trust-workload-identity-manager \ --type='merge' -p '{"spec":{"config":{"env":[{"name":"CREATE_ONLY_MODE","value":"true"}]}}}'CreateOnlymode prevents the Operator from automatically overwriting your SPIRE configurations during Istio integration.Define required environment variables:
$ export TRUST_DOMAIN=<apps.mycluster.example.com> $ export ZTWIM_NS=zero-trust-workload-identity-manager $ export JWT_ISSUER="https://oidc-discovery.$(oc get ingresses.config/cluster -o jsonpath={.spec.domain})"where:
TRUST_DOMAIN- The SPIFFE trust domain for the service mesh.
ZTWIM_NS- The namespace where the Zero Trust Workload Identity Manager is deployed.
JWT_ISSUER- The OpenID Connect (OIDC) discovery endpoint URL for the SPIRE OIDC Discovery Provider. SPIRE exposes SPIFFE identities as OIDC-compatible JSON Web Tokens (JWTs) through this endpoint, enabling Istio to validate workload identities with standard OIDC authentication protocols.
Deploy the Operator components according to the OpenShift Container Platform documentation Deploying Zero Trust Workload Identity Manager operands. The components (operands) are:
-
ZeroTrustWorkloadIdentityManagerCR - SPIRE server
- SPIRE agent
- SPIFFE Container Storage Interface (CSI) driver
- SPIRE OpenID Connect (OIDC) discovery provider
-
7.4. Integrate the Istio CR with SPIRE Copy linkLink copied to clipboard!
To implement zero-trust security in your mesh, configure the Istio CR to integrate with the SPIFFE Runtime Environment (SPIRE). This configuration connects Istio proxies to the SPIRE agent. Workloads receive SPIFFE identities instead of using default Istio certificates.
Prerequisites
- You have deployed a cluster on OpenShift Container Platform 4.18 or later.
- You have installed the OpenShift Service Mesh Operator.
- You have installed the Zero Trust Workload Identity Manager and deployed the associated components.
-
You have deployed an
IstioCNICR.
Procedure
Define environment variables for the Istio configuration, as shown in the following example:
$ export ZTWIM_NS=zero-trust-workload-identity-manager $ export TRUST_DOMAIN=<apps.mycluster.example.com> $ export JWT_ISSUER="https://oidc-discovery.$(oc get ingresses.config/cluster -o jsonpath={.spec.domain})" $ export OSSM_NS=istio-system $ export OSSM_CNI=istio-cni $ export VERIFY_NS=verify-ossm-ztwim $ export EXTRA_ROOT_CA="$(oc get secret oidc-serving-cert \ -n ${ZTWIM_NS} -o json | \ jq -r '.data."tls.crt"' | \ base64 -d | \ sed 's/^/ /')"where:
ZTWIM_NS- The namespace where the Zero Trust Workload Identity Manager is deployed. Use the value from your Zero Trust Workload Identity Manager configuration.
TRUST_DOMAIN- The SPIFFE trust domain for the service mesh, which is the same domain specified in your Zero Trust Workload Identity Manager configuration.
JWT_ISSUER- The OpenID Connect (OIDC) discovery endpoint URL for the SPIRE OIDC Discovery Provider. SPIRE exposes SPIFFE identities as OIDC-compatible JSON Web Tokens (JWTs) through this endpoint, enabling Istio to validate workload identities by using standard OIDC authentication protocols. This URL must match the URL specified in your Zero Trust Workload Identity Manager configuration.
OSSM_NS- The namespace where you deploy the Istio control plane.
OSSM_CNI- The namespace where you deployed the Istio CNI component.
VERIFY_NS- The namespace for deploying verification workloads.
EXTRA_ROOT_CA-
The root CA certificate from the SPIRE OIDC Discovery Provider. This certificate enables Istio’s
pilotcomponent to trust and verify JWTs issued by the SPIRE OIDC provider.
Create the Istio CR according to the following example:
$ oc new-project "${OSSM_NS}" 2>/dev/null # Create Istiod $ cat <<EOF | oc apply -f - apiVersion: sailoperator.io/v1 kind: Istio metadata: name: default spec: namespace: istio-system updateStrategy: type: InPlace values: pilot: jwksResolverExtraRootCA: | ${EXTRA_ROOT_CA} env: PILOT_JWT_ENABLE_REMOTE_JWKS: "true" meshConfig: trustDomain: $TRUST_DOMAIN defaultConfig: proxyMetadata: WORKLOAD_IDENTITY_SOCKET_FILE: "spire-agent.sock" sidecarInjectorWebhook: templates: spire: | spec: initContainers: - 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 spireGateway: | 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 EOF # Wait until it is successfully installed until oc get deployment istiod -n "${OSSM_NS}" &> /dev/null; do sleep 3; done oc wait --for=condition=Available deployment/istiod -n "${OSSM_NS}" --timeout=300swhere:
PILOT_JWT_ENABLE_REMOTE_JWKS-
Enables Istio’s
pilotcomponent to fetch JSON Web Key Sets (JWKS) from remote OIDC endpoints. Pilot uses these keys to validate JWTs issued by the SPIRE OIDC Discovery Provider. WORKLOAD_IDENTITY_SOCKET_FILE- Specifies the UNIX domain socket filename that sidecar proxies use to communicate with the SPIRE agent and obtain SPIFFE identities.
sidecarInjectorWebhook.templates.spire-
Custom injection template for regular workload sidecars. It mounts the SPIFFE CSI driver volume at
/run/secrets/workload-spiffe-uds. This directory has the UNIX domain socket file that sidecars use to communicate with the SPIRE agent and obtain SPIFFE identities. sidecarInjectorWebhook.templates.spireGateway-
Custom injection template for ingress and egress gateway pods. It mounts the SPIFFE Container Storage Interface (CSI) driver volume at
/run/secrets/workload-spiffe-uds. This directory has the UNIX domain socket file that gateways use to communicate with the SPIRE agent and obtain SPIFFE identities. csi.spiffe.io- The SPIFFE CSI driver that provides workloads with access to the SPIRE agent’s UNIX domain socket for obtaining SPIFFE identities.
Verification
Deploy a test workload and verify that it receives a SPIFFE identity from SPIRE.
Create a test namespace with sidecar injection enabled:
$ oc new-project "${VERIFY_NS}" $ oc label namespace "${VERIFY_NS}" istio-injection=enabledDeploy the httpbin test application and wait for it to become available:
$ cat <<EOF | oc apply -f - apiVersion: apps/v1 kind: Deployment metadata: name: httpbin namespace: ${VERIFY_NS} spec: replicas: 1 selector: matchLabels: app: httpbin version: v1 template: metadata: annotations: inject.istio.io/templates: "sidecar,spire" spiffe.io/audience: "sky-computing-demo" labels: app: httpbin version: v1 spec: containers: - image: docker.io/mccutchen/go-httpbin:v2.15.0 imagePullPolicy: IfNotPresent name: httpbin ports: - containerPort: 8080 EOF $ oc wait --for=condition=Available deployment/httpbin -n "${VERIFY_NS}" --timeout=300sVerify that the workload received a SPIFFE identity from SPIRE:
$ HTTPBIN_POD=$(oc get pod -l app=httpbin -n "${VERIFY_NS}" -o jsonpath="{.items[0].metadata.name}") $ istioctl proxy-config secret "$HTTPBIN_POD" -n "${VERIFY_NS}" -o json \ | jq -r '.dynamicActiveSecrets[0].secret.tlsCertificate.certificateChain.inlineBytes' \ | base64 --decode > chain.pem $ openssl x509 -in chain.pem -text | grep SPIREThe following output confirms that SPIRE issued the certificate:
Issuer: C=US, O=Sky Computing Corporation, CN=SPIRE Server CA/serialNumber=... Subject: C=US, O=SPIRENoteSPIRE issues two types of identities: X.509 SPIFFE Verifiable Identity Documents (SVIDs) for mTLS communication, and JWT-SVIDs for HTTP-based authentication. This verification confirms X.509 SVID functionality only.
7.5. Test mTLS connectivity with SPIRE Copy linkLink copied to clipboard!
Deploy test applications and configure strict mTLS to validate secure service-to-service communication within the mesh, enabled by the SPIFFE Runtime Environment (SPIRE).
Prerequisites
- You have integrated the Istio CR with SPIRE.
Procedure
Define environment variables for the test namespace and SPIFFE audience:
$ export TPJ=test-ossm-with-ztwim $ export SPIFFE_AUDIENCE="sky-computing-demo"where:
TPJ- Name of the test namespace where you deploy the sample workloads.
SPIFFE_AUDIENCE- Intended recipient of the SPIFFE identity. When workloads request identities from SPIRE, the audience value specifies which services or systems can validate and accept those identities. This restriction helps prevent unauthorized services from misusing identities.
Create a test namespace with sidecar injection enabled:
$ oc create namespace "${TPJ}" $ oc label namespace "${TPJ}" istio-injection=enabledDeploy an httpbin server application:
$ cat <<EOF | oc apply -f - apiVersion: v1 kind: ServiceAccount metadata: name: httpbin namespace: ${TPJ} --- apiVersion: v1 kind: Service metadata: name: httpbin namespace: ${TPJ} labels: app: httpbin service: httpbin spec: ports: - name: http-ex-spiffe port: 443 targetPort: 8080 - name: http port: 80 targetPort: 8080 selector: app: httpbin --- apiVersion: apps/v1 kind: Deployment metadata: name: httpbin namespace: ${TPJ} spec: replicas: 1 selector: matchLabels: app: httpbin version: v1 template: metadata: annotations: inject.istio.io/templates: "sidecar,spire" spiffe.io/audience: "${SPIFFE_AUDIENCE}" labels: app: httpbin version: v1 spec: serviceAccountName: httpbin containers: - image: docker.io/mccutchen/go-httpbin:v2.15.0 imagePullPolicy: IfNotPresent name: httpbin ports: - containerPort: 8080 EOF $ oc wait --for=condition=Available deployment/httpbin -n "${TPJ}" --timeout=300sDeploy a curl client application:
$ cat <<EOF | oc apply -f - apiVersion: v1 kind: ServiceAccount metadata: name: curl namespace: ${TPJ} --- apiVersion: v1 kind: Service metadata: name: curl namespace: ${TPJ} labels: app: curl service: curl spec: ports: - port: 80 name: http selector: app: curl --- apiVersion: apps/v1 kind: Deployment metadata: name: curl namespace: ${TPJ} spec: replicas: 1 selector: matchLabels: app: curl template: metadata: annotations: inject.istio.io/templates: "sidecar,spire" spiffe.io/audience: "${SPIFFE_AUDIENCE}" labels: app: curl spec: terminationGracePeriodSeconds: 0 serviceAccountName: curl containers: - name: curl image: curlimages/curl:8.16.0 command: - /bin/sh - -c - sleep inf imagePullPolicy: IfNotPresent EOF $ oc wait --for=condition=Available deployment/curl -n "${TPJ}" --timeout=300sTest connectivity without mTLS enforcement:
$ CURL_POD=$(oc get pod -l app=curl -n ${TPJ} -o jsonpath="{.items[0].metadata.name}") $ oc exec $CURL_POD -n ${TPJ} -it -- curl -s -o /dev/null -w "%{http_code}" http://httpbinThe command returns HTTP status code 200, which confirms basic connectivity in permissive mode.
Enable strict mTLS and configure destination rules:
$ cat <<EOF | oc apply -f - apiVersion: security.istio.io/v1beta1 kind: PeerAuthentication metadata: name: default namespace: ${TPJ} spec: mtls: mode: STRICT --- apiVersion: networking.istio.io/v1 kind: DestinationRule metadata: name: curl namespace: ${TPJ} spec: host: curl trafficPolicy: tls: mode: ISTIO_MUTUAL --- apiVersion: networking.istio.io/v1 kind: DestinationRule metadata: name: httpbin namespace: ${TPJ} spec: host: httpbin trafficPolicy: tls: mode: ISTIO_MUTUAL EOF
Verification
Verify that mTLS connectivity works with SPIRE-issued identities:
$ CURL_POD=$(oc get pod -l app=curl -n ${TPJ} -o jsonpath="{.items[0].metadata.name}") $ oc exec $CURL_POD -n ${TPJ} -it -- curl -s -o /dev/null -w "%{http_code}" http://httpbinAn HTTP 200 response confirms that:
- Both services successfully obtained SPIFFE X.509 SVIDs from SPIRE.
- The services trust each other’s identities.
- mTLS secures communication between the services.
7.6. Test the Istio ingress gateway with SPIRE Copy linkLink copied to clipboard!
Deploy an Istio ingress gateway that obtains SPIFFE identities from SPIRE to test how external traffic can securely access services in the mesh. The gateway uses these identities to establish mTLS connections to backend services.
Prerequisites
- You have integrated the Istio CR with SPIRE.
- You have verified mTLS connectivity between the two applications in the previous test procedure.
- You have the Helm CLI installed. (See the OpenShift Container Platform documentation Installing the Helm CLI.)
Procedure
Grant the necessary security context permissions for the gateway pod:
$ oc adm policy add-scc-to-user anyuid system:serviceaccount:istio-system:istio-gatewayAdd the Istio Helm repository:
$ helm repo add istio https://istio-release.storage.googleapis.com/charts $ helm repo updateInstall the ingress gateway and enable it to communicate with the SPIRE agent:
$ helm install istio-gateway -n "${OSSM_NS}" \ istio/gateway --set-json \ 'podAnnotations={"inject.istio.io/templates":"gateway,spireGateway"}' $ oc wait --for=condition=Available deployment/istio-gateway -n "${OSSM_NS}" --timeout=300sThe pod annotation
inject.istio.io/templates: gateway,spireGatewaymounts the SPIRE agent socket into the gateway pod. The gateway uses this socket to request and receive SPIFFE identities from SPIRE.Create the
Gatewayresource to define ingress routing rules:$ cat <<EOF | oc apply -f - apiVersion: networking.istio.io/v1 kind: Gateway metadata: name: httpbin-gateway namespace: ${TPJ} spec: selector: istio: gateway servers: - port: number: 80 name: http protocol: HTTP hosts: - "*" EOFConfigure a
VirtualServiceto route traffic from the gateway to the backend service:$ cat <<EOF | oc apply -f - apiVersion: networking.istio.io/v1 kind: VirtualService metadata: name: httpbin namespace: ${TPJ} spec: hosts: - "*" gateways: - httpbin-gateway http: - route: - destination: host: httpbin.${TPJ}.svc.cluster.local port: number: 80 EOFYou do not need to configure destination rules because you created them in the previous example procedure.
Verification
Retrieve the gateway’s external IP address and use it to test connectivity:
$ export GATEWAY_IP="$(oc get svc istio-gateway -n istio-system -o jsonpath={.status.loadBalancer.ingress[].ip})" $ curl -H "Host: httpbin" "${GATEWAY_IP}" -s -o /dev/null -w "%{http_code}"An HTTP 200 response confirms that:
- The ingress gateway routes external traffic.
- The gateway obtains SPIFFE identities from SPIRE for authentication.
- mTLS secures connections between the gateway and backend services.