feat(spiffe): GET /v1/spiffe-bundle (Trust Domain Format)#47
Merged
Conversation
Adds the SPIFFE Trust Domain Format (TDF) bundle endpoint defined in SPIFFE Trust Domain and Bundle 1.0 §4. The document carries both the X.509-SVID trust anchors and the JWT-SVID public keys in one JWK set, each tagged with `use` so a single fetch replaces the pair of `/v1/bundle` (PEM) + `/v1/jwt/bundle` (JWKS) for SPIFFE-native consumers. The legacy endpoints stay for backwards compatibility with the existing federation pump and `go-spiffe` consumers. Assembly lives in `identity.BuildSPIFFEBundle`, a free function that reads the existing `BundlePEM()` + `JWTBundle()` accessors. Adding a new CA backend (Vault PKI today; step-ca / AWS PCA / GCP CAS later) does not need to touch this code path. `spiffe_sequence` is fixed at 1 until runtime key rotation lands - omega does not rotate roots without a restart today, so the bundle is monotonic-at-one for the lifetime of a server process. The `spiffe_refresh_hint` is configurable via the new `--spiffe-bundle-refresh-hint` flag (default `5m`). Updates `docs/conformance-spiffe.md`: §4.1 (partial → implemented) and §6 (deferred → partial). OpenAPI gets the route and schema.
This comment was marked as resolved.
This comment was marked as resolved.
gemini flagged Params().Name string comparison as a soft footgun: elliptic.P256/P384/P521 return process-wide singletons, so identity comparison is both faster and harder to spoof than checking the human-readable curve name. Switch to the interface-equality pattern, keep Params().Name only for the error message where a unique name for the unsupported curve is the whole point.
This was referenced May 12, 2026
kanywst
added a commit
that referenced
this pull request
May 12, 2026
Federation pump now prefers the SPIFFE Trust Domain Format endpoint shipped on the producer side in the spiffe-bundle PR (#47), with a PEM fallback so a freshly-built omega still federates with peers older than that endpoint. fetchPeer ├── try GET /v1/spiffe-bundle → parse via go-spiffe v2's │ spiffebundle.Read (same code │ path a SPIRE agent walks), │ extract X.509 anchors + │ refresh_hint └── on 404 → fall back to GET /v1/bundle (PEM), and now parse every CERTIFICATE block as defence-in-depth so a malformed peer is rejected The peer-supplied `spiffe_refresh_hint` drives the effective per-round poll interval as effective = min(operator-configured-refresh, min-peer-hint) clamped to [10s, 1h]. The Run loop swaps `time.NewTicker` for a `time.After(EffectiveRefresh())` loop so the cadence can be re-derived after every round without Ticker.Reset gymnastics. Tests cover: TDF round-trip (with the test fixture built via spiffebundle.FromX509Authorities + Marshal so the on-the-wire bytes match what the SDK accepts on consume), PEM fallback when TDF returns 404, unreachable peer is omitted from the merged map, and malformed PEM is rejected by the new defence-in-depth parse. Moves conformance-spiffe.md §6 (sequence / refresh hints): still `partial` because spiffe_sequence stays at 1 until key rotation lands, but the note now reflects that consumption of the hint is in place too.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds the SPIFFE Trust Domain Format (TDF) bundle endpoint defined in SPIFFE Trust Domain and Bundle 1.0 §4. One JSON document carries both the X.509-SVID trust anchors (
use: x509-svid, full DER inx5c) and the JWT-SVID public keys (use: jwt-svid) in a single JWK set, plus thespiffe_sequenceandspiffe_refresh_hintenvelope fields. SPIFFE-native consumers replace the pair of/v1/bundle(PEM) +/v1/jwt/bundle(JWKS) with one fetch.The legacy endpoints stay so the existing federation pump and
go-spiffeconsumers do not need to change.Example response on a fresh server:
{ "keys": [ {"crv":"P-256","kty":"EC","use":"x509-svid","x":"...","x5c":["MIIBdT..."],"y":"..."}, {"alg":"ES256","crv":"P-256","kid":"BA0vwLDU7Bs","kty":"EC","use":"jwt-svid","x":"...","y":"..."} ], "spiffe_refresh_hint": 300, "spiffe_sequence": 1 }Scope layer
Core. SPIFFE spec endpoint, no new dependencies. Assembly lives in
identity.BuildSPIFFEBundle, a free function that reads the existingAuthority.BundlePEM()+Authority.JWTBundle()accessors so the Vault PKI backend and any future Authority backend (step-ca, AWS PCA, GCP CAS) work without code changes.Behaviour notes
spiffe_sequenceis fixed at1until runtime key rotation lands. omega does not rotate roots without a restart today, so the bundle is monotonic-at-one for the lifetime of a server process. The conformance row tracks this (§6 deferred → partial).spiffe_refresh_hintis configurable via the new--spiffe-bundle-refresh-hintflag (default5m).Test plan
go test -race -count=1 ./internal/server/identity/ ./internal/server/api/— passesTestBuildSPIFFEBundleEmitsTDFShape,TestBuildSPIFFEBundleSurfacesMalformedTrustAnchor,TestBuildSPIFFEBundleRefreshHintClampsNegative,TestSPIFFEBundleReturnsTDFDocumentgo vet ./...cleanredocly lint api/openapi.yaml—0 error(s)markdownlint-cli2 CHANGELOG.md docs/conformance-spiffe.md—0 error(s)omega server→curl /v1/spiffe-bundlereturns the document aboveConformance moves
docs/conformance-spiffe.md§4.1: partial → implementeddocs/conformance-spiffe.md§6: deferred → partial (sequence becomes "implemented" once key rotation lands)Follow-ups
spiffe_sequencelands with runtime key rotation./v1/bundlePEM polling to/v1/spiffe-bundleto honourspiffe_refresh_hintnatively (out of scope here).