Skip to content

feat(operator): spiffe-helper sidecar injection (proposal 011 PR-3) - #85

Merged
flg77 merged 1 commit into
mainfrom
spiffe/agent-sidecar
May 15, 2026
Merged

feat(operator): spiffe-helper sidecar injection (proposal 011 PR-3)#85
flg77 merged 1 commit into
mainfrom
spiffe/agent-sidecar

Conversation

@flg77

@flg77 flg77 commented May 15, 2026

Copy link
Copy Markdown
Owner

Summary

Third PR of proposal 011. When an AgentCollective has spec.spiffe.enabled: true, every agent pod gains a spiffe-helper sidecar that materialises the pod's X.509-SVID + JWT-SVID into a shared emptyDir. The agent container reads SVID files from there — no agent code change beyond the env vars the operator now sets.

Stacked on #84 (011 PR-2) — base is spiffe/operator-controller. Merge #84 first, then retarget this to main.

Inert by design — pods are unchanged until an operator sets spec.spiffe.enabled.

What's new

operator/internal/reconcilers/collective/spiffe_sidecar.go:

  • ApplySpiffeSidecar(deploy, collective, helperCMName) mutates a built agent Deployment: adds the spiffe-helper container, three volumes (spiffe-svids emptyDir shared with the agent; spiffe-workload-api CSI volume exposing the SPIRE Agent Workload API socket; spiffe-helper-config ConfigMap), the spiffe.io/spire-managed-identity pod annotation, and the agent container's read mount + ACC_SVID_* env vars. No-op when SPIFFE disabled.
  • RenderSpiffeHelperConfig() produces the helper.conf HCL (agent_address, cert_dir, jwt_svids with audience acc-role-update).
  • SpiffeEnabled() + SpiffeHelperConfigMapName() helpers.

agent_deployment.go:

  • ReconcileCollective upserts a per-collective <collective>-spiffe-helper ConfigMap when SPIFFE is enabled.
  • reconcileRoleDeployment calls ApplySpiffeSidecar after building the base Deployment.

Test plan

  • go build ./... clean — validated on lighthouse
  • 6 unit tests in spiffe_sidecar_test.goSpiffeEnabled, helper.conf rendering, disabled-is-no-op, sidecar injection, helper-container shape, ConfigMap naming
  • 13 SPIFFE tests pass (7 PR-2 reconciler + 6 PR-3 sidecar), full operator suite green

Proposal 011 reference

011 - SPIFFE workload identity for ACC agents.md. PR-1 #81 merged; PR-2 #84 open. PR-4 (agent-side verifier) next.

🤖 Generated with Claude Code

@flg77
flg77 changed the base branch from spiffe/operator-controller to main May 15, 2026 15:50
Third PR of proposal 011 — when an AgentCollective has
spec.spiffe.enabled=true, every agent pod gains a spiffe-helper
sidecar that materialises the pod's X.509-SVID + JWT-SVID into a
shared emptyDir.  The agent container reads SVID files from there.

Inert by design: pods are unchanged until an operator opts in.

New operator/internal/reconcilers/collective/spiffe_sidecar.go:

* ApplySpiffeSidecar(deploy, collective, helperCMName) mutates a
  built agent Deployment in place — adds the spiffe-helper
  container, three volumes (spiffe-svids emptyDir shared with the
  agent; spiffe-workload-api CSI volume exposing the SPIRE Agent
  Workload API socket; spiffe-helper-config ConfigMap), the
  spiffe.io/spire-managed-identity pod annotation, and the agent
  container's read mount + ACC_SVID_* env vars.  No-op when SPIFFE
  is disabled.
* RenderSpiffeHelperConfig() produces the helper.conf HCL that
  drives the sidecar (agent_address, cert_dir, jwt_svids with
  audience acc-role-update).
* SpiffeEnabled() + SpiffeHelperConfigMapName() helpers, shared
  with the wiring in agent_deployment.go.

agent_deployment.go changes:

