✨ Feat: Add SPIRE x5c init-container signing, trust-domain binding, and ConfigMap trust bundle - #185
Conversation
Drop SecretProvider, JWKSProvider, NoOpProvider and their tests. Remove legacy samples (build pipelines, JWKS signing), unused images, and helper scripts that are superseded by the SPIRE init-container approach. Signed-off-by: Kevin Cogan <kevin.s.cogan@gmail.com>
Implement X5CProvider for X.509 certificate chain-based JWS signature verification with SPIFFE ID extraction, trust bundle caching via ConfigMap, chain depth limits, and automatic bundle refresh. Remove legacy provider wiring and update metrics. Signed-off-by: Kevin Cogan <kevin.s.cogan@gmail.com>
…inding Replace allowedSpiffeIDs allowlist with trust-domain-only identity binding derived from x5c certificate SAN URIs. Add proactive SVID expiry restart logic, trust bundle hash tracking, and resign-trigger annotations. Update tests for new verification and binding flows. Signed-off-by: Kevin Cogan <kevin.s.cogan@gmail.com>
Implement init-container binary that fetches X.509-SVID from SPIRE Workload API, signs AgentCard JSON with JWS (x5c header), and writes the signed card to a shared volume. Includes Dockerfile for distroless image build. Signed-off-by: Kevin Cogan <kevin.s.cogan@gmail.com>
Add CLI flags for ConfigMap trust bundle, SPIRE trust domain, and SVID expiry grace period with startup validation. Cap HTTP response body at 1 MiB via io.LimitReader. Remove AllowedSpiffeIDs from CRD types and update deepcopy. Add go-spiffe/v2 dependency. Signed-off-by: Kevin Cogan <kevin.s.cogan@gmail.com>
Update manager deployment args for ConfigMap trust bundle and SVID grace period. Regenerate CRD schemas removing allowedSpiffeIDs. Add signed-agent-example sample demonstrating full x5c signing flow. Signed-off-by: Kevin Cogan <kevin.s.cogan@gmail.com>
Revise signature verification docs for ConfigMap trust bundle. Update architecture and API reference for x5c provider and removed providers. Refresh identity binding quickstart for trust-domain-only model. Signed-off-by: Kevin Cogan <kevin.s.cogan@gmail.com>
Accepts upstream removal of the Agent CRD and related controllers, types, RBAC, and samples. Retains AgentCard identity binding, signature verification, and SPIRE trust bundle integration. Restores configmaps and events RBAC permissions required by the X5CProvider and event recorder. Signed-off-by: Kevin Cogan <kevin.s.cogan@gmail.com>
When a manually-created AgentCard targets the same workload as an auto-created card, the sync controller now detects the supersession and deletes its auto-created card, ensuring exactly one card per workload. Adds unit tests and updates E2E guide documentation. Signed-off-by: Kevin Cogan <kevin.s.cogan@gmail.com>
…ates LastSyncTime, BindingStatus.LastEvaluationTime, and condition LastTransitionTime were written on every reconcile, causing the status object to change each cycle and re-triggering the controller. Update timestamps only when the underlying data actually changes: - LastSyncTime: only when cardId changes (or on first sync) - LastEvaluationTime: only when Bound/Reason/Message changes - LastTransitionTime: delegate to meta.SetStatusCondition (updates only on Status/Reason transitions) Signed-off-by: Kevin Cogan <kevin.s.cogan@gmail.com>
usize
left a comment
There was a problem hiding this comment.
nit: looks like we need to run go fmt
And finally, a request. This looks great, but the sample-config might confuse folks. I cheated and asked an LLM to help me hone in on the details:
1. image: weather-agent:latest — this image doesn't exist in any registry. Should this be
ghcr.io/kagenti/agent-examples/weather_service:v0.0.1-alpha.3 (as used in GETTING_STARTED.md), or does it need a real static-file-server
image that serves /.well-known/agent.json?
2. image: kagenti/agentcard-signer:latest — not published anywhere. It needs to be built from cmd/agentcard-signer/ and loaded into the
cluster, but there are no instructions for this.
3. No namespace creation — everything targets namespace: agents but nothing creates it (not in the manifests or the kustomization).
4. Missing ClusterSPIFFEID — the a2a-signature-verification.md doc lists this as a prerequisite (step 1), but it's not included in the
sample. Without it the init-container will crash because SPIRE won't issue an SVID.
5. Operator flag configuration not covered — the operator needs --require-a2a-signature=true and --spire-trust-domain=<domain> to verify
signatures, but there's no guidance on how to set these (e.g., Helm values).
The basic idea, is that I think we need to be explicit about e.g. requiring a kagenti dev install via kagenti/deployments/run_install.sh --env dev (in the Kagenti repo) and to add to the makefile in the project to build and add the agent signature container locally maybe? Or we could do it with a setup.sh and teardown.sh script.
That's the approach I've been taking e.g., here in AuthBridge in this demo I added: https://github.com/kagenti/kagenti-extensions/tree/main/AuthBridge/demos/multi-target
If we could add a working demo like that, that works with a fresh dev install of kagenti to a local kind cluster it would likely be a big help and we could use it to demo the cool new feature.
Otherwise, this is great. Ready to approve after hearing your thoughts about adding a slightly easier-to-run demo.
| ```bash | ||
| # Generate a different key pair | ||
| openssl genrsa -out wrong-private-key.pem 2048 | ||
| See `config/samples/spire-signing/` for complete manifests. The key elements: |
There was a problem hiding this comment.
nit: I think this is now config/samples/signed-agent-example ?
There was a problem hiding this comment.
Thanks for the thorough review! All points addressed and a lot cleaner now:
-
go fmt: Fixed across all changed files.
-
Sample config issues: Removed
config/samples/signed-agent-example/entirely and replaced it with four self-contained demos indemos/following the AuthBridge convention (demo.md+run-demo-commands.sh+teardown-demo.sh+k8s/manifests):-
agentcard-spire-signing: Full init-container signing flow with namespace, ClusterSPIFFEID, and operator flag documentation
-
agentcard-enforcement: Trust domain rejection and NetworkPolicy enforcement
-
agentcard-auto-discovery: Sync controller auto-creating AgentCards for labeled workloads
-
agentcard-proactive-restart: SVID expiry detection triggering automatic re-signing
Each demo is runnable end-to-end against a fresh
kagenti/deployments/run_install.sh --env devinstall. Addedmake build-signerandmake load-signer-imagetargets for the init-container image.
-
-
Stale path: Fixed. The old docs are replaced with
agentcard-signature-verification.mdandagentcard-identity-binding.md, all cross-references updated.Also cleaned up dead Secret setup in the signature verification tests (leftover from the removed SecretProvider).
Add four runnable demos with setup/run/teardown scripts and k8s manifests: spire-signing, enforcement, auto-discovery, and proactive-restart. Add build-signer and load-signer-image Makefile targets for the agentcard-signer init-container image. Signed-off-by: Kevin Cogan <kevin.s.cogan@gmail.com>
Rename a2a-signature-verification.md to agentcard-signature-verification.md and identity-binding-quickstart.md to agentcard-identity-binding.md for naming consistency. Remove config/samples/signed-agent-example/ (superseded by demos/agentcard-spire-signing/). Update cross-references in GETTING_STARTED, api-reference, architecture, and dev docs. Fix stale provider description in dev.md. Signed-off-by: Kevin Cogan <kevin.s.cogan@gmail.com>
Apply gofmt formatting fixes across controller and signature packages. Remove unused Secret creation and cleanup from signature verification tests (leftover from removed SecretProvider). Signed-off-by: Kevin Cogan <kevin.s.cogan@gmail.com>
Summary
Implements automated AgentCard signing via a SPIRE init-container and replaces the legacy signature verification infrastructure with an X.509 certificate chain (x5c) based approach.
Key changes:
Remove deprecated providers: Drop
SecretProvider,JWKSProvider,NoOpProvider, legacy samples, unused images, and helper scripts.Add
X5CProvider: X.509 certificate chain-based JWS signature verification with SPIFFE ID extraction from SAN URIs, trust bundle caching via ConfigMap, chain depth limits, and automatic bundle refresh.Refactor AgentCard controller: Replace
allowedSpiffeIDsmanual allowlist with trust domain only identity binding derived from x5c certificate SAN URIs. Add proactive SVID expiry restart logic withbundle-hashandresign-triggerannotations.Add
agentcard-signerinit-container: Binary that fetches X.509-SVID from SPIRE Workload API, signs AgentCard JSON with JWS (x5c header), and writes the signed card to a shared volume.Wire operator flags: Add CLI flags for
--spire-trust-bundle-configmap,--spire-trust-domain, and--svid-expiry-grace-periodwith startup validation. Harden fetcher withio.LimitReader(1 MiB cap).Update Helm chart and CRDs: Regenerate CRD schemas removing
allowedSpiffeIDs, update manager deployment args for ConfigMap trust bundle and SVID grace period.Update documentation: Revise signature verification, identity binding, architecture, and API reference docs for the new x5c/SPIRE model.
Related issue(s)
Fixes #179
Related #116
(Optional) Testing Instructions