1
0
mirror of https://github.com/openshift/openshift-docs.git synced 2026-02-05 12:46:18 +01:00

Merge pull request #104191 from openshift-cherrypick-robot/cherry-pick-103787-to-enterprise-4.21

[enterprise-4.21] OSDOCS-17246 created doc for spire federation
This commit is contained in:
Steven Smith
2025-12-18 14:38:39 -05:00
committed by GitHub
11 changed files with 1540 additions and 22 deletions

View File

@@ -1243,6 +1243,8 @@ Topics:
File: zero-trust-manager-configuration
- Name: Configuring Zero Trust Workload Identity Manager OIDC Federation
File: zero-trust-manager-oidc-federation
- Name: Configuring Zero Trust Workload Identity Manager SPIRE Federation
File: zero-trust-manager-spire-federation
- Name: Enabling create-only mode for the Zero Trust Workload Identity Manager
File: zero-trust-manager-reconciliation
- Name: Monitoring Zero Trust Workload Identity Manager

View File

@@ -0,0 +1,269 @@
// Module included in the following assemblies:
//
// * security/zero_trust_workload_identity_manager/zero-trust-manager-spire-federation.adoc
:_mod-docs-content-type: PROCEDURE
[id="zero-trust-manager-automatic-management_{context}"]
= Using SPIRE federation with Automatic Certificate Management Environment protocol
[role="_abstract"]
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-full} on all clusters that will participate in the federation.
* You have installed the OpenShift CLI (`oc`).
* You have `cluster-admin` privileges 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 `SpireServer` custom resource on each cluster to enable federation with ACME certificate management.
+
Create or update your `SpireServer` resource with the federation configuration:
+
[source,yaml]
----
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 `trustDomain` field sets a unique trust domain for each cluster (for example, `cluster1.example.com`, `cluster2.example.com`).
* The `profile` field uses the `https_web` profile for ACME-based certificate management.
* The `directoryUrl` field contains the Let's Encrypt production directory URL. For testing, use: `https://acme-staging-v02.api.letsencrypt.org/directory`.
* The `domainName` field is the domain name where your federation endpoint is accessible. This automatically sets to `federation.<cluster-apps-domain>` if `managedRoute` is set to "true".
* The `email` field is your email address for ACME account registration and certificate expiration notifications.
* The `tosAccepted` field accepts the Let's Encrypt Terms of Service.
* The `managedRoute` field enables an automatic route creation by the operator for the federation bundle endpoint.
. Apply the configuration to each cluster by running the following command:
+
[source,terminal]
----
$ oc apply -f spireserver.yaml
----
. Check the status of the SPIRE Server by entering the following command. Wait for the `Ready` status to be returned before proceeding to the next step.
+
[source,terminal]
----
$ oc get spireserver cluster -w
----
+
.Example output
[source,terminal]
----
NAME STATUS AGE
cluster Ready 5m
----
. Verify that the federation route has been created by running the following command:
+
[source,terminal]
----
$ oc get route -n zero-trust-workload-identity-manager | grep federation
----
+
.Example output
[source,terminal]
----
NAME 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:
+
[source,terminal]
----
$ curl https://federation.apps.cluster1.example.com > cluster1-bundle.json
----
+
The response contains the trust bundle in JSON Web Key Set (JWKS) format:
+
.Example trust bundle
[source,json]
----
{
"keys": [
{
"use": "x509-svid",
"kty": "RSA",
"n": "...",
"e": "AQAB",
"x5c": ["..."]
}
],
"spiffe_sequence": 1,
"refresh_hint": 300
}
----
. Create `ClusterFederatedTrustDomain` resources to establish federation relationships.
+
.. On Cluster 1, create resources to federate with Cluster 2 and Cluster 3:
+
[source,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
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 `trustDomainBundle` field contains the complete trust bundle JSON that you fetched using `curl` in step 5.
. Apply the `ClusterFederatedTrustDomain` resources by running the following command:
+
[source,terminal]
----
$ oc apply -f cluster-federated-trust-domains.yaml
----
. Repeat steps 6 and 7 on each cluster to establish bidirectional federation. Each cluster needs `ClusterFederatedTrustDomain` resources for every other cluster it federates with.
. Update the `SpireServer` resource on each cluster to add the `federatesWith` configuration:
+
[source,yaml]
----
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 `federatesWith` field lists all remote trust domains this cluster should federate with.
. Apply the updated configuration by running the following command:
+
[source,terminal]
----
$ oc apply -f spireserver.yaml
----
.Verification
. Verify that the `ClusterFederatedTrustDomain` resources have been created by running the following command:
+
[source,terminal]
----
$ oc get clusterfederatedtrustdomains
----
+
.Example output
[source,terminal]
----
NAME 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 `ClusterFederatedTrustDomain` to ensure bundle synchronization is working by running the following command:
+
[source,terminal]
----
$ oc describe clusterfederatedtrustdomain cluster2-federation
----
+
Look for `Successful` status 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:
+
[source,terminal]
----
$ curl https://federation.apps.cluster1.example.com
----
+
You should receive a JSON response containing the trust bundle.
. Check the SPIRE Server logs to confirm federation is active by running the following command:
+
[source,terminal]
----
$ oc logs -n zero-trust-workload-identity-manager deployment/spire-server -c spire-server --tail=50
----
+
Look for log messages indicating successful bundle synchronization with federated trust domains.
. Verify that all SPIRE components are running by running the following command:
+
[source,terminal]
----
$ oc get pods -n zero-trust-workload-identity-manager
----
+
.Example output
[source,terminal]
----
NAME 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.

View File

@@ -0,0 +1,152 @@
// Module included in the following assemblies:
//
// * security/zero_trust_workload_identity_manager/zero-trust-manager-spire-federation.adoc
:_mod-docs-content-type: REFERENCE
[id="zero-trust-manager-config-example_{context}"]
= Federation configuration examples
[role="_abstract"]
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:
+
[source,yaml]
----
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 `profile` field uses `https_web` profile for Web PKI certificate-based authentication.
* The `directoryURL` field is used for the production directory. For testing, use staging URL `https://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:
+
[source,yaml]
----
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 `fileSyncInterval` field checks for certificate updates every 24 hours.
* The `externalSecretRef` field is the name of the Kubernetes Secret containing `tls.crt` and `tls.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:
+
[source,yaml]
----
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 `profile` field uses `https_spiffe` profile for SPIFFE-based TLS authentication.
* The `endpointSiffeId` field 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:
+
[source,yaml]
----
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 `profile` field cluster exposes its bundle using `https_spiffe` profile.
* The `bundleEndpointProfile` field cluster exposes its bundle using `https_spiffe` profile.

View File

@@ -0,0 +1,54 @@
// Module included in the following assemblies:
//
// * security/zero_trust_workload_identity_manager/zero-trust-manager-spire-federation.adoc
:_mod-docs-content-type: CONCEPT
[id="zero-trust-manager-configure-endpoints_{context}"]
= Understanding bundle endpoint profiles
[role="_abstract"]
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-full} 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:
[cols="2,3,3",options="header"]
|===
|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.
====

View File

@@ -30,23 +30,23 @@ The SPIRE Server operand exposes metrics by default on port `9402` at the `/metr
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
labels:
app.kubernetes.io/name: server
app.kubernetes.io/instance: spire
name: spire-server-metrics
namespace: zero-trust-workload-identity-manager
labels:
app.kubernetes.io/name: server
app.kubernetes.io/instance: spire
name: spire-server-metrics
namespace: zero-trust-workload-identity-manager
spec:
endpoints:
- port: metrics
interval: 30s
path: /metrics
selector:
matchLabels:
app.kubernetes.io/name: server
app.kubernetes.io/instance: spire
namespaceSelector:
matchNames:
- zero-trust-workload-identity-manager
endpoints:
- port: metrics
interval: 30s
path: /metrics
selector:
matchLabels:
app.kubernetes.io/name: server
app.kubernetes.io/instance: spire
namespaceSelector:
matchNames:
- zero-trust-workload-identity-manager
----
.. Create the `ServiceMonitor` CR by running the following command:

View File

@@ -0,0 +1,233 @@
// Module included in the following assemblies:
//
// * security/zero_trust_workload_identity_manager/zero-trust-manager-spire-federation.adoc
:_mod-docs-content-type: PROCEDURE
[id="zero-trust-manager-federation-configuration_{context}"]
= Configuring SPIRE federation with the https_spiffe profile
[role="_abstract"]
The {zero-trust-full} 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-full} on all clusters that will participate in the federation.
* You have `cluster-admin` privileges on all participating clusters.
* You have network connectivity between the clusters you intend to federate.
.Procedure
. Configure the `SpireServer` custom resource on each cluster to enable federation with the `https_spiffe` profile. The `https_spiffe` profile uses SPIFFE-based TLS authentication, where SPIRE servers authenticate to each other using their own SVIDs (SPIFFE Verifiable Identity Documents).
+
[source,yaml]
----
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 `trustDomain` field sets a unique trust domain for each cluster.
* The `profile` field uses the `https_spiffe` profile for SPIFFE-based TLS authentication.
* The `refreshHint` field suggests intervals (in seconds) for remote servers to refresh the trust bundle. Range: 60-3600 seconds.
* The `managedRoute` field enables automatic route creation by the Operator.
. Apply the configuration changes by running the following command:
+
[source,terminal]
----
$ oc apply -f spire-server.yaml
----
. Check the status of the SPIRE Server by entering the following command. Wait for the `Ready` status to be returned.
+
[source,terminal]
----
$ oc get spireserver cluster -w
----
. Verify that the federation route has been created:
+
[source,terminal]
----
$ oc get route -n zero-trust-workload-identity-manager | grep federation
----
+
.Example output
[source,terminal]
----
NAME 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:
+
[source,terminal]
----
$ curl -k https://federation.apps.cluster2.example.com > cluster2-bundle.json
----
+
[NOTE]
====
For `https_spiffe` profile, you might need to use `-k` flag 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
[source,json]
----
{
"keys": [
{
"use": "x509-svid",
"kty": "RSA",
"n": "...",
"e": "AQAB",
"x5c": ["..."]
}
],
"spiffe_sequence": 1,
"refresh_hint": 300
}
----
. Create `ClusterFederatedTrustDomain` resources for each remote trust domain.
+
.. On Cluster 1, create a resource to federate with Cluster 2:
+
[source,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_spiffe
endpointSPIFFEID: spiffe://cluster2.example.com/spire/server
trustDomainBundle: |
{
"keys": [
{
"use": "x509-svid",
"kty": "RSA",
"n": "...",
"e": "AQAB",
"x5c": ["..."]
}
],
"spiffe_sequence": 1
}
----
* The `endpointSPIFFEID` field contains the SPIFFE ID of the remote SPIRE server. Required for `https_spiffe` profile to validate the remote server's identity.
* The `trustDomainBundle` contains the complete trust bundle JSON that you fetched in the previous step.
. Apply the `ClusterFederatedTrustDomain` resource by running the following command:
+
[source,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 `ClusterFederatedTrustDomain` resource for every other cluster.
. Update the `SpireServer` resource on each cluster to add the `federatesWith` configuration:
+
[source,yaml]
----
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 `federatesWith` field lists all remote trust domains this cluster should federate with.
. Apply the updated configuration by running the following command:
+
[source,terminal]
----
$ oc apply -f spireserver.yaml
----
.Verification
. Verify that the `ClusterFederatedTrustDomain` resources have been created by running the following command:
+
[source,terminal]
----
$ oc get clusterfederatedtrustdomains
----
+
.Example output
[source,terminal]
----
NAME 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 `ClusterFederatedTrustDomain` to ensure bundle synchronization is working by running the following command:
+
[source,terminal]
----
$ oc describe clusterfederatedtrustdomain cluster2-federation
----
+
Look for successful status conditions indicating that the trust bundle has been synchronized.
. Verify that the federation endpoint is accessible by running the following command:
+
[source,terminal]
----
$ curl https://federation.apps.cluster1.example.com
----
+
You should receive a JSON response containing the trust bundle.
. Check the SPIRE Server logs to confirm federation is active by running the following command:
+
[source,terminal]
----
$ oc logs -n zero-trust-workload-identity-manager \
deployment/spire-server -c spire-server --tail=50
----
+
Look for log messages indicating successful bundle synchronization with federated trust domains.

View File

@@ -0,0 +1,205 @@
// Module included in the following assemblies:
//
// * security/zero_trust_workload_identity_manager/zero-trust-manager-spire-federation.adoc
:_mod-docs-content-type: REFERENCE
[id="zero-trust-manager-federation-field-reference_{context}"]
= Federation configuration field reference
[role="_abstract"]
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::
[cols="2,1,1,2,3",options="header"]
|===
|Field
|Type
|Required
|Default
|Description
|`federation.bundleEndpoint`
|object
|Yes
|N/A
|Configuration for this cluster's federation endpoint that exposes the trust bundle to remote clusters.
|`federation.federatesWith`
|array
|No
|`[]`
|List of remote trust domains to federate with.
|`federation.managedRoute`
|string
|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::
[cols="2,1,1,2,3",options="header"]
|===
|Field
|Type
|Required
|Default
|Description
|`federation.bundleEndpoint.profile`
|string (enum)
|Yes
|`https_spiffe`
|Authentication profile for the bundle endpoint. Valid values: `https_spiffe` or `https_web`. This value is immutable after initial configuration.
|`federation.bundleEndpoint.refreshHint`
|integer
|No
|`300`
|Suggested interval (in seconds) for remote servers to refresh the trust bundle. Valid range: 60-3600.
|`federation.bundleEndpoint.httpsWeb`
|object
|Conditional
|N/A
|Required when `profile` is `https_web`. Contains certificate configuration.
|===
httpsWeb configuration fields::
[cols="2,1,1,2,3",options="header"]
|===
|Field
|Type
|Required
|Default
|Description
|`federation.bundleEndpoint.httpsWeb.acme`
|object
|Conditional
|N/A
|ACME configuration for automatic certificate management. Mutually exclusive with `servingCert`.
|`federation.bundleEndpoint.httpsWeb.servingCert`
|object
|Conditional
|N/A
|Manual certificate configuration. Mutually exclusive with `acme`.
|===
ACME configuration fields::
[cols="2,1,1,2,3",options="header"]
|===
|Field
|Type
|Required
|Default
|Description
|`federation.bundleEndpoint.httpsWeb.acme.directoryUrl`
|string
|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/directory`
|`federation.bundleEndpoint.httpsWeb.acme.domainName`
|string
|Yes
|N/A
|Fully qualified domain name for the certificate. Typically the federation endpoint hostname.
|`federation.bundleEndpoint.httpsWeb.acme.email`
|string
|Yes
|N/A
|Email address for ACME account registration and certificate expiration notifications.
|`federation.bundleEndpoint.httpsWeb.acme.tosAccepted`
|string
|No
|`"false"`
|Accept the ACME provider's Terms of Service. Must be `"true"` to obtain certificates.
|===
servingCert configuration fields::
[cols="2,1,1,2,3",options="header"]
|===
|Field
|Type
|Required
|Default
|Description
|`federation.bundleEndpoint.httpsWeb.servingCert.fileSyncInterval`
|integer
|No
|`86400`
|Interval (in seconds) to check for certificate updates. Valid range: 3600-7776000 (1 hour to 90 days).
|`federation.bundleEndpoint.httpsWeb.servingCert.externalSecretRef`
|string
|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::
[cols="2,1,1,2,3",options="header"]
|===
|Field
|Type
|Required
|Default
|Description
|`federation.federatesWith[].trustDomain`
|string
|Yes
|N/A
|Trust domain name of the remote SPIRE deployment (for example, `cluster2.example.com`).
|`federation.federatesWith[].bundleEndpointUrl`
|string
|Yes
|N/A
|HTTPS URL of the remote federation endpoint (for example, `https://federation.apps.cluster2.example.com`).
|`federation.federatesWith[].bundleEndpointProfile`
|string (enum)
|Yes
|N/A
|Authentication profile of the remote endpoint. Valid values: `https_spiffe` or `https_web`.
|`federation.federatesWith[].endpointSpiffeId`
|string
|Conditional
|N/A
|SPIFFE ID of the remote SPIRE server (for example, `spiffe://cluster2.example.com/spire/server`). Required when `bundleEndpointProfile` is `https_spiffe`.
|===
Field validation rules::
The following validation rules are enforced by the operator:
* Profile immutability: The `bundleEndpoint.profile` field cannot be changed after initial configuration. Changing it requires deleting and recreating the `SpireServer` resource (re-installation of the system).
* Mutual exclusivity: Within `httpsWeb`, only one of `acme` or `servingCert` can be specified.
* Conditional requirements: When `profile` is `https_web`, the `httpsWeb` object must be present with either `acme` or `servingCert` configured.
* SPIFFE ID requirement: When `bundleEndpointProfile` is `https_spiffe` in the `federatesWith` list, the `endpointSpiffeId` field is required.
* Array limits: The `federatesWith` array supports a maximum of 50 entries.
* Numeric ranges:
** `refreshHint`: 60-3600 seconds
** `fileSyncInterval`: 3600-7776000 seconds

View File

@@ -0,0 +1,561 @@
// Module included in the following assemblies:
//
// * security/zero_trust_workload_identity_manager/zero-trust-manager-spire-federation.adoc
:_mod-docs-content-type: PROCEDURE
[id="zero-trust-manager-manual-management_{context}"]
= Using SPIRE federation with manual certificate management
[role="_abstract"]
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-full} on all clusters that will participate in the federation.
* You have installed the OpenShift CLI (`oc`).
* You have `cluster-admin` privileges on all participating clusters.
* You have installed the {cert-manager-operator}. For more information, see link:https://docs.redhat.com/en/documentation/openshift_container_platform/4.20/html/security_and_compliance/cert-manager-operator-for-red-hat-openshift[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:
+
[source,yaml]
----
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:
+
[source,terminal]
----
$ oc apply -f cert-manager-install.yaml
----
. Check the status of the cert-manager Operator by entering the following command:
+
[source,terminal]
----
$ oc get pods -n cert-manager
----
+
All cert-manager pods should be in `Running` status.
. Create an Issuer for certificate provisioning.
+
For Let's Encrypt with HTTP-01 challenge:
+
[source,yaml]
----
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-default
----
+
Alternatively, for an internal CA:
+
[source,yaml]
----
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:
+
[source,terminal]
----
$ oc apply -f issuer.yaml
----
. Determine the federation endpoint domain name.
+
The federation route follows a predictable naming pattern if `managedRoute` is set to `true`. Get your cluster's application domain by running the following command:
+
[source,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 output
[source,terminal]
----
Federation domain will be: federation.apps.cluster1.example.com
----
+
[NOTE]
====
The federation route is created automatically if `managedRoute` is set to `true` when you apply the `SpireServer` configuration in a later step. The route name is `spire-server-federation` and the hostname is `federation.<cluster-apps-domain>`.
====
. Create a Certificate resource to request a TLS certificate.
+
Use the federation domain determined in the previous step:
+
[source,yaml]
----
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 `secretName` field must match the `externalSecretRef` value in SpireServer.
* The `duration` field shows how long a certificate is valid. Certificates are valid for 90 days.
* The `renewBefore` field shows how many days a certificate must be renewed before it expires. Renew a certificate 15 days before expiration.
* The `commonName` field must be replaced with your actual federation domain from the previous step.
* The `dnsNames` field must match the `commonName` and the actual route `hostname` that was created.
* The `name` field must reference the Issuer that was created earlier.
. Apply the Certificate resource by running the following command:
+
[source,terminal]
----
$ oc apply -f certificate.yaml
----
. Monitor the certificate issuance by running the following command:
+
[source,terminal]
----
$ oc get certificate spire-server-federation-tls \
-n zero-trust-workload-identity-manager -w
----
+
.Example output when ready
[source,terminal]
----
NAME 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:
+
[source,terminal]
----
$ oc create role secret-reader \
--verb=get,list,watch \
--resource=secrets \
--resource-name=spire-server-federation-tls \
-n zero-trust-workload-identity-manager
----
+
Create a `RoleBinding` by running the following command:
+
[source,terminal]
----
$ oc create rolebinding secret-reader-binding \
--role=secret-reader \
--serviceaccount=openshift-ingress:router \
-n zero-trust-workload-identity-manager
----
. Configure the `SpireServer` custom resource to use manual certificate management.
+
Now that the certificate is ready, configure the SpireServer to reference it:
+
[source,yaml]
----
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 `profile` field must use `https_web` profile for certificate-based authentication.
* The `fileSyncInterval` field checks for certificate updates every 24 hours (86400 seconds). Range: 3600-7776000 seconds.
* The `externalSecretRef` field 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:
+
[source,terminal]
----
$ oc apply -f spireserver.yaml
----
. Wait for the SPIRE Server to be ready:
+
[source,terminal]
----
$ oc get spireserver cluster -n zero-trust-workload-identity-manager -w
----
+
Wait until the status shows `Ready`.
. Verify that the federation route was created by running the following command:
+
[source,terminal]
----
$ oc get route spire-server-federation -n zero-trust-workload-identity-manager
----
+
.Example output
[source,terminal]
----
NAME HOST/PORT PATH SERVICES PORT TERMINATION
spire-server-federation federation.apps.cluster1.example.com spire-server 8443 reencrypt
----
+
Verify that the route hostname matches the domain name used in your certificate.
. Verify that the federation endpoint is accessible by running the following command:
+
[source,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:
+
[source,terminal]
----
$ curl https://federation.apps.cluster1.example.com > cluster1-bundle.json
$ curl https://federation.apps.cluster2.example.com > cluster2-bundle.json
----
+
The trust bundle is in JSON Web Key Set (JWKS) format:
+
.Example trust bundle
[source,json]
----
{
"keys": [
{
"use": "x509-svid",
"kty": "RSA",
"n": "xGOzB...",
"e": "AQAB",
"x5c": ["MIIC..."]
}
],
"spiffe_sequence": 1,
"refresh_hint": 300
}
----
. Create `ClusterFederatedTrustDomain` resources for each remote trust domain you want to federate with:
+
[source,yaml]
----
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 `trustDomainBundle` field contains the complete trust bundle JSON that you fetched in the previous step.
. Apply the `ClusterFederatedTrustDomain` resources by running the following command:
+
[source,terminal]
----
$ oc apply -f clusterfederatedtrustdomains.yaml
----
. Update the `SpireServer` resource to add the `federatesWith` configuration:
+
[source,yaml]
----
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 `federatesWith` field lists all remote trust domains this cluster should federate with.
. Apply the updated configuration by running the following command:
+
[source,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 `SpireServer` configuration
* Each cluster has the RBAC for the ingress router configured
* Each cluster has `ClusterFederatedTrustDomain` resources for every other cluster it federates with
* Each cluster's `SpireServer` has the complete `federatesWith` list
.Verification
. Verify that the certificate has been issued successfully by running the following command:
+
[source,terminal]
----
$ oc get certificate spire-server-federation-tls \
-n zero-trust-workload-identity-manager
----
+
.Example output
[source,terminal]
----
NAME READY SECRET AGE
spire-server-federation-tls True spire-server-federation-tls 5m
----
. Check the certificate details and expiration by running the following command:
+
[source,terminal]
----
$ oc get secret spire-server-federation-tls \
-n zero-trust-workload-identity-manager \
-o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -noout -dates
----
+
.Example output
[source,terminal]
----
notBefore=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:
+
[source,terminal]
----
$ oc get role,rolebinding -n zero-trust-workload-identity-manager \
| grep secret-reader
----
+
.Example output
[source,terminal]
----
role.rbac.authorization.k8s.io/secret-reader
rolebinding.rbac.authorization.k8s.io/secret-reader-binding
----
+
Verify the RoleBinding references the correct ServiceAccount by running the following command:
+
[source,terminal]
----
$ oc describe rolebinding secret-reader-binding \
-n zero-trust-workload-identity-manager
----
+
.Example output
[source,terminal]
----
Name: 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 `ClusterFederatedTrustDomain` resources have been created by running the following command:
+
[source,terminal]
----
$ oc get clusterfederatedtrustdomains
----
+
.Example output
[source,terminal]
----
NAME 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 `ClusterFederatedTrustDomain` to ensure bundle synchronization is working by running the following command:
+
[source,terminal]
----
$ oc describe clusterfederatedtrustdomain cluster1-federation
----
+
Look 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:
+
[source,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 correctly
+
[source,terminal]
----
$ oc logs -n zero-trust-workload-identity-manager \
statefulset/spire-server -c spire-server --tail=100
----
+
Look for log messages indicating successful federation bundle synchronization.
. Verify that all SPIRE components are running by running the following command:
+
[source,terminal]
----
$ oc get pods -n zero-trust-workload-identity-manager
----
+
.Example output
[source,terminal]
----
NAME 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.

View File

@@ -4,9 +4,6 @@
toc::[]
:FeatureName: Zero Trust Workload Identity Manager
include::snippets/technology-preview.adoc[]
You can deploy the following operands by creating the respective custom resources (CRs). You must deploy the operands in the following sequence to ensure successful installation.
. SPIRE Server

View File

@@ -7,9 +7,6 @@ include::_attributes/common-attributes.adoc[]
toc::[]
:FeatureName: Zero Trust Workload Identity Manager
include::snippets/technology-preview.adoc[]
The {zero-trust-full} leverages {spiffe-full} and the SPIFFE Runtime Environment (SPIRE) to provide a comprehensive identity management solution for distributed systems. SPIFFE and SPIRE provide a standardized approach to workload identity, allowing workloads to communicate with other services whether on the same cluster, or in another environment.
{zero-trust-full} replaces long-lived, manually managed secrets with cryptographically verifiable identities. It provides strong authentication ensuring workloads that are communicating with each other are who they claim to be. SPIRE automates the issuing, rotating, and revoking of a {svid-full}, reducing the workload of developers and administrators managing secrets.

View File

@@ -0,0 +1,48 @@
:_mod-docs-content-type: ASSEMBLY
[id="zero-trust-manager-spire-federation"]
= Zero Trust Workload Identity Manager SPIRE federation
include::_attributes/common-attributes.adoc[]
:context: zero-trust-manager-spire-federation
toc::[]
[role="_abstract"]
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_spiffe` or `https_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 `ClusterFederatedTrustDomain` resources to define which clusters trust each other.
. Configure automatic synchronization: The SPIRE Controller Manager automatically keeps trust bundles synchronized after initial setup.
// configure endpoints
include::modules/zero-trust-manager-configure-endpoints.adoc[leveloffset=+1]
// configure YAML file
include::modules/zero-trust-manager-config-example.adoc[leveloffset=+1]
// federation configuration
include::modules/zero-trust-manager-federation-configuration.adoc[leveloffset=+1]
// automatic management
include::modules/zero-trust-manager-automatic-management.adoc[leveloffset=+1]
// manual management
include::modules/zero-trust-manager-manual-management.adoc[leveloffset=+1]
// federation field reference
include::modules/zero-trust-manager-federation-field-reference.adoc[leveloffset=+1]