Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .agents/skills/helm-dev-environment/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,11 @@ OpenShell mounts the SPIFFE CSI Workload API socket at
grants. Supervisor-to-gateway authentication remains on the Kubernetes
ServiceAccount bootstrap and gateway-minted sandbox JWT path; the selected
Kubernetes compute driver validates the projected token before the gateway
mints its JWT.
returns the current generation-bound session JWT. The driver also returns the
runtime identity recorded during provisioning. Restart preserves its namespace
and Sandbox CR UID, rejects ambiguous label matches, and rotates only the
supervisor Pod UID; bootstrap fails when the live identity does not match the
durable sandbox record.

### Vault Credential Driver

Expand Down
48 changes: 30 additions & 18 deletions architecture/compute-runtimes.md
Original file line number Diff line number Diff line change
Expand Up @@ -226,11 +226,13 @@ conservative operator-managed behavior.
Drivers that can verify a platform-native sandbox credential advertise
`GetCapabilities.supports_sandbox_authentication`. On the path-scoped
`IssueSandboxToken` exchange, the gateway forwards the opaque bearer credential
to that selected driver through `AuthenticateSandbox`. The driver returns only
the authenticated sandbox ID. The gateway then verifies that its durable
sandbox record exists and mints the gateway JWT. The driver socket is therefore
a sandbox-identity trust boundary, but it does not grant user or administrator
authority.
to that selected driver through `AuthenticateSandbox`. The driver returns the
authenticated sandbox ID and opaque runtime identity. The gateway verifies
that both match its durable sandbox record and returns a generation-bound
session JWT whose lineage is checked on every subsequent sandbox RPC. Legacy
unbound sandbox JWTs are not admitted when session authentication is enabled.
The driver socket is therefore a sandbox-identity trust boundary, but it does
not grant user or administrator authority.

## Deletion Lifecycle

Expand Down Expand Up @@ -506,19 +508,29 @@ The Kubernetes driver's `AuthenticateSandbox` implementation applies its named
until the first watcher update.

It validates the projected token with Kubernetes `TokenReview`, checks the live
pod UID, and verifies the pod's controlling Sandbox CR UID and sandbox ID before
returning the identity to the gateway. These checks rely on an ownership
invariant. In shared and managed modes, the Kubernetes driver and its trusted
Agent Sandbox controller exclusively administer the sandbox namespace, Sandbox
CRs, sandbox pods, and configured sandbox ServiceAccount. Other principals must
not create or mutate those resources or use that ServiceAccount. In operator
mode, the platform operator retains
namespace lifecycle ownership, but must preserve the same exclusive control of
Sandbox CRs and the pods and ServiceAccount used for sandbox token bootstrap.
An allowlisted namespace is therefore a trust grant, not a tenant isolation
boundary. Kubernetes owner references alone do not prove which controller
created a pod, so admitting principals that can fabricate that resource chain
would allow them to claim an existing sandbox identity.
pod UID, and verifies the pod's controlling Sandbox CR UID and sandbox ID. The
driver returns both the sandbox ID and an opaque runtime identity derived from
the namespace, immutable Sandbox CR UID, and authenticated supervisor Pod UID.
Advertising sandbox authentication includes the runtime-binding contract. The
gateway requires non-empty runtime identities from successful create, start,
and authentication responses. It records the runtime identity when provisioning
succeeds and requires an exact match before issuing a sandbox JWT. If binding
validation or storage fails after a lifecycle call succeeds, the gateway
compensates that call before returning the error. This correlates credential
authentication with the durable runtime record rather than authorizing from the
sandbox ID alone.

`StartSandbox` carries the previously recorded opaque identity. Kubernetes
requires exactly one label-selected Sandbox CR and verifies that its namespace
and immutable UID match that identity before replacing the supervisor Pod. The
new Pod UID becomes the updated binding only after the continuity check passes.

