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
9 changes: 7 additions & 2 deletions crates/openshell-driver-kubernetes/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -262,8 +262,13 @@ fails closed.
and the routing preface only selects which generation-pinned TLS identity
the supervisor demands.

The topology does not support upstream proxies or provider SPIFFE identity, and
the shared supervisor is a single point of failure for the sandboxes it hosts.
The topology does not support upstream proxies or provider SPIFFE identity.
With a live replacement supervisor and a takeover-capable runtime, the gateway
can move a paused sandbox generation to the replacement using a signed takeover
grant. Recovery preserves workload processes and memory, but proxied connections
and interactive sessions must reconnect. If recovery exceeds the configured
deadline, the runtime terminates the workload. It cannot recover a lost workload
Pod or node. See [supervisor recovery](../../docs/kubernetes/high-availability.mdx#recover-from-a-supervisor-failure).
Shared sandbox instances export no supervisor OTLP traces or OCSF events and do
not relay agent traces; the driver warns at startup when the gateway configures
any of them.
Expand Down
67 changes: 42 additions & 25 deletions docs/about/architecture.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ position: 2

OpenShell governs what agents can do in two ways: it instruments the kernel to enforce policy on every file access, system call, and network connection at runtime, and it uses formal verification to check what a policy change would allow before it is applied.

- **Kernel-level enforcement.** Each agent runs in an isolated sandbox. Kernel controls confine which files it can access and which system calls it can make, and every network connection passes through a policy check before it leaves the sandbox. Agents never see real credentials; OpenShell adds them only to requests bound for approved endpoints.
- **Kernel-level enforcement.** Each agent runs in an isolated sandbox. Kernel controls confine which files it can access and which system calls it can make, and every network connection passes through a policy check before it leaves the sandbox. OpenShell supplies credential placeholders to agents and adds real credentials only to requests bound for approved endpoints.
- **Formally verified policy changes.** Before a policy change is approved, OpenShell uses formal verification to flag risky new access it would grant, such as reaching a new host with credentials or calling a new API method, so those changes wait for human review.

The **gateway** is the control plane: it manages the lifecycle of sandboxes and
Expand Down Expand Up @@ -55,7 +55,7 @@ trusted process observations.
### Mediated Channel

The **supervisor** and **sandbox** talk over the OpenShell Sandbox Protocol:
one mutually authenticated HTTP/2 connection that carries many independent
one HTTP/2 connection authenticated with TLS and a sandbox JWT that carries many independent
streams. The compute driver picks the transport: a Unix socket for Docker and
Podman, TCP for Kubernetes, or vsock for MicroVM. Authentication and protocol
behavior are the same on all of them. The **supervisor** presents a
Expand Down Expand Up @@ -112,7 +112,7 @@ network.
|---|---|---|---|
| Docker | Its own container | Authenticated Unix socket on a driver-owned volume | Workload container has networking turned off |
| Podman | Its own container | Authenticated Unix socket on a driver-owned volume | Workload container has networking turned off |
| Kubernetes | Its own pod | Private service with mutual TLS | NetworkPolicy allows only the **supervisor** service |
| Kubernetes | Its own pod | Private service with server-authenticated TLS and a sandbox JWT | NetworkPolicy allows only the **supervisor** service |
| VM | A process on the host | Authenticated vsock | Guest has no network device |

The runtime's job is to build the boundary and prove it's in place. It never
Expand All @@ -126,15 +126,15 @@ do.

## How Components Authenticate

Three connections tie a sandbox together. The gateway is the only component
that signs credentials, and every credential names exactly one sandbox.
Three connections tie a sandbox session together. The gateway signs the
session's gateway and sandbox JWTs, each bound to that sandbox and generation.

![OpenShell sandbox authentication showing the compute driver giving the supervisor a bootstrap credential, the gateway issuing a gateway JWT and sandbox JWT, and the supervisor presenting the sandbox JWT over mutual TLS to the sandbox, which holds only the gateway's public key.](../images/openshell-sandbox-authentication.svg)
![OpenShell sandbox authentication showing the gateway preissuing session JWTs, delivery to dedicated supervisors through the compute driver or to shared supervisors through a host-JWT-authenticated assignment stream, and the supervisor presenting the sandbox JWT over server-authenticated TLS to the sandbox.](../images/openshell-sandbox-authentication.svg)

| Connection | Who connects | How it's protected |
|---|---|---|
| **Supervisor** to gateway | The **supervisor** dials out to the gateway. | A gateway JWT, over TLS when the gateway has TLS enabled. |
| **Supervisor** to **sandbox** | The **supervisor** dials into the workload over the driver's private channel. | Mutual TLS, plus a sandbox JWT. |
| **Supervisor** to **sandbox** | The **supervisor** acts as the TLS and gRPC client over the driver's private channel. The runtime can initiate the underlying transport connection. | TLS authenticates the **sandbox** server; the sandbox JWT authenticates the **supervisor**. No TLS client certificate is used. |
| Agent to **supervisor** | The agent never connects directly. The **sandbox** relays its traffic over the connection above. | Covered by the supervisor-to-sandbox channel. |

The **supervisor** verifies the gateway's TLS certificate with its CA. User
Expand All @@ -143,27 +143,32 @@ workload; the gateway JWT authenticates supervisor RPCs.

### Getting the first credential

The **supervisor** needs a starting credential to prove which sandbox it belongs
to. How it gets one depends on the runtime:
The gateway prepares session credentials for each sandbox generation and
delivers them through trusted launch provisioning:

- **Docker, Podman, and MicroVM.** The driver hands the **supervisor** its initial
tokens directly, in files only the **supervisor** can read.
- **Kubernetes.** The **supervisor** presents its pod's ServiceAccount token. The
gateway asks the Kubernetes driver to verify the token and confirm that the
pod belongs to the expected sandbox before it issues any JWTs.
- **Docker, Podman, and MicroVM.** The driver supplies the dedicated
**supervisor** with private credential files.
- **Kubernetes, dedicated supervisor.** The driver mounts the preissued
credential bundle from a Secret into the **supervisor** pod.
- **Kubernetes, shared supervisor.** Each sandbox's credential bundle arrives
in its assignment over the authenticated supervisor-host stream.

Either way, the gateway checks the claim against its own record of the sandbox
before returning credentials.
A separate `IssueSandboxToken` exchange accepts a compute-driver bootstrap
identity. On Kubernetes, the driver validates a projected ServiceAccount token
and its pod and owner identity. The gateway compares the driver and runtime
identity with its stored sandbox record before returning a gateway JWT. This
exchange is not required for supervisors provisioned with a credential bundle.

### Gateway and Sandbox JWTs

The gateway issues a pair of JWTs for each run of a sandbox:

- **Gateway JWT.** Sent with every **supervisor** call to the gateway. It allows
only the calls a **supervisor** needs, such as fetching policy, pushing logs, and
- **Gateway JWT.** Authenticates the **supervisor**'s sandbox-specific calls to
the gateway. It allows only the calls a **supervisor** needs, such as fetching policy, pushing logs, and
relaying sessions. It is not a user credential and can't manage other
sandboxes.
- **Sandbox JWT.** Sent with every **supervisor** call to the **sandbox**.
- **Sandbox JWT.** Authenticates boundary opening and the **supervisor**'s control
and mediation streams to the **sandbox**.
The **sandbox** holds only the gateway's public key, so it can verify the
token but can never create one.

Expand All @@ -172,11 +177,17 @@ one run of that sandbox, called a generation. Restarting a sandbox starts a new
generation with fresh tokens and fresh TLS certificates, and the old ones stop
working.

Shared Kubernetes supervisors also use a separate, gateway-scoped supervisor-host
JWT to receive assignments. The pool's replicas share this token, which
authorizes only the host assignment stream. The gateway checks assignment
ownership separately, and each assigned sandbox still uses its own session JWTs.
See [Multi-tenant Supervisor](/kubernetes/high-availability#experimental-multi-tenant-supervisor).

### Renewing and revoking

The **supervisor** keeps its tokens in memory and renews both together before they
expire. Renewal works only while the sandbox still exists, so deleting a
sandbox cuts off its **supervisor**.
The **supervisor** keeps its session tokens in memory and renews both together
before they expire. Renewal works only while the sandbox still exists, so
deleting a sandbox ends that sandbox's session.

Shared deployments, such as Kubernetes, should set `gateway_jwt.ttl_secs` so
tokens expire. Local single-user gateways can leave it unset, which issues
Expand All @@ -189,9 +200,15 @@ the **sandbox** holds nothing worth stealing: no gateway signing key, no
gateway JWT, and no provider credentials. It can verify that it's talking to
the right **supervisor**, but it can't impersonate one.

If the **supervisor** disconnects, the **sandbox** freezes the agent. Only the
same **supervisor** process can reconnect and resume it. A new **supervisor** can't
take over a running sandbox, even with valid credentials.
If the **supervisor** disconnects, the **sandbox** freezes the agent. The same
**supervisor** process can reconnect and resume it within the recovery window.
In a [shared Kubernetes supervisor pool](/kubernetes/high-availability#recover-from-a-supervisor-failure),
the gateway can authorize a replacement **supervisor** with a signed takeover
grant for that sandbox generation and a higher ownership epoch. When the
replacement confirms the boundary, a runtime that supports takeover revokes the
previous owner's access and resumes the agent. Valid session credentials alone do not
authorize takeover. If recovery does not complete before the deadline, the
runtime terminates the workload.

## Working With Your Existing Infrastructure

Expand Down
11 changes: 6 additions & 5 deletions docs/how-it-works/inference.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,8 @@ response = client.chat.completions.create(

For an authenticated alternate endpoint, declare a credential in the custom
profile, bind it to that endpoint, and create the provider from the original
credential source. OpenShell never exports stored credential values.
credential source. The workload receives an opaque placeholder. Separately, an
explicitly enabled [mTLS operator can retrieve runtime credential values](/how-it-works/providers/overview#retrieve-runtime-credentials).

## Verify Access

Expand Down Expand Up @@ -264,8 +265,8 @@ openshell provider create \
openshell sandbox provider attach inference-demo nvidia-native-prod --wait
```

OpenShell does not export stored credential values or change a provider's
profile type in place. If the original credential source is unavailable, import
Provider inspection commands do not export stored credential values, and you
cannot change a provider's profile type in place. If the original credential source is unavailable, import
the original profile at its own ID so the preserved provider keeps resolving
while you arrange credential rotation into the replacement provider.

Expand Down Expand Up @@ -308,8 +309,8 @@ Special cases require additional work:

## Security Differences

Provider attachment preserves credential non-disclosure: workloads receive
opaque placeholders, and the proxy substitutes a real credential only after
Provider attachment delivers opaque placeholders to workloads, and the proxy
substitutes a real credential only after
network policy and endpoint binding both pass. Native requests are no longer
filtered or rewritten by a model-specific router. The provider profile's L7
rules therefore define the allowed API surface, and the workload controls
Expand Down
14 changes: 9 additions & 5 deletions docs/how-it-works/policies/default-policy.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,16 @@ additional paths when the corresponding GPU device is present:
| Access | Paths |
|---|---|
| Read-only | `/run/nvidia-persistenced`, `/usr/lib/wsl` |
| Read-write | `/dev/nvidiactl`, `/dev/nvidia-uvm`, `/dev/nvidia-uvm-tools`, `/dev/nvidia-modeset`, `/dev/dxg`, numbered `/dev/nvidia<N>` device nodes, and `/proc` |
| Read-write | `/dev/nvidiactl`, `/dev/nvidia-uvm`, `/dev/nvidia-uvm-tools`, `/dev/nvidia-modeset`, `/dev/dxg`, numbered `/dev/nvidia<N>` device nodes |

CUDA writes thread names under `/proc` during initialization, so GPU enrichment
moves `/proc` from read-only to read-write. OpenShell adds each path only when
it exists in the workload. These paths apply at runtime and are not saved in
the sandbox's policy.
OpenShell adds each path only when it exists in the workload. These paths apply
at runtime and are not saved in the sandbox's policy. GPU enrichment does not
change the filesystem policy's access to `/proc`.

CUDA can write thread names during initialization through the runtime's narrow
`/proc` exception. The runtime brokers supported `comm` writes only for threads
in the calling process's own thread group. This exception also applies without
a GPU and does not grant general write access to `/proc`.

### Protected Paths

Expand Down
6 changes: 3 additions & 3 deletions docs/how-it-works/providers/aws.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
# SPDX-License-Identifier: Apache-2.0
title: "AWS SigV4 Credential Signing"
sidebar-title: "AWS"
description: "Configure proxy-side AWS SigV4 request signing so sandbox agents can reach AWS services through CONNECT tunnels without holding real credentials."
description: "Configure proxy-side AWS SigV4 request signing so sandbox agents can reach AWS services through CONNECT tunnels using placeholder credentials."
keywords: "Generative AI, Cybersecurity, AI Agents, AWS, SigV4, Bedrock, S3, Credential Signing, Sandbox"
---

AWS SigV4 credential signing lets sandbox agents call AWS services (Bedrock, S3, STS, and others) through the proxy's CONNECT tunnel. The proxy intercepts outbound requests, strips the sandbox client's placeholder `Authorization` header, and re-signs the request with real AWS credentials from the provider. The sandbox never sees the real credentials.
AWS SigV4 credential signing lets sandbox agents call AWS services (Bedrock, S3, STS, and others) through the proxy's CONNECT tunnel. The proxy intercepts outbound requests, strips the sandbox client's placeholder `Authorization` header, and re-signs the request with real AWS credentials from the provider. The sandbox uses placeholder credentials; signing with the provider's credentials happens in the proxy. See [How Credential Injection Works](/how-it-works/providers/overview#how-credential-injection-works) for credential delivery and response-handling limits.

## Prerequisites

Expand Down Expand Up @@ -169,7 +169,7 @@ endpoints:

## Use from a Sandbox

Inside a sandbox, configure the AWS SDK with placeholder credentials. The proxy replaces them with real credentials during re-signing:
Inside a sandbox, configure the AWS SDK with placeholder credentials. The proxy uses the provider's real credentials to re-sign requests:

```shell
export AWS_ACCESS_KEY_ID=placeholder
Expand Down
18 changes: 15 additions & 3 deletions docs/how-it-works/providers/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,16 @@ The update records which sandboxes are attached before saving the new credential

Credential refresh status tells you whether OpenShell obtained credentials. [Provider readiness](/how-it-works/providers/profiles#inspect-provider-readiness) tells you whether the sandbox applied the credentials, policy, and environment for new processes. It does not test access to a backend model or cancel requests already sent upstream.

After a static credential update completes, launch a new client process to use the updated reference. An existing process keeps its revision-scoped reference; readiness does not make that old reference resolve the new value. Acknowledged detach revokes retained references and removes them from environments for future launches.
After an ordinary static credential update completes, launch a new client
process to use the updated reference. Existing processes keep their environment
references; readiness does not guarantee that they use the replacement value.
Credentials configured with
[`stable_placeholder: true`](/how-it-works/providers/profiles#keep-an-externally-updated-placeholder-stable)
let processes already holding a stable reference use a value-only update after
the supervisor installs it. See
[Runtime Limitations](/how-it-works/providers/profiles#runtime-limitations) for
retained revision behavior. Acknowledged detach revokes retained references and
removes them from environments for future launches.

Set or clear a credential expiry timestamp:

Expand Down Expand Up @@ -437,10 +446,13 @@ state.

## How Credential Injection Works

The agent process inside the sandbox never sees real credential values. At
startup, OpenShell replaces each credential with an opaque placeholder token in
At startup, OpenShell supplies each eligible provider credential as an opaque placeholder token in
the agent's environment. When the agent sends an HTTP request containing a
placeholder, the proxy resolves it immediately before forwarding the request.
Credential injection does not automatically scrub credential values from
upstream responses, so send credentialed requests only to trusted endpoints.
Operator retrieval is a separate export path described in
[Retrieve Runtime Credentials](#retrieve-runtime-credentials).

Static credential resolution has three independent authorization boundaries:

Expand Down
Loading
Loading