buzz-backend-kubernetes: service_account grants RBAC the pod cannot exercise
- Dominant language
- Rust
- Stars
- 32.7k
- Forks
- 4.3k
- Avg merge
- 1d 13h
- Merged PRs (30d)
- 253
Description
# buzz-backend-kubernetes: `service_account` grants RBAC the pod cannot exercise
## Problem
The kubernetes backend hardcodes `automount_service_account_token: Some(false)`
on the agent pod (`crates/buzz-backend-kubernetes/src/pod.rs`), and the
`service_account` config field documents the consequence: "Scheduling/RBAC
identity only. No API token is mounted."
That's sound hardening for most agents — a pod holding the agent's private key
shouldn't also carry an API-stealable cluster credential it never uses. But it
half-disconnects the `service_account` feature: an operator can bind RBAC to
the ServiceAccount the field names, and the pod can never exercise it, because
Kubernetes only delivers a pod's API identity through the projected token
volume that this flag suppresses. There is no environment-variable or
deploy-payload equivalent; the volume is the only door.
For agents whose *job* is the cluster — introspection, diagnostics, answering
"why is this pod crashlooping" — this is a hard capability wall. Concretely,
deploying such an agent today gets you:
```
$ kubectl get pods
The connection to the server localhost:8080 was refused
```
(in-cluster config requires the mounted token; without it kubectl falls back
to its localhost default), while the RBAC carefully granted to the configured
ServiceAccount sits unused.
## Proposed solution
A provider_config boolean, **`cluster_api_access`**, default `false`:
- `false` (default): current behavior exactly — the hardening stance is
preserved and existing deployments are untouched.
- `true`: the pod spec sets `automountServiceAccountToken: true`, giving the
pod whatever RBAC its `service_account` grants — which the operator already
controls, and which defaults to effectively nothing for an unbound account.
Schema entry alongside `service_account`, with a description that states the
trade honestly ("the token is an API-stealable credential in the pod; leave
off unless the agent's job involves the cluster itself").
Naming note: the natural name (`automount_service_account_token`, mirroring
the PodSpec field) is unavailable — the I2 key lint bans the substring
"token" in provider_config keys — so the field is named for the intent rather
than the mechanism. Happy to bikeshed.
Alternatives considered and rejected:
- **Shipping a static long-lived SA token via `env_vars`** works today but
inverts the security rationale: it replaces the platform's audience-bound,
~1h-rotating projected token with a never-expiring credential riding the
deploy payload — a strictly more stealable credential adopted to route
around a flag whose purpose is limiting credential theft.
- **TokenRequest at runtime** requires an authenticated client to call it.
## Status
I have a working patch (config field + schema + pod wiring + tests, including
the schema-guard and I2-lint updates) against `relay-v0.2.1`, currently
soak-testing on my own cluster: a read-only diagnostics agent (view
ClusterRole + a named-Secret Role) deployed through Buzz Desktop, using
kubectl/talosctl against the cluster it runs in. Before/after is crisp — the
identical agent config crashes on the Forbidden above without the flag and
runs with it. Glad to port it onto `main` and open a PR if the direction looks
right.
## Related work
I found no prior issues or PRs proposing this (searched: automount, service
account token, in-cluster kubectl, RBAC + pod). #5548 is adjacent as active
provider-protocol design discussion but addresses launch semantics, not pod
capabilities.
---
🤖 Investigated and drafted with [Claude Code](https://claude.com/claude-code);
diagnosed, reviewed, and submitted by a human.
Contributor guide
Assessment
This issue has not been assessed yet.