Repository navigation
Conversation
Propose four supervisor deployment models (per workspace, per node, per sandbox, per gateway) with shared safety rules for fenced recovery, and set out how to compare them and choose one. Refs NVIDIA#4311. Signed-off-by: divesh <dgude@nvidia.com>
65bc1ef to
21a0f97
Compare
|
Thanks for opening this. Some input from the Agent Substrate side, mostly on one case the RFC doesn't cover yet: a backend suspending a sandbox on purpose. Suspended sandboxes On Agent Substrate an idle sandbox is suspended and uses no compute, and it can resume later, possibly on a different node. The RFC's resume path is about replacing a failed supervisor. For a backend-initiated suspend, we'd hope for the following:
Placement Our lean is a pool that isn't tied to nodes: one HA deployment per install, or per gateway group, scaled horizontally, with sessions assignable to any replica. Per node fits a suspend-capable backend poorly, because sandboxes move between nodes on resume and many nodes would mostly hold sleeping sandboxes. Per workspace tends to split capacity. Capacity If suspended sandboxes release their sessions, the number to size supervisors for on a backend like ours is active sandboxes, not total sandboxes. Happy to walk through what we saw in our prototype, and to review as the comparison of the four models takes shape. |
|
will take this into consideration and update the RFC, thanks @mayawang |
Rewrite the proposal in plain language and shorten it. Address review notes on defaults, readiness, relay caps, the network fence, node drain, the driver reconciler, and token fencing on takeover. Signed-off-by: divesh <dgude@nvidia.com>
|
Thanks @mayawang. Suspend isn't supported in OpenShell yet, so I've listed backend-initiated suspend (#4352) as a separate non-goal, but the design leaves scope for it as a planned release plus a fresh assignment on wake. I also noted that per-node fits poorly with backends that move sandboxes, and that capacity should be sized by active sandboxes. |
Trim the proposal without dropping content. Note backend-initiated suspend as a separate task, per-node fit with backends that move sandboxes, and sizing by active sandboxes. Signed-off-by: divesh <dgude@nvidia.com>
There was a problem hiding this comment.
Almost there, thanks for the quick turnaround. 9 of the 13 threads are fixed in the text, so go ahead and resolve those.
Two small things before I approve:
- L147, see inline.
- The four items you're leaving for the prototype (per-node binding, per-replica vs per-sandbox lease, launch material delivery, lease renewal path) aren't in the RFC yet. Could you list them under Open questions so they don't get lost?
Also I think this would be a feature behind a k8s feature gate, maybe worth documenting.
|
|
||
| `detect + fence + start candidate + restore state + confirm + margin < 30 s` | ||
|
|
||
| If PostgreSQL is down, no takeovers or lease renewals happen. Running sandboxes continue until their lease ends, then freeze and stop, trading availability for safety. The database must never reuse an epoch, even after failover or restore. |
There was a problem hiding this comment.
Today a PostgreSQL outage doesn't stop running sandboxes (RFC 0012 treats gateway loss as a reconnect, not supervisor loss). Can you scope the lease to resume-enabled runs here, like we discussed in the lease thread? Otherwise a long DB outage stops every opted-in sandbox.
There was a problem hiding this comment.
Done: the lease applies only to runs with resume enabled and is checked only for takeovers. The runtime's freeze-on-disconnect is the fence, so a PostgreSQL outage never stops running sandboxes; only takeovers wait.
Signed-off-by: Dhiraj Bokde <dbokde@nvidia.com>
docs(rfc): define sandbox workload identity for shared supervisors
|
|
||
| The exchange protocol must specify the SVID form, intended audience, and proof required by each provider. For bearer-token exchange, the client obtains a JWT-SVID for the intended recipient; an X.509-SVID certificate alone is not proof of possession. X.509 private keys MUST remain in the Sandbox Pod and must never be forwarded to the Supervisor. | ||
|
|
||
| Identity context and exchanged credential caches remain scoped to the sandbox/run, provider, and audience. The client refreshes the SVID before expiry and forwards updates to the active Supervisor. After fenced handover, the client supplies a current SVID to the replacement Supervisor, which validates and binds it to the new session and epoch before fetching fresh credentials. Missing, expired, or mismatched identity must fail closed for operations requiring it, without falling back to another sandbox's identity or the Supervisor's identity. Workload identity does not replace the recovery grant or fencing rules in section 3. |
There was a problem hiding this comment.
The JWT-SVIDs should be short lived. Might it make sense for the supervisor to pull them rather than for the sandbox to push them? I.e. when the supervisor needs a new JWT-SVID, it makes a call to the sandbox which then retrieves the new token from the SPIFFE workload API and returns it?
There was a problem hiding this comment.
Agreed. FrostGod/OpenShell#2 proposes on-demand retrieval of short-lived, audience-specific JWT-SVIDs, with caches bounded by expiry and sandbox/run/ownership. Authorized middleware can use the same interface to inject an SVID into a configured X-Workload-SVID header for an admitted destination, replacing any agent-supplied value.
| New->>RT: Present grant | ||
| RT->>RT: Reject epoch e, close old channels | ||
| RT-->>New: Signed receipt and saved state | ||
| New->>GW: Fetch policy, send receipt |
There was a problem hiding this comment.
With config push (#4320, the only mode after #4498), policy and provider credentials flow down the already-open session, so rotating the token (L105) no longer cuts the old owner off from them. Worth a line here: the epoch CAS closes any older-epoch session, and this step becomes a pushed bootstrap that the candidate acks on a session at the reserved epoch (config only, no relays) before activation.
There was a problem hiding this comment.
Added a paragraph covering both config modes. In poll mode the new token ID cuts off the old owner. In push mode the epoch CAS also closes every older-epoch session. In both, the new supervisor acknowledges a config-only setup push at the reserved epoch before activation.
|
|
||
| Sharing a supervisor must preserve each sandbox's workload identity. For Kubernetes deployments using pod-specific SPIFFE Verifiable Identity Documents (SVIDs), the identity issuer must distinguish individual Sandbox Pods, even when they share a service account. The shared proxy Supervisor Pod's service identity does not represent the workloads it supervises. | ||
|
|
||
| The gRPC client running in the Sandbox Pod MUST obtain that Pod's SVID through the [SPIFFE Workload API](https://spiffe.io/docs/latest/deploying/svids/) Unix domain socket (UDS) exposed locally in the Sandbox Pod and pass the SVID over the authenticated gRPC connection to the Supervisor running in the shared proxy Supervisor Pod. Access to the UDS must preserve workload attestation so the client receives only identities authorized for its Sandbox Pod. |
There was a problem hiding this comment.
This puts the Workload API socket in the Pod where the agent runs, with the same UID as the runtime, so attestation can't keep the agent from minting JWT-SVIDs for any audience. The K8s driver strips spiffe-workload-api from the workload Pod today on purpose. Could the shared supervisor fetch them instead (SPIRE's Delegated Identity API)? I'd also scope this section to shared models, since per-sandbox already works. Small thing: nothing in the Sandbox Pod is a gRPC client today, the supervisor dials the runtime.
There was a problem hiding this comment.
SPIRE's Delegated Identity API works at the Agent scope i.e. at node scope on kubernetes. So you can't - as far as I know - allow a given supervisor to only retrieve SVIDs for the sandbox pods it is serving.
Though not ideal, the agent requesting SVIDs for any given audience is not in itself necessarily a problem. The SVID merely proves the identity of the workload that retrieved it. It is for accessed services to verify the SVIDs and determine if that workload is indeed authorized. The network restrictions also only allow the agent to communicate out through the supervisor, so it is only approved endpoints that can be reached.
Another problem with having the Workload API mounted on the sandbox pod though is when kata containers are used as the SPIRE socket isn't accessible from inside the VM.
The SPIFFE Broker API could be an option but it is still 'experimental'.
There was a problem hiding this comment.
Could the current broker in the supervisor be extended to prevent the agent from making connect) calls to domain sockets (while allowing itself to do so)? That could restrict the agent from accessing the Workload API, but would also prevent use of any other domain sockets. Is that too restrictive? Are there legitimate cases where an agent should be allowed to access a socket?
(Still does not solve the kata problem though)
There was a problem hiding this comment.
Blocking all Unix sockets would break things agents rely on, such as language servers, tmux and ssh-agent. Blocking only the SPIFFE socket isn't safe either, because the agent can change the socket path after we check it. Simplest is to keep the socket out of the agent's view, as we do today, and let the runtime or supervisor fetch SVIDs for it. We'll pick the approach during implementation.
let me get to the kata part
There was a problem hiding this comment.
Agreed: keep the Workload API socket outside the agent's view and leave the acquisition backend to implementation. FrostGod/OpenShell#2 scopes section 5 to shared supervisors, preserves the supervisor-initiated runtime channel, and flags node-wide delegation for separate authorization review.
Kata's host-to-guest UDS limitation is independent of supervisor topology. For Teleport, a bot sidecar inside the Kata VM can expose a guest-local socket, provided issuance is sandbox-scoped and the socket, credentials, and configuration are isolated from the agent. This remains a deployment option to validate.
| Provider-->>Supervisor: Credentials scoped to that sandbox | ||
| ``` | ||
|
|
||
| The Supervisor MUST validate the SVID against the configured trust bundle and expected workload identity, including validity and audience where applicable, and bind it to the authenticated sandbox/run session and current ownership epoch. A caller-supplied sandbox ID alone cannot establish that binding. The validated Sandbox SVID MUST be used as the workload identity for dynamic Credential Provider exchange and other identity-dependent operations performed on behalf of that sandbox. The Supervisor must not substitute its own SVID: doing so would collapse distinct sandbox identities into one shared identity and lose per-sandbox authorization and attribution. |
There was a problem hiding this comment.
The gateway needs this check too. validate_supervisor_jwt_svid checks issuer, audience and trust domain, but not that sub is this sandbox. That's OK while each supervisor can only fetch its own SVID. Once one process holds many, a mix-up can hand one sandbox's credentials to another, so let's have the gateway match sub against the authenticated sandbox.
There was a problem hiding this comment.
Agreed. FrostGod/OpenShell#2 requires the gateway to independently validate the SVID and match sub to the authenticated sandbox using trusted control-plane state, with use bound to the current run and ownership epoch.
|
will be addressing the comments today, was not online yesterday |
3b9639f to
cd5e6ae
Compare
Signed-off-by: divesh <dgude@nvidia.com>
cd5e6ae to
c3d6029
Compare
Signed-off-by: Dhiraj Bokde <dbokde@nvidia.com>
…y/dhirajsb docs(rfc): clarify workload identity for shared supervisors
Summary
Adds RFC 0018, which proposes four ways to deploy supervisors: per workspace, per node, per sandbox, and per gateway. It sets out one shared set of safety rules for replacing a failed supervisor (fencing), and a plan to compare the four models and choose one.
Related Issue
Refs #4311. This PR only adds the RFC and changes no code. It also builds on #3661 and #2385.
Changes
rfc/0018-multi-sandbox-ha-supervisors/README.mdwith goals, the four proposed models, and the shared rules (fenced recovery, ownership epoch, leases).Testing
Docs-only change, so there are no unit or E2E tests. The RFC links, the Mermaid diagrams, and the headings are checked by eye. The full
mise run pre-commithas not completed on this branch: the first run failed on a localuvenvironment error unrelated to the RFC, and the rerun did not start.Checklist