Zero Trust Workload Identity Manager SPIRE federation
Configure SPIRE federation to enable workloads in different trust domains to securely authenticate each other across clusters, cloud providers, and organizational boundaries. By establishing trust relationships between separate SPIRE deployments, you can build a zero-trust architecture that spans multiple environments without compromising security or sharing secrets.
Federation works by securely sharing trust bundles between SPIRE servers through dedicated federation endpoints. Each SPIRE deployment maintains its own trust domain and cryptographic identity, while being able to verify identities from federated trust domains. This approach enables cross-cluster communication, multi-cloud deployments, and secure integration with external partners.
Setting up SPIRE federation involves the following high-level steps:
- Choose an authentication profile: Select either
https_spiffeorhttps_web. - Configure the bundle endpoints: Each cluster exposes its trust bundle through a federation endpoint secured by the chosen authentication profile.
- Bootstrap the initial trust: Manually fetch and configure the initial trust bundle from each remote cluster.
- Establish federation relationships: Create
ClusterFederatedTrustDomainresources to define which clusters trust each other. - Configure automatic synchronization: The SPIRE Controller Manager automatically keeps trust bundles synchronized after initial setup.
Understanding bundle endpoint profiles
The bundle endpoint profile determines how your cluster exposes its trust bundle to other SPIRE deployments and how it authenticates remote clusters accessing the bundle. Choose the profile that best matches your security requirements and infrastructure.
The Zero Trust Workload Identity Manager supports two authentication profiles for federation:
- https_spiffe
Uses SPIFFE-based TLS authentication. The SPIRE server presents its own SVID (SPIFFE Verifiable Identity Document) to authenticate itself to remote SPIRE servers. This profile provides strong cryptographic identity verification and is ideal for federation between SPIRE deployments.
- https_web
Uses standard Web PKI (X.509 certificates from public or private certificate Authorities). This profile supports both automatic certificate management via ACME (Let’s Encrypt) and manual certificate management using tools like cert-manager.
The following table summarizes the key differences between the two profiles:
| Criteria | https_spiffe | https_web |
|---|---|---|
| Authentication method | SPIFFE SVID (TLS) | X.509 certificate from CA |
| Certificate management | Automatic (SPIRE-managed) | ACME (automatic) or manual |
| Trust model | SPIFFE trust domain | Web PKI / CA trust |
| Best for | Internal SPIRE-to-SPIRE federation | External federation, public endpoints |
| Security level | Very high (cryptographic identity) | High (CA-based trust) |
| Setup complexity | Medium (requires SPIFFE IDs) | Low (ACME) to Medium (manual certs) |
After enablement, federation cannot be disabled. The bundle endpoint profile is immutable once configured. Changing the profile or disabling federation requires reinstallation of the system. However, peer configurations (federatesWith) remain dynamic and can be added or removed at any time. Plan your profile selection carefully based on your long-term federation requirements.
Federation configuration examples
The following examples demonstrate different SPIRE federation configurations. Use these as templates when setting up federation between your clusters.
- Example 1: Using ACME for automatic certificate management
The following example shows how to configure federation using Let’s Encrypt for automatic certificate provisioning and renewal:
yamlapiVersion: operator.openshift.io/v1alpha1 kind: SpireServer metadata: name: cluster spec: trustDomain: cluster1.example.com federation: bundleEndpoint: profile: https_web refreshHint: 300 httpsWeb: acme: directoryUrl: https://acme-v02.api.letsencrypt.org/directory domainName: federation.apps.cluster1.example.com email: admin@example.com tosAccepted: "true" federatesWith: - trustDomain: cluster2.example.com bundleEndpointUrl: https://federation.apps.cluster2.example.com bundleEndpointProfile: https_web - trustDomain: cluster3.example.com bundleEndpointUrl: https://federation.apps.cluster3.example.com bundleEndpointProfile: https_web managedRoute: "true"- The
profilefield useshttps_webprofile for Web PKI certificate-based authentication. - The
directoryURLfield is used for the production directory. For testing, use staging URLhttps://acme-staging-v02.api.letsencrypt.org/directory
- The
- Example 2: Using manual certificate management with cert-manager
The following example shows how to configure federation using externally managed certificates:
yamlapiVersion: operator.openshift.io/v1alpha1 kind: SpireServer metadata: name: cluster spec: trustDomain: cluster1.example.com federation: bundleEndpoint: profile: https_web refreshHint: 300 httpsWeb: servingCert: fileSyncInterval: 86400 externalSecretRef: spire-server-federation-tls federatesWith: - trustDomain: cluster2.example.com bundleEndpointUrl: https://federation.apps.cluster2.example.com bundleEndpointProfile: https_web - trustDomain: cluster3.example.com bundleEndpointUrl: https://federation.apps.cluster3.example.com bundleEndpointProfile: https_web managedRoute: "true"- The
fileSyncIntervalfield checks for certificate updates every 24 hours. - The
externalSecretReffield is the name of the Kubernetes Secret containingtls.crtandtls.key
- The
- Example 3: Using https_spiffe profile for SPIRE-to-SPIRE federation
The following example shows how to configure federation using SPIFFE-based TLS authentication:
yamlapiVersion: operator.openshift.io/v1alpha1 kind: SpireServer metadata: name: cluster spec: trustDomain: cluster1.example.com federation: bundleEndpoint: profile: https_spiffe refreshHint: 300 federatesWith: - trustDomain: cluster2.example.com bundleEndpointUrl: https://federation.apps.cluster2.example.com bundleEndpointProfile: https_spiffe endpointSpiffeId: spiffe://cluster2.example.com/spire/server - trustDomain: cluster3.example.com bundleEndpointUrl: https://federation.apps.cluster3.example.com bundleEndpointProfile: https_spiffe endpointSpiffeId: spiffe://cluster3.example.com/spire/server managedRoute: "true"- The
profilefield useshttps_spiffeprofile for SPIFFE-based TLS authentication. - The
endpointSiffeIdfield contains the SPIFFE ID of the remote SPIRE server, required for identity validation.
- The
- Example 4: Mixed federation with multiple authentication profiles
The following example shows a cluster federating with multiple remote clusters using different authentication profiles:
yamlapiVersion: operator.openshift.io/v1alpha1 kind: SpireServer metadata: name: cluster spec: trustDomain: internal-cluster.example.com federation: bundleEndpoint: profile: https_spiffe refreshHint: 300 federatesWith: # Internal cluster using SPIFFE TLS - trustDomain: dev-cluster.example.com bundleEndpointUrl: https://federation.apps.dev-cluster.example.com bundleEndpointProfile: https_spiffe endpointSpiffeId: spiffe://dev-cluster.example.com/spire/server # External partner using Web PKI - trustDomain: partner.example.com bundleEndpointUrl: https://federation.partner.example.com bundleEndpointProfile: https_web # Another external partner using Web PKI - trustDomain: vendor.example.com bundleEndpointUrl: https://spire-federation.vendor.example.com bundleEndpointProfile: https_web managedRoute: "true"- The
profilefield cluster exposes its bundle usinghttps_spiffeprofile. - The
bundleEndpointProfilefield cluster exposes its bundle usinghttps_spiffeprofile.
- The
Configuring SPIRE federation with the https_spiffe profile
The Zero Trust Workload Identity Manager includes SPIRE Federation support, allowing multiple independent SPIRE deployments to establish trust relationships. This procedure demonstrates how to configure federation using the https_spiffe profile, which uses SPIFFE-based TLS authentication between SPIRE servers.
Prerequisites
- You have installed the OpenShift CLI (
oc). - You have installed the Zero Trust Workload Identity Manager on all clusters that will participate in the federation.
- You have
cluster-adminprivileges on all participating clusters. - You have network connectivity between the clusters you intend to federate.
Procedure
- Configure the
SpireServercustom resource on each cluster to enable federation with thehttps_spiffeprofile. Thehttps_spiffeprofile uses SPIFFE-based TLS authentication, where SPIRE servers authenticate to each other using their own SPIFFE Verifiable Identity Documents (SVIDs).yamlapiVersion: operator.openshift.io/v1alpha1 kind: SpireServer metadata: name: cluster spec: trustDomain: cluster1.example.com federation: bundleEndpoint: profile: https_spiffe refreshHint: 300 managedRoute: "true"- The
spec.trustDomainfield sets a unique trust domain for each cluster. - The
spec.federation.bundleEnpoint.profilefield uses thehttps_spiffeprofile for SPIFFE-based TLS authentication. - The
spec.federation.bundleEndpoint.refreshHintfield suggests intervals (in seconds) for remote servers to refresh the trust bundle. Range: 60-3600 seconds. - The
spec.federation.managedRoutefield enables automatic route creation by the Operator.
- The
- Apply the configuration changes by running the following command:terminal
$ oc apply -f spire-server.yaml - Check the status of the SPIRE Server by entering the following command. Wait for the
Readystatus to be returned.terminal$ oc get spireserver cluster -w - Verify that the federation route has been created:terminal
$ oc get route -n zero-trust-workload-identity-manager | grep federationExample outputNAME HOST/PORT PATH SERVICES PORT TERMINATION spire-server-federation federation.apps.cluster1.example.com spire-server 8443 passthrough - Fetch the trust bundle from each remote cluster’s federation endpoint:terminal
$ curl -k https://federation.apps.cluster2.example.com > cluster2-bundle.jsonNoteFor
https_spiffeprofile, you might need to use the-kflag if the certificate is not trusted by your system’s CA bundle:The response contains the trust bundle in JSON Web Key Set (JWKS) format:
Example trust bundle{ "keys": [ { "use": "x509-svid", "kty": "RSA", "n": "...", "e": "AQAB", "x5c": ["..."] } ], "spiffe_sequence": 1, "refresh_hint": 300 } - Create
ClusterFederatedTrustDomainresources for each remote trust domain.- On Cluster 1, create a resource to federate with Cluster 2:yaml
apiVersion: spire.spiffe.io/v1alpha1 kind: ClusterFederatedTrustDomain metadata: name: federation-to-cluster2 spec: trustDomain: <CLUSTER2_APPS_DOMAIN> bundleEndpointURL: https://federation.<CLUSTER2_APPS_DOMAIN> bundleEndpointProfile: type: https_spiffe endpointSPIFFEID: spiffe://<CLUSTER2_APPS_DOMAIN>/spire/server className: zero-trust-workload-identity-manager-spire trustDomainBundle: | { "keys": [ { "use": "x509-svid", "kty": "RSA", "n": "...", "e": "AQAB", "x5c": ["..."] } ], "spiffe_sequence": 1 }where
<CLUSTER2_APPS_DOMAIN>Specifies the trust domain of the external cluster you are federating with.
- On Cluster 1, create a resource to federate with Cluster 2:
spec.bundleEndpointProfile.endpointSPIFFEIDSpecifies the SPIFFE ID of the remote SPIRE server. Required for
https_spiffeprofile to validate the remote server’s identity.spec.trustDomainBundleSpecifies the complete trust bundle JSON that you fetched in the previous step.
spec.classNameSpecifies the name of a class to watch CRs for. Spire-controller-manager watches the resource only if
spec.classNameis set tozero-trust-workload-identity-manager-spire.
- Apply the
ClusterFederatedTrustDomainresource by running the following command:terminal$ oc apply -f clusterfederatedtrustdomain.yaml - Repeat steps 5-7 on each cluster for every remote cluster it should federate with. For bidirectional federation, each cluster needs a
ClusterFederatedTrustDomainresource for every other cluster. - Update the
SpireServerresource on each cluster to add thefederatesWithconfiguration:yamlapiVersion: operator.openshift.io/v1alpha1 kind: SpireServer metadata: name: cluster spec: trustDomain: cluster1.example.com federation: bundleEndpoint: profile: https_spiffe refreshHint: 300 federatesWith: - trustDomain: cluster2.example.com bundleEndpointUrl: https://federation.apps.cluster2.example.com bundleEndpointProfile: https_spiffe endpointSpiffeId: spiffe://cluster2.example.com/spire/server - trustDomain: cluster3.example.com bundleEndpointUrl: https://federation.apps.cluster3.example.com bundleEndpointProfile: https_spiffe endpointSpiffeId: spiffe://cluster3.example.com/spire/server managedRoute: "true"- The
spec.federation.federatesWithfield lists all remote trust domains this cluster should federate with.
- The
- Apply the updated configuration by running the following command:terminal
$ oc apply -f spireserver.yaml
Verification
- Verify that the
ClusterFederatedTrustDomainresources have been created by running the following command:terminal$ oc get clusterfederatedtrustdomainsExample outputNAME TRUST DOMAIN ENDPOINT URL AGE cluster2-federation cluster2.example.com https://federation.apps.cluster2.example.com 5m cluster3-federation cluster3.example.com https://federation.apps.cluster3.example.com 5m - Check the status of a
ClusterFederatedTrustDomainto ensure bundle synchronization is working by running the following command:terminal$ oc describe clusterfederatedtrustdomain cluster2-federationLook for successful status conditions indicating that the trust bundle has been synchronized.
- Verify that the federation endpoint is accessible by running the following command:terminal
$ curl https://federation.apps.cluster1.example.comYou should receive a JSON response containing the trust bundle.
- Check the SPIRE Server logs to confirm federation is active by running the following command:terminal
$ oc logs -n zero-trust-workload-identity-manager \ statefulset/spire-server -c spire-server --tail=50Look for log messages indicating successful bundle synchronization with federated trust domains.
Using SPIRE federation with Automatic Certificate Management Environment protocol
Using SPIRE federation with Automatic Certificate Management Environment (ACME) protocol provides automatic certificate provisioning from Let’s Encrypt. ACME also enables automatic certificate renewal before expiration, eliminating manual certificate management overhead.
Prerequisites
- You have installed the Zero Trust Workload Identity Manager on all clusters that will participate in the federation.
- You have installed the OpenShift CLI (
oc). - You have
cluster-adminprivileges on all participating clusters. - Your federation endpoints must be publicly accessible for Let’s Encrypt HTTP-01 challenge validation.
- You have network connectivity between all federated clusters.
Procedure
- Configure the
SpireServercustom resource on each cluster to enable federation with ACME certificate management.Create or update your
SpireServerresource with the federation configuration:yamlapiVersion: operator.openshift.io/v1alpha1 kind: SpireServer metadata: name: cluster spec: trustDomain: cluster1.example.com federation: bundleEndpoint: profile: https_web refreshHint: 300 httpsWeb: acme: directoryUrl: https://acme-v02.api.letsencrypt.org/directory domainName: federation.apps.cluster1.example.com email: admin@example.com tosAccepted: "true" managedRoute: "true"- The
spec.trustDomainfield sets a unique trust domain for each cluster (for example,cluster1.example.com,cluster2.example.com). - The
spec.federation.bundleEndpoint.profilefield uses thehttps_webprofile for ACME-based certificate management. - The
spec.federation.bundleEndpoint.httpsWeb.acme.directoryUrlfield contains the Let’s Encrypt production directory URL. For testing, use:https://acme-staging-v02.api.letsencrypt.org/directory. - The
spec.federation.bundleEndpoint.httpsWeb.acme.domainNamefield is the domain name where your federation endpoint is accessible. This automatically sets tofederation.<cluster-apps-domain>ifmanagedRouteis set to "true". - The
spec.federation.bundleEndpoint.httpsWeb.acme.emailfield is your email address for ACME account registration and certificate expiration notifications. - The
spec.federation.bundleEndpoint.httpsWeb.acme.tosAcceptedfield accepts the Let’s Encrypt Terms of Service. - The
spec.federation.managedRoutefield enables an automatic route creation by the operator for the federation bundle endpoint.
- The
- Apply the configuration to each cluster by running the following command:terminal
$ oc apply -f spireserver.yaml - Check the status of the SPIRE Server by entering the following command. Wait for the
Readystatus to be returned before proceeding to the next step.terminal$ oc get spireserver cluster -wExample outputNAME STATUS AGE cluster Ready 5m - Verify that the federation route has been created by running the following command:terminal
$ oc get route -n zero-trust-workload-identity-manager | grep federationExample outputNAME HOST/PORT PATH SERVICES PORT TERMINATION spire-server-federation federation.apps.cluster1.example.com spire-server 8443 passthrough - On each cluster, fetch the trust bundle from the federation endpoint by running the following command:terminal
$ curl https://federation.apps.cluster1.example.com > cluster1-bundle.jsonThe response contains the trust bundle in JSON Web Key Set (JWKS) format:
Example trust bundle{ "keys": [ { "use": "x509-svid", "kty": "RSA", "n": "...", "e": "AQAB", "x5c": ["..."] } ], "spiffe_sequence": 1, "refresh_hint": 300 } - Create
ClusterFederatedTrustDomainresources to establish federation relationships.- On Cluster 1, create resources to federate with Cluster 2 and Cluster 3:yaml
apiVersion: spire.spiffe.io/v1alpha1 kind: ClusterFederatedTrustDomain metadata: name: cluster2-federation spec: trustDomain: cluster2.example.com bundleEndpointURL: https://federation.apps.cluster2.example.com bundleEndpointProfile: type: https_web className: zero-trust-workload-identity-manager-spire trustDomainBundle: | { "keys": [...], "spiffe_sequence": 1 } --- apiVersion: spire.spiffe.io/v1alpha1 kind: ClusterFederatedTrustDomain metadata: name: cluster3-federation spec: trustDomain: cluster3.example.com bundleEndpointURL: https://federation.apps.cluster3.example.com bundleEndpointProfile: type: https_web className: zero-trust-workload-identity-manager-spire trustDomainBundle: | { "keys": [...], "spiffe_sequence": 1 }- The
spec.trustDomainBundlefield contains the complete trust bundle JSON that you fetched usingcurlin step 5. - The
spec.classNamefield contains the name of a class to watch CRs for. Spire-controller-manager watches the resource only ifspec.classNameis set tozero-trust-workload-identity-manager-spire.
- The
- On Cluster 1, create resources to federate with Cluster 2 and Cluster 3:
- Apply the
ClusterFederatedTrustDomainresources by running the following command:terminal$ oc apply -f cluster-federated-trust-domains.yaml - Repeat steps 6 and 7 on each cluster to establish bidirectional federation. Each cluster needs
ClusterFederatedTrustDomainresources for every other cluster it federates with. - Update the
SpireServerresource on each cluster to add thefederatesWithconfiguration:yamlapiVersion: operator.openshift.io/v1alpha1 kind: SpireServer metadata: name: cluster spec: # ... existing configuration ... federation: bundleEndpoint: # ... existing bundleEndpoint configuration ... federatesWith: - trustDomain: cluster2.example.com bundleEndpointUrl: https://federation.apps.cluster2.example.com bundleEndpointProfile: https_web - trustDomain: cluster3.example.com bundleEndpointUrl: https://federation.apps.cluster3.example.com bundleEndpointProfile: https_web managedRoute: "true"- The
spec.federation.federatesWithfield lists all remote trust domains this cluster should federate with.
- The
- Apply the updated configuration by running the following command:terminal
$ oc apply -f spireserver.yaml
Verification
- Verify that the
ClusterFederatedTrustDomainresources have been created by running the following command:terminal$ oc get clusterfederatedtrustdomainsExample outputNAME TRUST DOMAIN ENDPOINT URL AGE cluster2-federation cluster2.example.com https://federation.apps.cluster2.example.com 5m cluster3-federation cluster3.example.com https://federation.apps.cluster3.example.com 5m - Check the status of a
ClusterFederatedTrustDomainto ensure bundle synchronization is working by running the following command:terminal$ oc describe clusterfederatedtrustdomain cluster2-federationLook for
Successfulstatus conditions indicating that the trust bundle has been synchronized. - Verify that the federation endpoint is accessible and serving the trust bundle by running the following command:terminal
$ curl https://federation.apps.cluster1.example.comYou should receive a JSON response containing the trust bundle.
- Check the SPIRE Server logs to confirm federation is active by running the following command:terminal
$ oc logs -n zero-trust-workload-identity-manager deployment/spire-server -c spire-server --tail=50Look for log messages indicating successful bundle synchronization with federated trust domains.
- Verify that all SPIRE components are running by running the following command:terminal
$ oc get pods -n zero-trust-workload-identity-managerExample outputNAME READY STATUS RESTARTS AGE spire-agent-abcde 1/1 Running 0 10m spire-server-0 2/2 Running 0 10m - Optional: Test cross-cluster workload authentication by deploying workloads with SPIFFE identities on different clusters and verifying they can authenticate to each other using the federated trust.
Using SPIRE federation with manual certificate management
You can use SPIRE federation with custom certificate management using cert-manager or other certificate providers. This approach provides flexibility for organizations that require control over certificate issuance, support for internal certificate authorities (CAs), or integration with existing certificate management infrastructure.
Prerequisites
- You have installed the Zero Trust Workload Identity Manager on all clusters that will participate in the federation.
- You have installed the OpenShift CLI (
oc). - You have
cluster-adminprivileges on all participating clusters. - You have installed the cert-manager Operator for Red Hat OpenShift. For more information, see cert-manager Operator for Red Hat OpenShift.
- Your federation endpoints must be publicly accessible for certificate validation.
- You have network connectivity between all federated clusters.
Procedure
- Install the cert-manager Operator on the cluster where you want to use externally managed certificates.
Create a namespace and install the operator:
yamlapiVersion: v1 kind: Namespace metadata: name: cert-manager-operator --- apiVersion: operators.coreos.com/v1 kind: OperatorGroup metadata: name: openshift-cert-manager-operator namespace: cert-manager-operator spec: upgradeStrategy: Default --- apiVersion: operators.coreos.com/stable-v1 kind: Subscription metadata: name: openshift-cert-manager-operator namespace: cert-manager-operator spec: source: redhat-operators sourceNamespace: openshift-marketplace name: openshift-cert-manager-operator channel: stable-v1 - Apply the cert-manager installation by running the following command:terminal
$ oc apply -f cert-manager-install.yaml - Check the status of the cert-manager Operator by entering the following command:terminal
$ oc get pods -n cert-managerAll cert-manager pods should be in
Runningstatus. - Create an Issuer for certificate provisioning.
For Let’s Encrypt with HTTP-01 challenge:
yamlapiVersion: cert-manager.io/v1 kind: Issuer metadata: name: letsencrypt-http01 namespace: zero-trust-workload-identity-manager spec: acme: server: https://acme-v02.api.letsencrypt.org/directory privateKeySecretRef: name: letsencrypt-account-key solvers: - http01: ingress: ingressClassName: openshift-defaultAlternatively, for an internal CA:
yamlapiVersion: cert-manager.io/v1 kind: Issuer metadata: name: internal-ca namespace: zero-trust-workload-identity-manager spec: ca: secretName: internal-ca-key-pair - Apply the Issuer by running the following command:terminal
$ oc apply -f issuer.yaml - Determine the federation endpoint domain name.
The federation route follows a predictable naming pattern if
managedRouteis set totrue. Get your cluster’s application domain by running the following command:terminal$ CLUSTER_DOMAIN=$(oc get ingresses.config/cluster -o jsonpath='{.spec.domain}') $ FEDERATION_DOMAIN="federation.${CLUSTER_DOMAIN}" $ echo "Federation domain will be: $FEDERATION_DOMAIN"Example outputFederation domain will be: federation.apps.cluster1.example.comNoteThe federation route is created automatically if
managedRouteis set totruewhen you apply theSpireServerconfiguration in a later step. The route name isspire-server-federationand the hostname isfederation.<cluster-apps-domain>. - Create a Certificate resource to request a TLS certificate.
Use the federation domain determined in the previous step:
yamlapiVersion: cert-manager.io/v1 kind: Certificate metadata: name: spire-server-federation-tls namespace: zero-trust-workload-identity-manager spec: secretName: spire-server-federation-tls duration: 2160h renewBefore: 360h commonName: federation.apps.cluster1.example.com dnsNames: - federation.apps.cluster1.example.com usages: - server auth - digital signature - key encipherment issuerRef: kind: Issuer name: letsencrypt-http01- The
secretNamefield must match theexternalSecretRefvalue in SpireServer. - The
durationfield shows how long a certificate is valid. Certificates are valid for 90 days. - The
renewBeforefield shows how many days a certificate must be renewed before it expires. Renew a certificate 15 days before expiration. - The
commonNamefield must be replaced with your actual federation domain from the previous step. - The
dnsNamesfield must match thecommonNameand the actual routehostnamethat was created. - The
namefield must reference the Issuer that was created earlier.
- The
- Apply the Certificate resource by running the following command:terminal
$ oc apply -f certificate.yaml - Monitor the certificate issuance by running the following command:terminal
$ oc get certificate spire-server-federation-tls \ -n zero-trust-workload-identity-manager -wExample output when readyNAME READY SECRET AGE spire-server-federation-tls True spire-server-federation-tls 2m - Create RBAC permissions for the OpenShift Ingress Router to access the certificate secret.
Create a Role by running the following command:
terminal$ oc create role secret-reader \ --verb=get,list,watch \ --resource=secrets \ --resource-name=spire-server-federation-tls \ -n zero-trust-workload-identity-managerCreate a
RoleBindingby running the following command:terminal$ oc create rolebinding secret-reader-binding \ --role=secret-reader \ --serviceaccount=openshift-ingress:router \ -n zero-trust-workload-identity-manager - Configure the
SpireServercustom resource to use manual certificate management.Now that the certificate is ready, configure the SpireServer to reference it:
yamlapiVersion: operator.openshift.io/v1alpha1 kind: SpireServer metadata: name: cluster spec: trustDomain: cluster1.example.com federation: bundleEndpoint: profile: https_web refreshHint: 300 httpsWeb: servingCert: fileSyncInterval: 86400 externalSecretRef: spire-server-federation-tls managedRoute: "true"- The
profilefield must usehttps_webprofile for certificate-based authentication. - The
fileSyncIntervalfield checks for certificate updates every 24 hours (86400 seconds). Range: 3600-7776000 seconds. - The
externalSecretReffield is the name of the secret containing the TLS certificate and private key. Must match the certificate secret created in the previous steps.
- The
- Apply the configuration by running the following command:terminal
$ oc apply -f spireserver.yaml - Wait for the SPIRE Server to be ready:terminal
$ oc get spireserver cluster -n zero-trust-workload-identity-manager -wWait until the status shows
Ready. - Verify that the federation route was created by running the following command:terminal
$ oc get route spire-server-federation -n zero-trust-workload-identity-managerExample outputNAME HOST/PORT PATH SERVICES PORT TERMINATION spire-server-federation federation.apps.cluster1.example.com spire-server 8443 reencryptVerify that the route hostname matches the domain name used in your certificate.
- Verify that the federation endpoint is accessible by running the following command:terminal
$ curl https://$(oc get route spire-server-federation \ -n zero-trust-workload-identity-manager \ -o jsonpath='{.spec.host}')You should receive a JSON response containing the trust bundle.
- Fetch the trust bundle from each federation endpoint that you want to federate with.
For each remote cluster, fetch its trust bundle by running the following commands:
terminal$ curl https://federation.apps.cluster1.example.com > cluster1-bundle.json $ curl https://federation.apps.cluster2.example.com > cluster2-bundle.jsonThe trust bundle is in JSON Web Key Set (JWKS) format:
Example trust bundle{ "keys": [ { "use": "x509-svid", "kty": "RSA", "n": "xGOzB...", "e": "AQAB", "x5c": ["MIIC..."] } ], "spiffe_sequence": 1, "refresh_hint": 300 } - Create
ClusterFederatedTrustDomainresources for each remote trust domain you want to federate with:yamlapiVersion: spire.spiffe.io/v1alpha1 kind: ClusterFederatedTrustDomain metadata: name: cluster1-federation spec: trustDomain: cluster1.example.com bundleEndpointURL: https://federation.apps.cluster1.example.com bundleEndpointProfile: type: https_web className: zero-trust-workload-identity-manager-spire trustDomainBundle: | { "keys": [ { "use": "x509-svid", "kty": "RSA", "n": "xGOzB...", "e": "AQAB", "x5c": ["MIIC..."] } ], "spiffe_sequence": 1 } --- apiVersion: spire.spiffe.io/v1alpha1 kind: ClusterFederatedTrustDomain metadata: name: cluster2-federation spec: trustDomain: cluster2.example.com bundleEndpointURL: https://federation.apps.cluster2.example.com bundleEndpointProfile: type: https_web className: zero-trust-workload-identity-manager-spire trustDomainBundle: | { "keys": [...], "spiffe_sequence": 1 }- The
trustDomainBundlefield contains the complete trust bundle JSON that you fetched in the previous step. - The
spec.classNamefield contains the name of a class to watch CRs for. Spire-controller-manager watches the resource only ifspec.classNameis set tozero-trust-workload-identity-manager-spire.
- The
- Apply the
ClusterFederatedTrustDomainresources by running the following command:terminal$ oc apply -f clusterfederatedtrustdomains.yaml - Update the
SpireServerresource to add thefederatesWithconfiguration:yamlapiVersion: operator.openshift.io/v1alpha1 kind: SpireServer metadata: name: cluster spec: trustDomain: cluster3.example.com federation: bundleEndpoint: profile: https_web refreshHint: 300 httpsWeb: servingCert: fileSyncInterval: 86400 externalSecretRef: spire-server-federation-tls federatesWith: - trustDomain: cluster1.example.com bundleEndpointUrl: https://federation.apps.cluster1.example.com bundleEndpointProfile: https_web - trustDomain: cluster2.example.com bundleEndpointUrl: https://federation.apps.cluster2.example.com bundleEndpointProfile: https_web managedRoute: "true"- The
federatesWithfield lists all remote trust domains this cluster should federate with.
- The
- Apply the updated configuration by running the following command:terminal
$ oc apply -f spireserver.yaml - Repeat steps 1-15 on each cluster that participates in the federation, ensuring that:
- Each cluster has cert-manager installed and configured
- Each cluster has its own certificate created and ready before applying the
SpireServerconfiguration - Each cluster has the RBAC for the ingress router configured
- Each cluster has
ClusterFederatedTrustDomainresources for every other cluster it federates with - Each cluster’s
SpireServerhas the completefederatesWithlist
Verification
- Verify that the certificate has been issued successfully by running the following command:terminal
$ oc get certificate spire-server-federation-tls \ -n zero-trust-workload-identity-managerExample outputNAME READY SECRET AGE spire-server-federation-tls True spire-server-federation-tls 5m - Check the certificate details and expiration by running the following command:terminal
$ oc get secret spire-server-federation-tls \ -n zero-trust-workload-identity-manager \ -o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -noout -datesExample outputnotBefore=Dec 16 10:00:00 2025 GMT notAfter=Mar 16 10:00:00 2026 GMT - Verify that the RBAC permissions are configured correctly by running the following command:terminal
$ oc get role,rolebinding -n zero-trust-workload-identity-manager \ | grep secret-readerExample outputrole.rbac.authorization.k8s.io/secret-reader rolebinding.rbac.authorization.k8s.io/secret-reader-bindingVerify the RoleBinding references the correct ServiceAccount by running the following command:
terminal$ oc describe rolebinding secret-reader-binding \ -n zero-trust-workload-identity-managerExample outputName: secret-reader-binding Namespace: zero-trust-workload-identity-manager Role: Kind: Role Name: secret-reader Subjects: Kind Name Namespace ---- ---- --------- ServiceAccount router openshift-ingress - Verify that the
ClusterFederatedTrustDomainresources have been created by running the following command:terminal$ oc get clusterfederatedtrustdomainsExample outputNAME TRUST DOMAIN ENDPOINT URL AGE cluster1-federation cluster1.example.com https://federation.apps.cluster1.example.com 5m cluster2-federation cluster2.example.com https://federation.apps.cluster2.example.com 5m - Check the status of a
ClusterFederatedTrustDomainto ensure bundle synchronization is working by running the following command:terminal$ oc describe clusterfederatedtrustdomain cluster1-federationLook for successful status conditions indicating that the trust bundle has been synchronized.
- Verify that the federation endpoint is accessible and using the correct certificate by running the following command:terminal
$ curl -v https://$(oc get route spire-server-federation \ -n zero-trust-workload-identity-manager \ -o jsonpath='{.spec.host}')In the output, verify that the certificate presented is issued by your configured CA (Let’s Encrypt or internal CA).
- Check the SPIRE Server logs to confirm that by running the following command:
- Federation is active with remote trust domains
- Trust bundles are being synchronized
- The bundle endpoint is serving correctlyterminal
$ oc logs -n zero-trust-workload-identity-manager \ statefulset/spire-server -c spire-server --tail=100Look for log messages indicating successful federation bundle synchronization.
- Verify that all SPIRE components are running by running the following command:terminal
$ oc get pods -n zero-trust-workload-identity-managerExample outputNAME READY STATUS RESTARTS AGE spire-agent-abc123 1/1 Running 0 10m spire-server-0 2/2 Running 0 10m - Optional: Test cross-cluster workload authentication by deploying workloads with SPIFFE identities on different clusters and verifying they can authenticate to each other using the federated trust.
Federation configuration field reference
This reference provides detailed information about all configuration fields available for SPIRE federation in the SpireServer custom resource. Use this reference when customizing your federation setup.
- Top-level federation fields
Field Type Required Default Description federation.bundleEndpointobject Yes N/A Configuration for this cluster’s federation endpoint that exposes the trust bundle to remote clusters. federation.federatesWitharray No []List of remote trust domains to federate with. federation.managedRoutestring No "true"Enable or disable automatic OpenShift Route creation. Set to "true"for operator-managed routes or"false"for manual route management.- bundleEndpoint configuration fields
Field Type Required Default Description federation.bundleEndpoint.profilestring (enum) Yes https_spiffeAuthentication profile for the bundle endpoint. Valid values: https_spiffeorhttps_web. This value is immutable after initial configuration.federation.bundleEndpoint.refreshHintinteger No 300Suggested interval (in seconds) for remote servers to refresh the trust bundle. Valid range: 60-3600. federation.bundleEndpoint.httpsWebobject Conditional N/A Required when profileishttps_web. Contains certificate configuration.- httpsWeb configuration fields
Field Type Required Default Description federation.bundleEndpoint.httpsWeb.acmeobject Conditional N/A ACME configuration for automatic certificate management. Mutually exclusive with servingCert.federation.bundleEndpoint.httpsWeb.servingCertobject Conditional N/A Manual certificate configuration. Mutually exclusive with acme.- ACME configuration fields
Field Type Required Default Description federation.bundleEndpoint.httpsWeb.acme.directoryUrlstring Yes N/A ACME directory URL. For Let’s Encrypt production: https://acme-v02.api.letsencrypt.org/directory. For staging:https://acme-staging-v02.api.letsencrypt.org/directoryfederation.bundleEndpoint.httpsWeb.acme.domainNamestring Yes N/A Fully qualified domain name for the certificate. Typically the federation endpoint hostname. federation.bundleEndpoint.httpsWeb.acme.emailstring Yes N/A Email address for ACME account registration and certificate expiration notifications. federation.bundleEndpoint.httpsWeb.acme.tosAcceptedstring No "false"Accept the ACME provider’s Terms of Service. Must be "true"to obtain certificates.- servingCert configuration fields
Field Type Required Default Description federation.bundleEndpoint.httpsWeb.servingCert.fileSyncIntervalinteger No 86400Interval (in seconds) to check for certificate updates. Valid range: 3600-7776000 (1 hour to 90 days). federation.bundleEndpoint.httpsWeb.servingCert.externalSecretRefstring Yes N/A Name of the Kubernetes Secret containing the TLS certificate ( tls.crt) and private key (tls.key) for the federation route.- federatesWith configuration fields
Field Type Required Default Description federation.federatesWith[].trustDomainstring Yes N/A Trust domain name of the remote SPIRE deployment (for example, cluster2.example.com).federation.federatesWith[].bundleEndpointUrlstring Yes N/A HTTPS URL of the remote federation endpoint (for example, https://federation.apps.cluster2.example.com).federation.federatesWith[].bundleEndpointProfilestring (enum) Yes N/A Authentication profile of the remote endpoint. Valid values: https_spiffeorhttps_web.federation.federatesWith[].endpointSpiffeIdstring Conditional N/A SPIFFE ID of the remote SPIRE server (for example, spiffe://cluster2.example.com/spire/server). Required whenbundleEndpointProfileishttps_spiffe.- Field validation rules
The following validation rules are enforced by the operator:
- Profile immutability: The
bundleEndpoint.profilefield cannot be changed after initial configuration. Changing it requires deleting and recreating theSpireServerresource (re-installation of the system). - Mutual exclusivity: Within
httpsWeb, only one ofacmeorservingCertcan be specified. - Conditional requirements: When
profileishttps_web, thehttpsWebobject must be present with eitheracmeorservingCertconfigured. - SPIFFE ID requirement: When
bundleEndpointProfileishttps_spiffein thefederatesWithlist, theendpointSpiffeIdfield is required. - Array limits: The
federatesWitharray supports a maximum of 50 entries. - Numeric ranges:
refreshHint: 60-3600 secondsfileSyncInterval: 3600-7776000 seconds
- Profile immutability: The