kubectl.
The sandbox resource
Sandboxes are represented by theSandbox kind in the agents.x-k8s.io API group, served at
v1beta1 and scoped to a namespace. The type comes from the open-source
agent-sandbox project maintained under
Kubernetes SIG Apps, licensed Apache-2.0. hiloop runs the upstream controller from a pinned image
and consumes its API types as a versioned module rather than forking them.
The spec fields that carry a sandbox’s shape:
Status is observation, not intent:
conditions (Ready, Suspended, Finished), plus
nodeName and podIPs once scheduled. The controller is the only writer of status.
The reconcile loop
For each sandbox resource that is not being deleted, the controller:- Creates exactly one pod from
podTemplate, with an owner reference back to the sandbox. One sandbox is always one pod. Observing more than one live child pod for a sandbox is a contradiction, and the product record reports it as needing attention rather than picking a winner. - Re-propagates pod-template metadata onto the live pod on every reconcile, including scrubbing keys that were removed. This is how a control-plane annotation edit reaches a running pod without another controller in the path.
- Creates one claim per
volumeClaimTemplatesentry, owned by the sandbox rather than the pod. Because the claim’s owner is the sandbox, it outlives any single pod and is garbage-collected with the sandbox itself. - Writes status from pod readiness.
operatingMode: Suspended makes the controller
delete the sandbox’s pod, and setting it back to Running makes the controller create a
replacement. That is the entire lifecycle transition. Because storage owned by the sandbox is not
owned by the pod, a filesystem with its own lifetime survives the gap and is presented again to the
replacement pod. Processes do not: the replacement pod starts its image’s entrypoint from the
beginning.
The control plane reaches the cluster directly over the Kubernetes API and writes only merge
patches, never a server-side apply, so it never takes ownership of fields the controller manages.
Its write vocabulary against a sandbox is small: create, patch the operating mode and expiry,
annotate, and delete.
State is mirrored, never inferred
A separate status-mirror controller watches sandbox resources and sandbox pods and writes what it observed into the product record. The API answers reads from that record. This is why a sandbox’sstate reports evidence: a sandbox is running because a pod was observed ready, and out-of-band
pod death converges the record to a terminal state instead of leaving it green.
The mirror resolves contradictions explicitly rather than smoothing them. An unparseable organization
label, a missing resource identity, more than one child pod, or a runtime receipt it cannot read all
produce an attention state naming the anomaly, and a recorded capability contradiction produces
quarantined. It reconciles state; it never writes a pod.
What a sandbox is at the pod level
One pod, with one container that matters:- The workload container runs your image’s entrypoint unmodified. No command, no arguments, no injected environment, and no security-context override are applied to it. What runs is what your image says runs, as the user your image declares.
restartPolicy: Never. A workload that exits has exited; it is not silently restarted underneath you.- No Kubernetes service-account token is mounted. A sandbox cannot talk to the Kubernetes API, because it holds no credential for it.
- The pod requests the gVisor runtime class, which also carries a fixed per-pod memory overhead for the sandboxing layer so the scheduler accounts for it.
Reaching into a sandbox
hiloop sandbox exec is brokered through the Kubernetes API as an exec into the workload container.
The command’s real exit code is recovered from the API server’s terminating status frame rather than
inferred from a closed stream, so a non-zero exit is reported as a non-zero exit and not as a
transport error.
Interactive access is served by a small static server that runs inside the workload container, so a
shell sees your filesystem as your image’s own user. It shares the pod’s network namespace but not
its mount namespace, which is why the exec path, not the session path, is what reaches the
container’s own filesystem view.
Port forwarding through the container runtime is deliberately not offered. Runtime port-forward
implementations work by entering the pod’s host-side network namespace and dialing loopback, which
cannot reach a workload whose network stack lives in a user-space kernel. Forwarding a port is done
over the session instead, with the standard OpenSSH -L flag.
The isolation boundary
Sandboxes run arbitrary, untrusted images, so every control sits outside the workload.- gVisor. Each sandbox pod runs under the
runscruntime class: a user-space kernel that intercepts system calls instead of passing them to the host kernel. - Admission pins the boundary. A cluster admission policy evaluates sandbox resources at the API server and refuses any whose pod template does not request the gVisor runtime class, or which asks to share the host’s network, process, or IPC namespaces. The policy fails closed, and it binds the invariant to the API server rather than to the code that renders sandboxes, so neither a control-plane regression nor a stolen control-plane credential can place a customer workload on the host kernel.
- Pod Security. The sandbox namespace enforces the
baselinePod Security Standard and audits againstrestricted. Baseline rather than restricted is a considered choice: arbitrary customer images legitimately run as root and declare no seccomp or capability posture, so they cannot satisfy restricted. Baseline still refuses privileged containers and host namespace escapes at the API server as defense in depth. - Network policy. Ingress to sandboxes is default-deny, with a single exception for the control plane’s session port. Egress allows cluster DNS and the public internet while denying private address ranges and the link-local range, so a workload can reach the internet but not the deployment’s own infrastructure or the cloud metadata endpoint. See network access.
- An organization-scoped identity. Each organization’s sandboxes run under their own service account, with token mounting disabled.
- An object-count ceiling. A resource quota on sandbox objects bounds the fleet transactionally at the API server, behind the per-organization quotas applied at admission.
unsupported_capability rather than quietly
downgraded.
Related pages
- Deploy on Kubernetes: what to install, and what the chart needs from your cluster.
- Architecture: the components around the sandbox runtime.
- Sandbox lifecycle: the states and transitions this loop produces.
- Security model: the trust boundaries in full.