Repository navigation
feat(server): support more than one sandbox ServiceAccount per gateway #2806
Description
Activity
- addedstate:triage-neededOpened without agent diagnostics and needs triageOpened without agent diagnostics and needs triage
on 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
- changed the title
[-]feat(server): accept multiple sandbox ServiceAccounts for K8s bootstrap auth[/-][+]feat(server): support more than one sandbox ServiceAccount per gateway[/+]on Aug 19, 2026 📋 triage-agent
Triage Assessment
Classification: feature-valid
Summary
The report describes a real least-privilege limitation: Kubernetes sandbox pods and bootstrap authentication both rely on one gateway-wide ServiceAccount. The requested design is feasible if the accepted identities remain operator-configured and the per-sandbox selection is constrained to that set.
Investigation
The Kubernetes driver always sources
spec.serviceAccountNamefrom its single driver configuration, while bootstrap TokenReview authentication exactly compares the authenticated principal to that configured account. Existing per-templateplatform_configoverrides make a narrowly validated selector feasible. Preserve the current singleservice_account_nameas the pod default; add a closed allowlist for accepted bootstrap identities and reject a per-sandbox selector unless it is a valid, allowlisted identity. Keep namespace binding explicit for any multi-namespace deployment.This overlaps #2023 on bootstrap-configuration ownership, but it is not a duplicate: #2806 adds the multi-identity capability. Sequence or implement it alongside that work (and related PR #2460).
Recommendation
Accept as feature work. Add unit coverage for legacy single-account behavior, multiple allowed identities, non-member rejection, and selector validation; add Kubernetes E2E coverage for bootstrap with a non-default allowed ServiceAccount. Do not apply
state:agent-ready; that remains a human decision.- addedstate:acceptedA maintainer decided OpenShell should pursue this issueA maintainer decided OpenShell should pursue this issuearea:gatewayGateway server and control-plane workGateway server and control-plane worktest:e2e-kubernetesRequires Kubernetes end-to-end coverageRequires Kubernetes end-to-end coverageand removedstate:triage-neededOpened without agent diagnostics and needs triageOpened without agent diagnostics and needs triage
on 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
Sorry about the delay. You should be vouched now.
If you want to pick this up, feel free.
Reacted by Sanket NadkarniReacted by Bryce Wilkinson- added 9 commits that reference this issue
on Aug 20, 2026
Description
The sandbox ServiceAccount is fixed gateway-wide.
[openshell.drivers.kubernetes] service_account_nameis a single value that serves two purposes at once:serviceAccountName—OpenShell/crates/openshell-driver-kubernetes/src/driver.rs
Line 3517 in 8d67250
OpenShell/crates/openshell-server/src/auth/k8s_sa.rs
Line 386 in 8d67250
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:
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_configon the SandboxTemplate already carriesruntime_class_name,node_selector,tolerations,annotationsandhost_users, including a documented per-sandbox-overrides-cluster-default precedent:OpenShell/crates/openshell-driver-kubernetes/src/driver.rs
Line 3503 in 8d67250
Workarounds today, both unattractive:
Proposed Direction
Two complementary parts; either is useful, together they close the case:
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
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_uidextras), andIssueSandboxTokenstill requires aK8sServiceAccount-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
Environment
Observed on gateway 0.0.85; code references above are against
mainat 8d67250.