* ReconcileCollective upserts a per-collective spiffe-helper
  ConfigMap (<collective>-spiffe-helper) when SPIFFE is enabled.
* reconcileRoleDeployment calls ApplySpiffeSidecar after building
  the base Deployment, before the Upsert.

Test coverage: 6 unit tests in spiffe_sidecar_test.go covering
SpiffeEnabled, helper.conf rendering, disabled-is-no-op, sidecar
injection (containers/volumes/annotation/agent-env), helper
container shape, and ConfigMap naming.  contains() reused from
role_catalogue_test.go (same package).

Validated on lighthouse: go build ./... clean, full operator
suite green.

Stacked on spiffe/operator-controller (011 PR-2, PR #84).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@flg77
flg77 force-pushed the spiffe/agent-sidecar branch from de26aa9 to c87295d Compare May 15, 2026 15:52
@flg77
flg77 merged commit 3d57062 into main May 15, 2026
@flg77
flg77 deleted the spiffe/agent-sidecar branch May 15, 2026 15:52
flg77 added a commit that referenced this pull request May 15, 2026
Second PR of proposal 012 — extends the operator-side SPIFFE
provisioning (011 PR-2) to edge deployments.

Inert by design: no behaviour change until an operator sets
deployMode=edge + spec.spiffe.

CRD changes (agentcollective_types.go + hand-updated CRD bases):

* SpiffeSpec gains EdgeTopology (nested | federated | ed25519,
  default nested) + EdgeSiteID.
* AgentCollectiveStatus gains EdgeSiteID — echoes the site
  qualifier baked into SpiffeID.

Reconciler (collective/spiffe.go):

* New computeSpiffeID() — when the owning AgentCorpus has
  deployMode=edge AND spiffe.edgeTopology=nested, the SPIFFE ID
  is site-qualified:
    spiffe://<trust-domain>/edge/<site-id>/role/<collective>
  Federated / ed25519 topologies + every non-edge deploy mode
  keep the flat spiffe://<trust-domain>/role/<collective> form.
* nested topology without an edgeSiteID reports a config error
  via SpiffeResult.Err -> status.spiffeError; never hard-fails
  reconciliation.
* CollectiveReconciler.patchSpiffeStatus also patches EdgeSiteID.

Deploy manifests (deploy/edge-spire/):

* nested-spire-server.values.yaml — Helm values overlay for the
  upstream spiffe/spire chart configured for nested topology
  (edge SPIRE downstream of an rhoai parent).  ACC does not
  vendor SPIRE — operators helm-install it.
* edge-bundle-fetcher.yaml — PVC + CronJob caching the parent
  SPIRE trust bundle every 6h for offline survival.
* README.md — install runbook + the edgeSiteID-uniqueness
  requirement + the no-RWX fallback.

Test coverage: 5 unit tests in spiffe_edge_test.go covering the
site-qualified ID, the missing-edgeSiteID error path, federated
plain ID, non-edge topology-ignored, and ed25519 topology.

Validated on lighthouse: go build ./... clean, full operator
suite green.

Stacked on spiffe/agent-sidecar (011 PR-3, PR #85), which is
itself stacked on 011 PR-2 (#84).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
flg77 added a commit that referenced this pull request May 15, 2026
Second PR of proposal 012 — extends the operator-side SPIFFE
provisioning (011 PR-2) to edge deployments.

Inert by design: no behaviour change until an operator sets
deployMode=edge + spec.spiffe.

CRD changes (agentcollective_types.go + hand-updated CRD bases):

* SpiffeSpec gains EdgeTopology (nested | federated | ed25519,
  default nested) + EdgeSiteID.
* AgentCollectiveStatus gains EdgeSiteID — echoes the site
  qualifier baked into SpiffeID.

Reconciler (collective/spiffe.go):

* New computeSpiffeID() — when the owning AgentCorpus has
  deployMode=edge AND spiffe.edgeTopology=nested, the SPIFFE ID
  is site-qualified:
    spiffe://<trust-domain>/edge/<site-id>/role/<collective>
  Federated / ed25519 topologies + every non-edge deploy mode
  keep the flat spiffe://<trust-domain>/role/<collective> form.
* nested topology without an edgeSiteID reports a config error
  via SpiffeResult.Err -> status.spiffeError; never hard-fails
  reconciliation.
* CollectiveReconciler.patchSpiffeStatus also patches EdgeSiteID.

Deploy manifests (deploy/edge-spire/):

* nested-spire-server.values.yaml — Helm values overlay for the
  upstream spiffe/spire chart configured for nested topology
  (edge SPIRE downstream of an rhoai parent).  ACC does not
  vendor SPIRE — operators helm-install it.
* edge-bundle-fetcher.yaml — PVC + CronJob caching the parent
  SPIRE trust bundle every 6h for offline survival.
* README.md — install runbook + the edgeSiteID-uniqueness
  requirement + the no-RWX fallback.

Test coverage: 5 unit tests in spiffe_edge_test.go covering the
site-qualified ID, the missing-edgeSiteID error path, federated
plain ID, non-edge topology-ignored, and ed25519 topology.

Validated on lighthouse: go build ./... clean, full operator
suite green.

Stacked on spiffe/agent-sidecar (011 PR-3, PR #85), which is
itself stacked on 011 PR-2 (#84).

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
flg77 pushed a commit that referenced this pull request Jun 15, 2026
…'t host-writable (#85)

acc-deploy.sh apply <preset-with-required_packages> crashed with a raw
PermissionError when the packages root (/var/lib/acc/packages) is the
in-container acc-packages volume the host can't write — observed on the
lighthouse edge stack.

- registry: reads (list/find/find_by_name) no longer materialise the root;
  a read against a never-created root returns 'nothing installed' instead
  of raising. New non-destructive root_is_host_writable() probe.
- collective pkg-install: when the spec declares required_packages but the
  root isn't host-writable, defer to in-container resolution with exit 20
  (EXIT_PKG_ROOT_DEFERRED) + an actionable message naming the three
  provisioning surfaces (TUI Get pack / acc-deploy pkg add / infuse) — no
  traceback, no misleading ACC_ALLOW_UNSIGNED hint.
- acc-deploy.sh: treats exit 20 as a soft-skip (apply continues; agents
  resolve roles from the in-container registry), other non-zero still aborts.
- tests: tests/pkg/test_required_packages_host_degrade.py.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
flg77 added a commit that referenced this pull request Jun 15, 2026
fix(acc-deploy/pkg): apply degrades gracefully when packages root isn't host-writable (#85)
flg77 pushed a commit that referenced this pull request Jun 15, 2026
New how-to for collective.e2e-demo: build a Keycloak-secured stock-quotes
web app (React + FastAPI, Yahoo Finance) reviewed before an RHOAI deploy,
on external MaaS models. Covers:
- the collective topology + collective_id=sol-01 rationale + MaaS/API-key
  handling (api_key_env + .env, never committed);
- the end-to-end methodology (build -> redeploy -> install/infuse -> apply
  -> run), incl. why the acc-packages volume mount is required (#91);
- package install / role INFUSION in depth — AutoMode assistant
  ([PROPOSE_INFUSE] -> always Compliance-gated even under AUTO -> spawn)
  vs Manual (pkg add / infuse --from-pkg / TUI Get-pack), plus the
  lighthouse reality (#85 host-can't-write, signed install-from-file with
  cosign, catalog #92);
- prompt techniques + reasoning: the reviewer verdict contract, that
  depends_on sequences but does NOT thread step outputs (use the inline
  critic loop or KNOWLEDGE_SHARE, not {step:X}), model-to-job matching,
  and writing specific task_descriptions so mid-size models don't ramble;
- a field troubleshooting table (dormant cells, 401, no-catalog, etc.).
Linked from DEMOS.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant