Integrating Red Hat OpenShift Service Mesh with Zero Trust Workload Identity Manager in a single-cluster { #zero-trust-manager-mesh-integration_{context} }¶
Deploy and configure SPIFFE Runtime Environment as the certificate authority (CA) for Red Hat OpenShift Service Mesh workloads, replacing the Istio built-in CA with SPIFFE-compliant identities and automatically rotated short-lived certificates.
SPIRE integration with Red Hat OpenShift Service Mesh¶
Red Hat OpenShift Service Mesh integrates with Zero Trust Workload Identity Manager so Envoy sidecars obtain mTLS certificates from Secure Production Identity Framework for Everyone (SPIFFE) instead of Istio’s built-in CA, enabling cryptographically verified workload identities.
SPIRE provides cryptographic workload identities based on the Secure Production Identity Framework for Everyone (SPIFFE) standard. This integration enables a zero-trust security model where workload identities are cryptographically verified rather than relying on network-based authentication.
Component overview¶
The following table summarizes the main components in a single-cluster SPIFFE and Red Hat OpenShift Service Mesh integration and what each one does.
| Component | Purpose |
|---|---|
| Zero Trust Workload Identity Manager | Manages SPIRE deployment on OpenShift Container Platform |
| SPIRE Server | Certificate Authority; issues SVIDs |
| SPIRE Agent | Runs on each node; provides SDS API to workloads |
| SPIFFE CSI Driver | Mounts SPIRE socket into pods |
| ClusterSPIFFEID | Registers which pods get which identities |
| Red Hat OpenShift Service Mesh Operator | Manages Istio deployment |
| Istiod | Istio control plane |
| Envoy Sidecar | Proxy in each pod; uses SPIRE for certificates |
SPIRE integration architecture components¶
Learn about the key components in the SPIRE integration architecture and how they work together to enable zero-trust workload identity and automated certificate management for secure mTLS connections in Red Hat OpenShift Service Mesh.
- Zero Trust Workload Identity Manager
- Manages the SPIRE deployment lifecycle on OpenShift Container Platform, including custom resources for SPIRE Server, SPIRE Agent, and related components.
- SPIRE Server
- Acts as the certificate authority that issues SPIFFE Verifiable Identity Documents (SVIDs) to authenticated workloads.
- SPIRE Agent
- Runs as a DaemonSet on each cluster node, providing the Envoy Secret Discovery Service (SDS) API to workloads on that node.
- SPIFFE CSI Driver
- Mounts the SPIRE Agent UNIX domain socket into pods, enabling secure communication between Envoy sidecars and the SPIRE Agent.
- Red Hat OpenShift Service Mesh
- Manages the Istio deployment through the
servicemeshoperator3Operator. - Istiod
- The Istio control plane that configures Envoy proxies but delegates certificate issuance to SPIRE.
- Envoy sidecar
- The proxy injected into each workload pod that uses SPIRE-issued certificates for mTLS connections.
Deploying SPIRE operands for Red Hat OpenShift Service Mesh integration¶
Deploy SPIRE operands by creating the ZeroTrustWorkloadIdentityManager custom resource (CR) and related SPIRE operand CRs together. A running SPIRE deployment is required before you configure Red Hat OpenShift Service Mesh to use SPIRE-issued certificates for workload mTLS.
Prerequisites
- You have installed Zero Trust Workload Identity Manager.
- The OpenShift CLI (
oc) is configured with access to the cluster. - You have permissions to create custom resources in the
zero-trust-workload-identity-managernamespace.
Procedure
-
Set the environment variables by running the following commands:
-
Deploy all SPIRE operand CRs, including the
ZeroTrustWorkloadIdentityManagerCR:-
Create the
ZeroTrustWorkloadIdentityManagerCR:$ oc apply -f - <<EOF apiVersion: operator.openshift.io/v1alpha1 kind: ZeroTrustWorkloadIdentityManager metadata: name: cluster labels: app.kubernetes.io/name: zero-trust-workload-identity-manager app.kubernetes.io/managed-by: zero-trust-workload-identity-manager spec: trustDomain: ${TRUST_DOMAIN} clusterName: "" bundleConfigMap: "spire-bundle" EOF -
Create the
SpireServerCR:$ cat <<EOF | oc apply -f - apiVersion: operator.openshift.io/v1alpha1 kind: SpireServer metadata: name: cluster spec: logLevel: "info" logFormat: "text" jwtIssuer: $JWT_ISSUER caValidity: "24h" defaultX509Validity: "1h" defaultJWTValidity: "5m" caKeytype: “rsa-2048” jwtKeyType: "rsa-2048" keyManager: “” caSubject: country: "US" organization: "RH" commonName: "SPIRE Server CA" persistence: size: "5Gi" accessMode: "ReadWriteOnce" datastore: databaseType: "sqlite3" connectionString: "/run/spire/data/datastore.sqlite3" tlsSecretName: "" maxOpenConns: 100 maxIdleConns: 10 connMaxLifetime: 0 disableMigration: "false" EOF -
Wait for the SPIRE Server to become ready by running the following commands:
-
Create the
SpireAgentCR:$ cat <<EOF | oc apply -f - apiVersion: operator.openshift.io/v1alpha1 kind: SpireAgent metadata: name: cluster spec: socketPath: "/run/spire/agent-sockets" logLevel: "info" logFormat: "text" nodeAttestor: k8sPSATEnabled: "true" workloadAttestors: k8sEnabled: "true" workloadAttestorsVerification: type: "auto" hostCertBasePath: "/etc/kubernetes" hostCertFileName: "kubelet-ca.crt" disableContainerSelectors: "false" useNewContainerLocator: "true" EOF -
Wait for the SPIRE Agent to become ready by running the following commands:
-
Deploy the
SpiffeCSIDriverCR: -
Wait for the SPIFFE CSI Driver to become ready by running the following commands:
-
Deploy the
SpireOIDCDiscoveryProviderCR: -
Wait for the OIDC Discovery Provider to be created by running the following commands:
-
Verification
-
Verify that Zero Trust Workload Identity Manager is installed:
-
Deploy the client workload and try to fetch a workload SVID:
$ cat <<EOF | oc apply -f - apiVersion: apps/v1 kind: Deployment metadata: name: ztwim-client namespace: default labels: app: ztwim-client spec: selector: matchLabels: app: ztwim-client template: metadata: labels: app: ztwim-client spec: containers: - name: client image: ghcr.io/spiffe/spire-agent:1.5.1 command: ["/opt/spire/bin/spire-agent"] args: [ "api", "watch", "-socketPath", "/run/spire/sockets/spire-agent.sock" ] volumeMounts: - mountPath: /run/spire/sockets name: spiffe-workload-api readOnly: true volumes: - name: spiffe-workload-api csi: driver: csi.spiffe.io readOnly: true EOF -
Wait for the client deployment to become ready by running the following command:
-
-
Verify that the x509 SVID is available by running the following command:
$ oc exec -it \ "$(oc get \ pods -o=jsonpath='{.items[0].metadata.name}' \ -l app=ztwim-client \ -n default \ )" -n default -- \ /opt/spire/bin/spire-agent \ api fetch -socketPath /run/spire/sockets/spire-agent.sockThe expected output is an SVID like the following example:
-
Verify that the JSON Web Token (JWT) SVID is available by running the following command:
$ oc exec -it \ "$(oc get \ pods -o=jsonpath='{.items[0].metadata.name}' \ -l app=ztwim-client \ -n default \ )" -n default -- \ /opt/spire/bin/spire-agent \ api fetch jwt -audience=sample-aud -socketPath /run/spire/sockets/spire-agent.sockThe expected output is a JWT SVID like the following example:
-
Remove the client workload by running the following command:
Deploying Red Hat OpenShift Service Mesh for SPIRE integration¶
Deploy Red Hat OpenShift Service Mesh by creating the IstioCNI and Istio CRs with SPIRE integration settings so Envoy sidecars obtain SPIRE-issued certificates for workload mTLS after the SPIRE stack is running.
Prerequisites
- You have installed Zero Trust Workload Identity Manager.
- The OpenShift CLI (
oc) is configured with access to the cluster. - You have permissions to create namespaces and custom resources in the
istio-cniandistio-systemnamespaces. - You have permissions to read secrets in the
zero-trust-workload-identity-managernamespace.
Procedure
-
Set the Istio environment variables by running the following commands:
$ export ZTWIM_NS=zero-trust-workload-identity-manager $ export TRUST_DOMAIN=ocp.one $ 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/^/ /')" -
Create the
IstioCNICR to deploy Istio CNI by running the following commands:$ oc apply -f - <<EOF apiVersion: sailoperator.io/v1 kind: IstioCNI metadata: name: default spec: version: <version> namespace: ${OSSM_CNI} EOFwhere:
spec.version- Replace
<version>with the Istio version supported by your Red Hat OpenShift Service Mesh Operator. You can find supported versions by runningoc get IstioCNI -o jsonpath='{.items[*].spec.version}'after the Operator is installed.
-
Wait for Istio CNI to become ready by running the following commands:
The
untilloop waits for the Red Hat OpenShift Service Mesh Operator to create theistio-cni-nodeDaemonSet. Theoc rollout statuscommand waits for the DaemonSet pods to become ready. -
Install the Istio CR with SPIRE integration by running the following commands:
$ 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 for all of the resources to become ready by running the following commands:
Verification
-
Verify that Istio is integrated with SPIRE:
-
Create a test workload with the
spireinjection template by running the following commands: -
Enable the sidecar injection by running the following command:
-
Create the
httpbinworkload:$ 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: "test-audience" labels: app: httpbin version: v1 spec: containers: - image: docker.io/mccutchen/go-httpbin:v2.15.0 imagePullPolicy: IfNotPresent name: httpbin ports: - containerPort: 8080 EOF -
Wait for all of the resources to become ready by running the following commands:
-
Verify the SPIRE workload identity by running the following command:
$ 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 SPIREIf you see
SPIREin bothIssuerandSubject, the integration is working. Envoy is getting its certificates from SPIRE, not from Istio’s built-in CA. -
Remove the namespace by running the following command:
-