temporalio / temporalio/temporal-worker-controller
Support Kubernetes Service Account Tokens as an auth mode for Connection (controller + worker pods)
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 187
- Forks
- 70
- Avg merge
- 4d 1h
- Merged PRs (30d)
- 31
Description
Is your feature request related to a problem? Please describe.
Today Connection supports exactly two mutually-exclusive auth modes: mutualTLSSecretRef
and apiKeySecretRef. Both require a long-lived, static Kubernetes Secret — a client cert/key
pair for mTLS, or a bearer token for API keys. For self-hosted Temporal running on Kubernetes,
this means:
- The controller itself holds a static credential to make control-plane calls (register worker
deployment versions, check drainage, etc.). - Worker pods get that same static credential injected as an env var at pod creation time, with
no rotation until the pod restarts.
For teams already running Workload Identity / IRSA / OIDC-federated auth elsewhere in their
Kubernetes platform (no static keys, short-lived tokens, automatic rotation), this is a step
backward — it reintroduces exactly the kind of long-lived Secret that Workload Identity patterns
are meant to eliminate. It also means every rotation of the underlying cert/key requires updating
a Secret and waiting for the controller/pods to notice, rather than tokens refreshing themselves
transparently.
This isn't hypothetical — worker-side JWT auth against Temporal keeps coming up in the community:
- https://community.temporal.io/t/how-use-authorization-mechanism-in-worker/3613
- https://community.temporal.io/t/extending-the-custom-authorisation-jwt-to-the-system-worker/3408
Describe the solution you'd like
Add a third auth mode, e.g. serviceAccountToken, to ConnectionSpec, alongside the existing
mutualTLSSecretRef / apiKeySecretRef. This would rely on projected Kubernetes SA tokens
(TokenRequest API) rather than a static Secret, and splits cleanly into two independent pieces:
1. Controller's own connection (control plane)
The controller already runs as a pod with its own ServiceAccount. Instead of reading a static
Secret, it would read its own pod's projected SA token (refreshed automatically by kubelet) and
use it as a bearer token via sdkclient.NewAPIKeyDynamicCredentials, the same mechanism already
used for the apiKeySecretRef path in clientpool.go. This is a self-contained change — no new
pod-injection logic needed, since the controller's own pod spec is under the cluster operator's
control already.
2. Worker pods (data plane)
When Connection.spec.authMode: ServiceAccountToken is set, the controller would inject into
every worker pod template it generates:
- a projected volume with a
serviceAccountTokensource (configurableaudience,
expirationSeconds) - a volumeMount at a well-known path
- an env var pointing at that path (e.g.
TEMPORAL_API_KEY_FILE) instead of the current
TEMPORAL_API_KEY=<value>injection
Example spec:
apiVersion: temporal.io/v1alpha1
kind: Connection
metadata:
name: my-temporal-connection
spec:
hostPort: temporal-frontend.temporal-system:7233
authMode: ServiceAccountToken
serviceAccountToken:
audience: temporal
expirationSeconds: 3600
Worker pods would need no manual volume/env config — just a serviceAccountName on the pod
template, same as today.
Additional context
- This mode would only be meaningful for self-hosted Temporal — it requires the server to be
configured with a JWT ClaimMapper validating tokens against the cluster's OIDC issuer/JWKS.
Temporal Cloud's auth model doesn't support this today, so this would not replace
apiKeySecretRefas the recommended mode there. - The controller can guarantee "a fresh token is on disk," but whether the worker process
actually re-reads that file per-connection (vs. caching it once at startup) is up to the
worker's own SDK client construction — e.g. Go SDK'sNewAPIKeyDynamicCredentialscallback
pattern. - For multi-cluster setups (workers on EKS/AKS/GKE all pointing at one Temporal cluster), the
server-side ClaimMapper would need to trust multiple clusters' OIDC issuers — worth surfacing
in docs rather than assuming a single-issuer setup.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with ConnectionSpec and clientpool.go, especially the existing apiKeySecretRef path using sdkclient.NewAPIKeyDynamicCredentials. Trace the controller and worker pod-template generation entry points to understand where projected service-account volumes, mounts, and environment variables are configured. Done means controller authentication uses a projected token and generated worker pods receive configurable TokenRequest settings without static credentials.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go, kubernetes
- Domain
- authentication, backend
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100