Shared and managed modes still reserve the sandbox namespace, Sandbox CRs,
sandbox pods, and configured sandbox ServiceAccount for the Kubernetes driver
and trusted Agent Sandbox controller. In operator mode, the platform operator
retains namespace lifecycle ownership and must preserve the same control of
those resources. An allowlisted namespace is a trust grant, not a tenant
isolation boundary.

### Credential Driver Integration

Expand Down
17 changes: 12 additions & 5 deletions architecture/gateway.md
Original file line number Diff line number Diff line change
Expand Up @@ -317,11 +317,18 @@ Sandbox secrets are gateway-signed JWTs bound to a single sandbox ID. Docker,
Podman, and VM drivers deliver the initial token through supervisor-only
runtime material; Kubernetes supervisors exchange a projected ServiceAccount
token through `IssueSandboxToken`. The gateway delegates that opaque credential
to the selected compute driver's `AuthenticateSandbox` RPC. A capable driver is
trusted to return the authenticated sandbox ID, while the gateway still requires
a matching durable sandbox record before minting a JWT. The Kubernetes driver
uses its own named configuration to run TokenReview and verify the live pod and
controlling Sandbox CR. The bootstrap path accepts
to the selected compute driver's `AuthenticateSandbox` RPC. A capable driver
returns the authenticated sandbox ID and an opaque runtime identity. The
gateway requires both a matching durable sandbox record and the exact
driver/runtime identity recorded at provisioning before returning the current
generation-bound session JWT. Session authentication checks the durable runtime
generation and token lineage for every sandbox RPC, so a replaced runtime and
legacy unbound tokens cannot retain provider or control-plane access. The
Kubernetes driver uses its own named configuration to run TokenReview and
verify the live pod and controlling Sandbox CR. Its runtime identity binds the
namespace, immutable Sandbox CR UID, and supervisor Pod UID. Restart preserves
the namespace and CR UID, rejects ambiguous label matches, and rotates only the
Pod-bound portion of the identity. The bootstrap path accepts
both `agents.x-k8s.io/v1beta1` ownerReferences from newer Agent Sandbox
controllers and `agents.x-k8s.io/v1alpha1` ownerReferences from existing
deployments. Supervisors renew gateway JWTs in memory before expiry only while
Expand Down
4 changes: 2 additions & 2 deletions crates/openshell-driver-docker/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3092,7 +3092,7 @@ impl ComputeDriver for DockerComputeDriver {
.sandbox
.ok_or_else(|| Status::invalid_argument("sandbox is required"))?;
self.create_sandbox_inner(&sandbox).await?;
span_status.finish(Ok(Response::new(CreateSandboxResponse {})))
span_status.finish(Ok(Response::new(CreateSandboxResponse::default())))
}

#[tracing::instrument(
Expand Down Expand Up @@ -3152,7 +3152,7 @@ impl ComputeDriver for DockerComputeDriver {
}
self.publish_container_snapshot(&request.sandbox_id, &request.name)
.await?;
Ok(Response::new(StartSandboxResponse {}))
Ok(Response::new(StartSandboxResponse::default()))
}

#[tracing::instrument(
Expand Down
8 changes: 6 additions & 2 deletions crates/openshell-driver-kubernetes/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,12 @@ mount attaches an existing PVC under `/sandbox`, which skips the default PVC.

Both Pods set `automountServiceAccountToken: false`. The supervisor receives an
explicit audience-bound projected token for the one-shot `IssueSandboxToken`
exchange. The driver verifies that token and the gateway returns the
sandbox-scoped JWT used by the supervisor session. The sandbox Pod receives
exchange. The driver verifies that token and returns an opaque runtime identity
derived from the namespace, immutable Sandbox resource UID, and supervisor Pod
UID. Restart requires exactly one matching Sandbox resource and preserves its
namespace and UID while rotating the supervisor Pod UID. The gateway requires
the authenticated identity to match the durable binding before returning the
generation-bound session JWT used by the supervisor. The sandbox Pod receives
neither token.

The gateway uses the supervisor relay for connect, exec, logs, and file sync.
Expand Down
Loading
Loading