Repository navigation
feat(server): support more than one sandbox ServiceAccount per gateway #2806
Description
Description
The sandbox ServiceAccount is fixed gateway-wide. [openshell.drivers.kubernetes] service_account_name is a single value that serves two purposes at once:
- the driver stamps it onto every sandbox pod as
serviceAccountName—
if !params.service_account_name.is_empty() { - bootstrap auth requires the presented principal to match it exactly —
if sa_name != expected_service_account {
So every sandbox on a gateway necessarily shares one Kubernetes identity. This asks for that to be configurable as a set, in the same spirit as the namespace-level validation added in #2656.
Context
The ServiceAccount is the unit of cloud IAM federation. On EKS the IAM trust policy conditions on the token subject:
StringLike <oidc>:sub = "system:serviceaccount:<namespace>:<service-account>"
GCP Workload Identity and Azure Workload Identity bind the same way. So "one SA per gateway" means "one cloud identity per gateway": sandboxes doing different work, with different blast radii, cannot be granted different cloud permissions. Granting the union to the shared SA gives every sandbox the most-privileged set.
Notably the SA is the only pod-level field with no per-sandbox override. platform_config on the SandboxTemplate already carries runtime_class_name, node_selector, tolerations, annotations and host_users, including a documented per-sandbox-overrides-cluster-default precedent:
| // Per-sandbox platform_config.host_users overrides the cluster-wide default. |
Workarounds today, both unattractive:
- Share one SA and grant it the union of permissions — every sandbox gets every permission.
- Run a gateway per identity — preserves isolation, but duplicates the gateway, its database and its forwarder topology for what is a single config value.
Proposed Direction
Two complementary parts; either is useful, together they close the case:
- Accept a configured set of sandbox service accounts in bootstrap auth. A single value stays the default and keeps current behaviour.
- Allow the pod's ServiceAccount to be selected per sandbox — e.g.
platform_config.service_account_name, constrained to the set from (1), defaulting to the existing single value.
They are separable. (2) without (1) cannot authenticate, so (1) is the prerequisite. (1) alone is already useful for deployments where something other than the gateway sets the pod's ServiceAccount — a mutating admission policy, or an external controller that owns the sandbox pods — which is the situation we hit: our pods are given a different SA out-of-band, and bootstrap then fails with
K8s TokenReview principal is not the configured sandbox service account
Whichever way (1) is implemented, it should be additive rather than a widening of service_account_name, because of consumer (1) in the Description: turning that field into a list or a delimited string would render invalid pods. The pod default and the accepted-for-auth set need to be distinct settings.
This overlaps #2023, which proposes making bootstrap config explicit and independent of the selected compute driver, and whose first Definition-of-Done item is defining the ownership model for the bootstrap namespace and service-account settings. That seems like the natural place to decide where an accepted set lives; happy to follow that issue's outcome rather than pre-empt it.
Security properties are unchanged: tokens are still verified through TokenReview, still required to be pod-bound (pod_name / pod_uid extras), and IssueSandboxToken still requires a K8sServiceAccount-sourced sandbox principal. This widens which identities an operator may enrol, not how they are verified — the accepted set stays operator-configured and closed.
Definition of Done
- Bootstrap auth accepts a configured set of sandbox service accounts; a single value remains the default and is unchanged in behaviour.
- The pod-default service account and the accepted-for-auth set are distinct settings, so the driver keeps stamping exactly one name onto pods.
- Rejection logging identifies the presented principal and that it was not in the accepted set.
- Tests: single configured SA (accept + reject), multiple configured SAs (each accepted, non-member rejected).
- Helm chart can express the set, with the existing single-value setting still supported.
- Gateway configuration documentation updated.
Environment
Observed on gateway 0.0.85; code references above are against main at 8d67250.
Activity
bjw123 commentedon Aug 19, 2026
Worth highlighting that I've put in 2 seperate vouch requests and radio silence, if anyone would like to vouch me i am happy to contribute
[-]feat(server): accept multiple sandbox ServiceAccounts for K8s bootstrap auth[/-][+]feat(server): support more than one sandbox ServiceAccount per gateway[/+]elezar commentedon Aug 19, 2026
elezar commentedon Aug 19, 2026
Sorry about the delay. You should be vouched now.
If you want to pick this up, feel free.
feat(server): accept a configured set of sandbox service accounts
feat(server): accept a configured set of sandbox service accounts
feat(server): accept a configured set of sandbox service accounts
feat(server): accept a configured set of sandbox service accounts
feat(server): allow a sandbox to select its ServiceAccount
feat(server): allow a sandbox to select its ServiceAccount
feat(server): accept a configured set of sandbox service accounts
feat(kubernetes): allow a sandbox to select its ServiceAccount
feat(kubernetes): allow a sandbox to select its ServiceAccount