Commit 3413cc2
committed
Define SPIFFE trust configuration
Both SPIFFE credential methods (X.509-SVID and JWT-SVID) need one
fail-closed identity and association model before authentication can
produce equivalent authorization outcomes for either method. Without
a shared model, adding live SVID verification later would force a
choice between duplicating trust-domain/scope/audience checks per
credential type or bolting authorization onto whichever method lands
first.
This commit defines that model as pure config validation, deliberately
without loading trust bundles or authenticating credentials — those
are separate, later steps on this stacked branch (refs #6200). It is,
however, independently fail-closed: `RunConfig.Validate()` now
validates `spiffe_trust_domains`/`inbound_grants.spiffe_client_auth`
directly, and `Config.SPIFFETrust` is built in the embedded auth
server constructor, so a malformed or half-configured declaration
cannot start successfully and silently have no effect.
`SPIFFETrustDomainRunConfig` declares a named trust domain, the
credential methods it enables, and exactly one bundle source: a SPIFFE
Bundle Endpoint (an HTTPS URL plus an `https_web`/`https_spiffe`
authentication profile, so a future loader knows whether to trust the
endpoint's TLS connection via Web PKI or a separately distributed
X.509-SVID root) or the local Workload API. Both are validated for
shape now so the field exists in the authoritative model before
consumption is built, even though fetching a bundle is out of scope
here. `SPIFFEClientAuthRunConfig` associates a SPIFFE principal
pattern (a concrete ID or a terminal `/*` wildcard) within a declared
trust domain with an explicit OAuth client_id, methods, and
permissions — client_id is never derived from the SPIFFE ID, so an
operator always states which OAuth identity a workload maps to.
Permissions are three independent dimensions instead of one combined
list: `resources` (RFC 8707, optional, must be an absolute HTTP(S) URI
and a member of the server's `allowed_audiences` allowlist — the same
list `DelegateClientRunConfig.Audiences` is validated against),
`audiences` (RFC 8693, required, but deliberately *not* bounded by
that allowlist since a token audience is a distinct request dimension
from a resource and may be a non-URI logical identifier), and
`grant_types` (required, must be exactly token-exchange for now) — so
permitting a resource never implies permitting the same value as an
audience, or vice versa, and client authentication never by itself
confers a grant.
`NewSPIFFETrustConfig` validates and normalizes these declarations
into an immutable `SPIFFETrustConfig`. It retains the validated,
canonicalized trust-domain records (not just the association policy),
exposed via a lookup-by-name method, so a future X.509/JWT-SVID
validator has one authoritative source for a trust domain's canonical
form, enabled methods, and bundle source instead of re-parsing the raw
RunConfig separately. Its zero value is also valid (equivalent to what
the constructor returns for empty input), so external packages may
construct it directly without going through the constructor.
Validation fails closed on anything that could make authorization
ambiguous or order-dependent: duplicate trust-domain names or
canonical trust domains, a principal whose trust domain doesn't match
its declared trust-domain reference, overlapping principal patterns
across associations (segment-aware, so `/agent/*` doesn't collide with
`/agent-x/*`), client IDs colliding with the reserved synthetic-client
namespace or matching a client metadata document URL (reserved for
CIMD-resolved clients, checked with the same predicate the runtime
CIMD router uses), a bundle source whose declared type doesn't match
its payload, and a bundle endpoint whose authentication profile is
missing or unrecognized.
A valid, non-empty configuration still has no runtime effect in this
commit: nothing yet registers a client or verifies a credential
against it. That first consumer (static client registration) lands in
a later commit on this stack; live SVID/bundle verification is a
further step beyond it. Since no part of this epic as currently
drafted verifies an SVID against the configured bundle, `RunConfig.Validate()`
hard-rejects a non-empty `spiffe_trust_domains` outright rather than
accepting it silently: an operator must not be able to believe SPIFFE
client authentication is active when no credential is ever checked.
The follow-up that adds real verification removes this rejection.
Refs #6200
Signed-off-by: Jakub Hrozek <jakub@stacklok.com>1 parent 65eaa1b commit 3413cc2
10 files changed
Lines changed: 1594 additions & 4 deletions
File tree
- docs/server
- pkg/authserver
- runner
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
0 commit comments