Define the SPIFFE client identity, association, and configuration model
@jhrozek is already working on this.
Since Aug 13, 2026.
- Dominant language
- Go
- Stars
- 2.2k
- Forks
- 300
- Avg merge
- 1d 15h
- Merged PRs (30d)
- 184
Description
Description
Establish the shared foundation both SPIFFE authentication methods sit on: what
an authenticated SPIFFE principal is, how a SPIFFE ID is associated with an
OAuth client, and how an operator declares all of it.
This is the piece that decides whether spiffe_x509 and spiffe_jwt are two
features or one. Everything downstream — certificate validation, assertion
validation, grant issuance, Cedar inputs — consumes the normalized principal
defined here, so if the two credential paths produce different principals the
"equivalent authorization outcome" guarantee is unenforceable rather than
merely untested.
Scope
- Define a normalized authenticated principal carrying the OAuth client ID, the
SPIFFE ID, the trust domain, and the authentication method (spiffe_x509or
spiffe_jwt). - Add one authoritative runtime and operator configuration model, as an
extension of thetrustedIssuers/inboundGrantssurface rather than a
parallel one. Concretely: a trust-domain declaration (name, trust domain,
bundle source) as a sibling oftrustedIssuers, plus aspiffeClientAuth
entry underinboundGrants(trust-domain ref, enabled methods, client
associations). - Allow X.509-SVID, JWT-SVID, or both to be enabled explicitly. Nothing is
enabled by default. - Associate exact SPIFFE IDs or segment-safe
/*patterns with registered
OAuth clients. - Configure grants, scopes, resources, audiences and token-exchange permission
per association. - Make client association durable and restart-safe.
- Remove ambiguous SPIFFE upstream-provider behaviour and allow-all
registration defaults.
Reuse and prior art
The xaa-spike-1 branch built this surface once already, for inbound trust and
ID-JAG. Extend it; do not add a third way to declare external trust.
pkg/authserver/trust_config.go—TrustedIssuerRunConfig+
InboundGrantsRunConfig, validated into anIssuerTrustRegistryby
BuildIssuerTrustRegistry. The governing rule is that trust registration and
grant enablement are separate declarations and neither may silently broaden
the other: an issuer trusted but enabled for no grant is rejected, not
ignored. That is exactly this issue's fail-closed requirement.validateIDJAGGrantsenforces that no two trusted issuers may resolve
subjects onto the same upstream identity space. That is the existing
precedent for "a workload cannot claim aclient_idassociated with another
SPIFFE ID" — model the association check on it rather than inventing a new
shape.
Two patterns from the spiffee-authserver branch must not be lifted:
upstream/spiffe.go(ProviderTypeSPIFFE) andupstream/oidc_trust.go
(ProviderTypeOIDCTrust). Thexaa-spike-1branch first modelled external
trust as ajwks-trustupstream-provider type and then deliberately deleted
it in favour of a first-class config field. A SPIFFE trust domain is a trust
declaration, not an identity provider.- The branch's two known policy weaknesses: a
nilpolicy meaning allow-all,
and auto-registered clients receiving every supported scope and every allowed
audience. Per-identity narrowing is required here, not deferred.
Acceptance criteria
- X.509-SVID and JWT-SVID authentication produce the same normalized principal
for the same association. - Configuration does not advertise or accept an authentication method unless it
is enabled. - Exact and wildcard SPIFFE ID matching respects path-segment boundaries.
- A public client cannot become confidential by presenting an SVID.
- A workload cannot claim a
client_idassociated with a different SPIFFE ID. - A missing association policy fails closed.
- A trust domain declared but enabled for no authentication method is a
configuration error, not a silent no-op. - Client association and authorization policy survive authorization-server
restarts.
Blocker on the restart-safety criterion
The last criterion is not reachable with the storage layer as it stands.
Two defects catalogued in #6082 are directly in the way:
ClientRegistry.RegisterClientdocumentsErrAlreadyExistsbut both backends
silently overwrite, so a re-registering workload replaces an existing client's
configuration instead of failing.- In-memory storage loses confidential clients on restart, so any configuration
naming them goes stale every boot.
Either fix those as part of this issue, or state the Redis-only constraint
explicitly and drop the criterion. Do not leave it implied.
Dependencies
pkg/authserver/trust_config.go(unpushed,xaa-spike-1). If this issue
starts first, land the shared trust-config in a form the ID-JAG work can
adopt, not a SPIFFE-only copy.- #6082 storage and registration fixes, for the restart-safety criterion.
Related
- Part of the SPIFFE client-authentication epic
- #6082 (option D, and the storage defects above)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.