Skip to content

Commit 01f999c

Browse files
committed
chore: merge main into streaming middleware protocol
Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>
2 parents e4d8731 + c8a4ff5 commit 01f999c

25 files changed

Lines changed: 1646 additions & 163 deletions

File tree

‎.agents/skills/helm-dev-environment/SKILL.md‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,11 @@ OpenShell mounts the SPIFFE CSI Workload API socket at
359359
grants. Supervisor-to-gateway authentication remains on the Kubernetes
360360
ServiceAccount bootstrap and gateway-minted sandbox JWT path; the selected
361361
Kubernetes compute driver validates the projected token before the gateway
362-
mints its JWT.
362+
returns the current generation-bound session JWT. The driver also returns the
363+
runtime identity recorded during provisioning. Restart preserves its namespace
364+
and Sandbox CR UID, rejects ambiguous label matches, and rotates only the
365+
supervisor Pod UID; bootstrap fails when the live identity does not match the
366+
durable sandbox record.
363367

364368
### Vault Credential Driver
365369

‎architecture/compute-runtimes.md‎

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -226,11 +226,13 @@ conservative operator-managed behavior.
226226
Drivers that can verify a platform-native sandbox credential advertise
227227
`GetCapabilities.supports_sandbox_authentication`. On the path-scoped
228228
`IssueSandboxToken` exchange, the gateway forwards the opaque bearer credential
229-
to that selected driver through `AuthenticateSandbox`. The driver returns only
230-
the authenticated sandbox ID. The gateway then verifies that its durable
231-
sandbox record exists and mints the gateway JWT. The driver socket is therefore
232-
a sandbox-identity trust boundary, but it does not grant user or administrator
233-
authority.
229+
to that selected driver through `AuthenticateSandbox`. The driver returns the
230+
authenticated sandbox ID and opaque runtime identity. The gateway verifies
231+
that both match its durable sandbox record and returns a generation-bound
232+
session JWT whose lineage is checked on every subsequent sandbox RPC. Legacy
233+
unbound sandbox JWTs are not admitted when session authentication is enabled.
234+
The driver socket is therefore a sandbox-identity trust boundary, but it does
235+
not grant user or administrator authority.
234236

235237
## Deletion Lifecycle
236238

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

508510
It validates the projected token with Kubernetes `TokenReview`, checks the live
509-
pod UID, and verifies the pod's controlling Sandbox CR UID and sandbox ID before
510-
returning the identity to the gateway. These checks rely on an ownership
511-
invariant. In shared and managed modes, the Kubernetes driver and its trusted
512-
Agent Sandbox controller exclusively administer the sandbox namespace, Sandbox
513-
CRs, sandbox pods, and configured sandbox ServiceAccount. Other principals must
514-
not create or mutate those resources or use that ServiceAccount. In operator
515-
mode, the platform operator retains
516-
namespace lifecycle ownership, but must preserve the same exclusive control of
517-
Sandbox CRs and the pods and ServiceAccount used for sandbox token bootstrap.
518-
An allowlisted namespace is therefore a trust grant, not a tenant isolation
519-
boundary. Kubernetes owner references alone do not prove which controller
520-
created a pod, so admitting principals that can fabricate that resource chain
521-
would allow them to claim an existing sandbox identity.
511+
pod UID, and verifies the pod's controlling Sandbox CR UID and sandbox ID. The
512+
driver returns both the sandbox ID and an opaque runtime identity derived from
513+
the namespace, immutable Sandbox CR UID, and authenticated supervisor Pod UID.
514+
Advertising sandbox authentication includes the runtime-binding contract. The
515+
gateway requires non-empty runtime identities from successful create, start,
516+
and authentication responses. It records the runtime identity when provisioning
517+
succeeds and requires an exact match before issuing a sandbox JWT. If binding
518+
validation or storage fails after a lifecycle call succeeds, the gateway
519+
compensates that call before returning the error. This correlates credential
520+
authentication with the durable runtime record rather than authorizing from the
521+
sandbox ID alone.
522+
523+
`StartSandbox` carries the previously recorded opaque identity. Kubernetes
524+
requires exactly one label-selected Sandbox CR and verifies that its namespace
525+
and immutable UID match that identity before replacing the supervisor Pod. The
526+
new Pod UID becomes the updated binding only after the continuity check passes.
527+
528+
Shared and managed modes still reserve the sandbox namespace, Sandbox CRs,
529+
sandbox pods, and configured sandbox ServiceAccount for the Kubernetes driver
530+
and trusted Agent Sandbox controller. In operator mode, the platform operator
531+
retains namespace lifecycle ownership and must preserve the same control of
532+
those resources. An allowlisted namespace is a trust grant, not a tenant
533+
isolation boundary.
522534

