Relationships
#2196 Workload identity (Kubernetes ServiceAccount / OIDC) for worker enrollment
Opened by keeb · 9/16/2026
Summary
Workers running in Kubernetes have no way to authenticate with a workload identity. Today every worker pod needs two long-lived bearer secrets delivered out of band — a server token (--server-token-file) and an enrollment token (--token-file) — and something with elevated privileges has to mint and rotate them into Kubernetes Secrets. Users building ephemeral worker fleets are asking for "auto-enrollment inside the deployment" and end up writing CronJobs plus narrowly-scoped RBAC just to keep a Secret fresh.
There is no support for Kubernetes ServiceAccount tokens, projected tokens, or OIDC federation in src/worker, src/serve/worker_gateway.ts, or design/enablers/remote-execution.md. "Host launching is a swamp workflow" in the design doc describes provisioning but not identity.
Proposal
Let swamp serve accept a workload identity token as a worker enrollment credential:
- A worker started with e.g.
--identity-token-file /var/run/secrets/tokens/swamp(a projected ServiceAccount token with a configured audience) presents it at enrollment. - The orchestrator validates it against a configured issuer (Kubernetes TokenReview or OIDC discovery/JWKS), checks the audience, and maps claims (namespace, service account) to an enrollment policy defined in serve config or as grants — which fleet name/labels the worker gets and which server principal it acts as.
- Tokens are short-lived and rotated by the kubelet, so no Secret minting, rotation job, or RBAC write access is needed, and binding/worker records are tied to the pod identity.
Affected components: worker connect flags, enrollment protocol (src/domain/remote/protocol.ts), worker gateway enrollment, serve config/auth, the remote-execution design doc, and the worker-fleets Kubernetes guide.
Alternatives
- Current pattern: long-lived fleet enrollment token in a Secret, rotated by a CronJob holding a mint-capable credential with RBAC limited to a single pre-created Secret (
get/patchwithresourceNames). Works, but needs a privileged rotator and does not remove long-lived secrets. - Init container per pod minting its own token: removes the Secret write but puts a mint-capable credential in every worker pod.
Open
No activity in this phase yet.
Sign in to post a ripple.