Description
Provide the supported Kubernetes deployment and credential-delivery path: SPIRE
issues rotating SVIDs over the Workload API, and the operator declares trust
domains, enabled methods and client associations through the CRD.
Without this the epic is a library change nobody can deploy. It is also where
the "no static secret" claim is actually cashed out — the workload must obtain
both credential types with no private-key file and no OAuth client secret
anywhere in the manifest.
Scope
- Add v1beta1 CRD and controller wiring.
- Configure trust domains, enabled authentication methods, client associations,
TLS, bundle sources, scopes, resources and audiences.
- Support referenced Secrets, ConfigMaps, SPIFFE Bundle Endpoints and Workload
API sockets as appropriate to each field.
- Provide a supported SPIRE Server and Agent deployment.
- Define node and workload attestation, and workload registration entries.
- Obtain rotating X.509-SVIDs and trust bundles through the Workload API.
- Obtain audience-specific JWT-SVIDs whose audience exactly matches the ToolHive
authorization-server issuer.
- Support bundle and credential rotation without application restart.
API version and enforcement
Two things to get right rather than inherit:
API version. The spiffee-authserver branch's CRD work is on v1alpha1
MCPExternalAuthConfig, but the trustedIssuers / inboundGrants surface this
epic extends is v1beta1. Reusing that surface resolves the drift; porting the
v1alpha1 work forward re-creates it.
Three-layer enforcement. Mirror the pattern already used for inbound trust:
CEL admission rules on the CRD, a Go mirror in the controller for the rules CEL
cannot express (cross-entry uniqueness in particular), and a runtime registry
build at authserver startup. Each layer is deliberately redundant — CEL is the
cheapest failure point, the Go mirror catches stored objects that bypassed
admission, and the runtime build is the backstop.
One existing gap in that pattern is worth not repeating: the runtime
registry build is gated on ID-JAG grants being present, so a
token-exchange-only deployment has no runtime backstop at all and relies
entirely on the first two layers. The SPIFFE equivalent should be gated on its
own configuration being present, not on an unrelated grant.
Acceptance criteria
- The operator rejects incomplete or contradictory SPIFFE configurations at
admission time where CEL can express the rule, and during reconciliation
otherwise.
- The operator reconciles relevant Secret, ConfigMap and bundle-source changes.
- A SPIRE-attested workload obtains both supported SVID types with no static
OAuth client secret.
- No private-key file is required on the SPIRE Workload API path.
- X.509-SVID and JWT-SVID rotation work without restarting the workload or the
authorization server.
- The cert-manager CSI implementation is documented only as an optional
compatibility or development path, with its different attestation and RBAC
properties made explicit.
Dependencies
- Sub-issue 5 (OAuth grants and discovery integration)
- The v1beta1
trustedIssuers / inboundGrants CRD surface (unpushed,
xaa-spike-1)
Related
- Part of the SPIFFE client-authentication epic
Description
Provide the supported Kubernetes deployment and credential-delivery path: SPIRE
issues rotating SVIDs over the Workload API, and the operator declares trust
domains, enabled methods and client associations through the CRD.
Without this the epic is a library change nobody can deploy. It is also where
the "no static secret" claim is actually cashed out — the workload must obtain
both credential types with no private-key file and no OAuth client secret
anywhere in the manifest.
Scope
TLS, bundle sources, scopes, resources and audiences.
API sockets as appropriate to each field.
authorization-server issuer.
API version and enforcement
Two things to get right rather than inherit:
API version. The
spiffee-authserverbranch's CRD work is on v1alpha1MCPExternalAuthConfig, but thetrustedIssuers/inboundGrantssurface thisepic extends is v1beta1. Reusing that surface resolves the drift; porting the
v1alpha1 work forward re-creates it.
Three-layer enforcement. Mirror the pattern already used for inbound trust:
CEL admission rules on the CRD, a Go mirror in the controller for the rules CEL
cannot express (cross-entry uniqueness in particular), and a runtime registry
build at authserver startup. Each layer is deliberately redundant — CEL is the
cheapest failure point, the Go mirror catches stored objects that bypassed
admission, and the runtime build is the backstop.
One existing gap in that pattern is worth not repeating: the runtime
registry build is gated on ID-JAG grants being present, so a
token-exchange-only deployment has no runtime backstop at all and relies
entirely on the first two layers. The SPIFFE equivalent should be gated on its
own configuration being present, not on an unrelated grant.
Acceptance criteria
admission time where CEL can express the rule, and during reconciliation
otherwise.
OAuth client secret.
authorization server.
compatibility or development path, with its different attestation and RBAC
properties made explicit.
Dependencies
trustedIssuers/inboundGrantsCRD surface (unpushed,xaa-spike-1)Related