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) |
Important
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:
apiVersion: 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
-
- Example 2: Using manual certificate management with cert-manager
-
The following example shows how to configure federation using externally managed certificates:
apiVersion: 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
-
- Example 3: Using https_spiffe profile for SPIRE-to-SPIRE federation
-
The following example shows how to configure federation using SPIFFE-based TLS authentication:
apiVersion: 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.
-
- Example 4: Mixed federation with multiple authentication profiles
-
The following example shows a cluster federating with multiple remote clusters using different authentication profiles:
apiVersion: 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.
-
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.
-
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.
-
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 SVIDs (SPIFFE Verifiable Identity Documents).apiVersion: operator.openshift.io/v1alpha1 kind: SpireServer metadata: name: cluster spec: trustDomain: cluster1.example.com federation: bundleEndpoint: profile: https_spiffe refreshHint: 300 managedRoute: "true"-
The
trustDomainfield sets a unique trust domain for each cluster. -
The
profilefield uses thehttps_spiffeprofile for SPIFFE-based TLS authentication. -
The
refreshHintfield suggests intervals (in seconds) for remote servers to refresh the trust bundle. Range: 60-3600 seconds. -
The
managedRoutefield enables automatic route creation by the Operator.
-
-
Apply the configuration changes by running the following command:
$ 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.$ oc get spireserver cluster -w -
Verify that the federation route has been created:
$ 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:
$ curl -k https://federation.apps.cluster2.example.com > cluster2-bundle.jsonNote
For
https_spiffeprofile, you might need to use-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:
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_spiffe endpointSPIFFEID: spiffe://cluster2.example.com/spire/server trustDomainBundle: | { "keys": [ { "use": "x509-svid", "kty": "RSA", "n": "...", "e": "AQAB", "x5c": ["..."] } ], "spiffe_sequence": 1 }-
The
endpointSPIFFEIDfield contains the SPIFFE ID of the remote SPIRE server. Required forhttps_spiffeprofile to validate the remote server’s identity. -
The
trustDomainBundlecontains the complete trust bundle JSON that you fetched in the previous step.
-
-
-
Apply the
ClusterFederatedTrustDomainresource by running the following command:$ 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:apiVersion: 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
federatesWithfield lists all remote trust domains this cluster should federate with.
-
-
Apply the updated configuration by running the following command:
$ oc apply -f spireserver.yaml
-
Verify that the
ClusterFederatedTrustDomainresources have been created by running the following command:$ 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:$ 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:
$ 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:
$ 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.
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.
-
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.
-
Configure the
SpireServercustom resource on each cluster to enable federation with ACME certificate management.Create or update your
SpireServerresource with the federation configuration:apiVersion: 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
trustDomainfield sets a unique trust domain for each cluster (for example,cluster1.example.com,cluster2.example.com). -
The
profilefield uses thehttps_webprofile for ACME-based certificate management. -
The
directoryUrlfield contains the Let’s Encrypt production directory URL. For testing, use:https://acme-staging-v02.api.letsencrypt.org/directory. -
The
domainNamefield is the domain name where your federation endpoint is accessible. This automatically sets tofederation.<cluster-apps-domain>ifmanagedRouteis set to "true". -
The
emailfield is your email address for ACME account registration and certificate expiration notifications. -
The
tosAcceptedfield accepts the Let’s Encrypt Terms of Service. -
The
managedRoutefield enables an automatic route creation by the operator for the federation bundle endpoint.
-
-
Apply the configuration to each cluster by running the following command:
$ 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.$ oc get spireserver cluster -wExample outputNAME STATUS AGE cluster Ready 5m -
Verify that the federation route has been created by running the following command:
$ 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:
$ 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:
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 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 trustDomainBundle: | { "keys": [...], "spiffe_sequence": 1 }-
The
trustDomainBundlefield contains the complete trust bundle JSON that you fetched usingcurlin step 5.
-
-
-
Apply the
ClusterFederatedTrustDomainresources by running the following command:$ 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:apiVersion: 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
federatesWithfield lists all remote trust domains this cluster should federate with.
-
-
Apply the updated configuration by running the following command:
$ oc apply -f spireserver.yaml
-
Verify that the
ClusterFederatedTrustDomainresources have been created by running the following command:$ 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:$ 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:
$ 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:
$ 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:
$ 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.
-
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.
-
Install the cert-manager Operator on the cluster where you want to use externally managed certificates.
Create a namespace and install the operator:
apiVersion: 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:
$ oc apply -f cert-manager-install.yaml -
Check the status of the cert-manager Operator by entering the following command:
$ 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:
apiVersion: 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:
apiVersion: 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:
$ 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:$ 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.comNote
The 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:
apiVersion: 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.
-
-
Apply the Certificate resource by running the following command:
$ oc apply -f certificate.yaml -
Monitor the certificate issuance by running the following command:
$ 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:
$ 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:$ 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:
apiVersion: 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.
-
-
Apply the configuration by running the following command:
$ oc apply -f spireserver.yaml -
Wait for the SPIRE Server to be ready:
$ 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:
$ 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:
$ 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:
$ 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:apiVersion: 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 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 trustDomainBundle: | { "keys": [...], "spiffe_sequence": 1 }-
The
trustDomainBundlefield contains the complete trust bundle JSON that you fetched in the previous step.
-
-
Apply the
ClusterFederatedTrustDomainresources by running the following command:$ oc apply -f clusterfederatedtrustdomains.yaml -
Update the
SpireServerresource to add thefederatesWithconfiguration:apiVersion: 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.
-
-
Apply the updated configuration by running the following command:
$ 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
-
-
Verify that the certificate has been issued successfully by running the following command:
$ 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:
$ 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:
$ 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:
$ 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:$ 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:$ 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:
$ 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 correctly
$ 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:
$ 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 |
|---|---|---|---|---|
|
object |
Yes |
N/A |
Configuration for this cluster’s federation endpoint that exposes the trust bundle to remote clusters. |
|
array |
No |
|
List of remote trust domains to federate with. |
|
string |
No |
|
Enable or disable automatic OpenShift Route creation. Set to |
- bundleEndpoint configuration fields
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
|
string (enum) |
Yes |
|
Authentication profile for the bundle endpoint. Valid values: |
|
integer |
No |
|
Suggested interval (in seconds) for remote servers to refresh the trust bundle. Valid range: 60-3600. |
|
object |
Conditional |
N/A |
Required when |
- httpsWeb configuration fields
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
|
object |
Conditional |
N/A |
ACME configuration for automatic certificate management. Mutually exclusive with |
|
object |
Conditional |
N/A |
Manual certificate configuration. Mutually exclusive with |
- ACME configuration fields
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
|
string |
Yes |
N/A |
ACME directory URL. For Let’s Encrypt production: |
|
string |
Yes |
N/A |
Fully qualified domain name for the certificate. Typically the federation endpoint hostname. |
|
string |
Yes |
N/A |
Email address for ACME account registration and certificate expiration notifications. |
|
string |
No |
|
Accept the ACME provider’s Terms of Service. Must be |
- servingCert configuration fields
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
|
integer |
No |
|
Interval (in seconds) to check for certificate updates. Valid range: 3600-7776000 (1 hour to 90 days). |
|
string |
Yes |
N/A |
Name of the Kubernetes Secret containing the TLS certificate ( |
- federatesWith configuration fields
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
|
string |
Yes |
N/A |
Trust domain name of the remote SPIRE deployment (for example, |
|
string |
Yes |
N/A |
HTTPS URL of the remote federation endpoint (for example, |
|
string (enum) |
Yes |
N/A |
Authentication profile of the remote endpoint. Valid values: |
|
string |
Conditional |
N/A |
SPIFFE ID of the remote SPIRE server (for example, |
- 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 seconds -
fileSyncInterval: 3600-7776000 seconds
-
-