523535
### Credential Driver Integration
524536

‎architecture/gateway.md‎

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -317,11 +317,18 @@ Sandbox secrets are gateway-signed JWTs bound to a single sandbox ID. Docker,
317317
Podman, and VM drivers deliver the initial token through supervisor-only
318318
runtime material; Kubernetes supervisors exchange a projected ServiceAccount
319319
token through `IssueSandboxToken`. The gateway delegates that opaque credential
320-
to the selected compute driver's `AuthenticateSandbox` RPC. A capable driver is
321-
trusted to return the authenticated sandbox ID, while the gateway still requires
322-
a matching durable sandbox record before minting a JWT. The Kubernetes driver
323-
uses its own named configuration to run TokenReview and verify the live pod and
324-
controlling Sandbox CR. The bootstrap path accepts
320+
to the selected compute driver's `AuthenticateSandbox` RPC. A capable driver
321+
returns the authenticated sandbox ID and an opaque runtime identity. The
322+
gateway requires both a matching durable sandbox record and the exact
323+
driver/runtime identity recorded at provisioning before returning the current
324+
generation-bound session JWT. Session authentication checks the durable runtime
325+
generation and token lineage for every sandbox RPC, so a replaced runtime and
326+
legacy unbound tokens cannot retain provider or control-plane access. The
327+
Kubernetes driver uses its own named configuration to run TokenReview and
328+
verify the live pod and controlling Sandbox CR. Its runtime identity binds the
329+
namespace, immutable Sandbox CR UID, and supervisor Pod UID. Restart preserves
330+
the namespace and CR UID, rejects ambiguous label matches, and rotates only the
331+
Pod-bound portion of the identity. The bootstrap path accepts
325332
both `agents.x-k8s.io/v1beta1` ownerReferences from newer Agent Sandbox
326333
controllers and `agents.x-k8s.io/v1alpha1` ownerReferences from existing
327334
deployments. Supervisors renew gateway JWTs in memory before expiry only while

‎crates/openshell-driver-docker/src/lib.rs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3092,7 +3092,7 @@ impl ComputeDriver for DockerComputeDriver {
30923092
.sandbox
30933093
.ok_or_else(|| Status::invalid_argument("sandbox is required"))?;
30943094
self.create_sandbox_inner(&sandbox).await?;
3095-
span_status.finish(Ok(Response::new(CreateSandboxResponse {})))
3095+
span_status.finish(Ok(Response::new(CreateSandboxResponse::default())))
30963096
}
30973097

30983098
#[tracing::instrument(
@@ -3152,7 +3152,7 @@ impl ComputeDriver for DockerComputeDriver {
31523152
}
31533153
self.publish_container_snapshot(&request.sandbox_id, &request.name)
31543154
.await?;
3155-
Ok(Response::new(StartSandboxResponse {}))
3155+
Ok(Response::new(StartSandboxResponse::default()))
31563156
}
31573157

31583158
#[tracing::instrument(

‎crates/openshell-driver-kubernetes/README.md‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,12 @@ mount attaches an existing PVC under `/sandbox`, which skips the default PVC.
140140

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

147151
The gateway uses the supervisor relay for connect, exec, logs, and file sync.

0 commit comments

Comments
 (0)