* feat(policy): accept numeric UIDs in sandbox process identity validation Allow run_as_user and run_as_group to be either the literal 'sandbox' or a numeric UID/GID within [1000, 2_000_000_000]. This removes the hard dependency on a baked-in 'sandbox' user in container images, enabling compute drivers to inject resolved UIDs at sandbox creation. Phase 1 of #1959. Signed-off-by: Seth Jennings <sjenning@redhat.com> * feat(supervisor): accept numeric UIDs for process identity dropping Allow run_as_user and run_as_group to be numeric UIDs/GIDs, removing the hard dependency on a baked-in 'sandbox' user in container images. Changes: - validate_sandbox_user(): accepts numeric UIDs without passwd lookup (logs OCSF event); keeps passwd check for "sandbox" name; rejects non-numeric non-sandbox strings that fail passwd lookup - prepare_filesystem(): passes numeric UIDs/GIDs directly to chown() instead of requiring a passwd entry - drop_privileges(): resolves numeric UIDs/GIDs directly via UID::from_raw / Gid::from_raw; skips initgroups when target uid matches current euid; uses guard conditions before setgid/setuid calls - session_user_and_home(): falls back to ("{uid}", "/sandbox") for numeric UIDs, avoiding a passwd lookup that will fail Re-exports MIN_SANDBOX_UID and MAX_SANDBOX_UID from openshell-policy so callers have consistent range constants. Phase 2 of #1959. Signed-off-by: Seth Jennings <sjenning@redhat.com> * feat(driver-kubernetes): resolve sandbox UID/GID from config or OpenShift SCC annotations Phase 3 of the numeric-UID plan: allow operators to specify explicit sandbox_uid/sandbox_gid in Kubernetes driver config, auto-detect from OpenShift SCC namespace annotations, and propagate resolved values to supervisor container env vars and PVC init container securityContext. Changes: - Add sandbox_uid/sandbox_gid fields to KubernetesComputeConfig - Add SANDBOX_UID/SANDBOX_GID env var constants to openshell-core - Implement resolve_sandbox_identity() to fetch namespace annotations and auto-detect OpenShift SCC UID ranges (sa.scc.uid-range) - Pass resolved UID/GID through SandboxPodParams to pod spec builder - Inject SANDBOX_UID/SANDBOX_GID env vars into supervisor container - Update PVC init container securityContext with resolved UID/GID instead of hard-coded root - Add comprehensive unit tests for resolution logic and annotation parsing (resolve_sandbox_uid, resolve_sandbox_gid, OpenShift SCC annotation parsing) Signed-off-by: Seth Jennings <sjenning@redhat.com> * feat(driver-vm): add configurable sandbox UID/GID and update docs/examples Phase 4 of the numeric-UID plan: replace hardcoded SANDBOX_UID (10001) in VM rootfs preparation with configurable sandbox_uid/sandbox_gid fields. Changes: - Add sandbox_uid/sandbox_gid to VmDriverConfig with serde derives - Pass resolved UID/GID through prepare_sandbox_rootfs_from_image_root to ensure_sandbox_guest_user which writes /etc/passwd/group/gshadow - Update BYOC Dockerfile: remove groupadd/useradd, document runtime UID injection and the ability to skip baked-in sandbox user - Update gateway-config.mdx: document sandbox_uid/sandbox_gid for both Kubernetes (with OpenShift SCC autodetection) and VM drivers - Update sandbox-compute-drivers.mdx: add Sandbox User Identity section explaining numeric UID support across all compute drivers - Update rootfs tests to use non-default UIDs, verify config passthrough Signed-off-by: Seth Jennings <sjenning@redhat.com> * code review changes * fix(supervisor): harden tests for restricted CI container environments Guard tests against CI-specific constraints: root without CAP_SETPCAP, UIDs with no /etc/passwd entry, and restricted /proc access. Signed-off-by: Seth Jennings <sjennings@nvidia.com> Signed-off-by: Seth Jennings <sjenning@redhat.com> --------- Signed-off-by: Seth Jennings <sjenning@redhat.com> Signed-off-by: Seth Jennings <sjennings@nvidia.com>
Bring Your Own Container
Run a sandbox with a custom container image. This example includes a ready-to-use Python REST API that you can build, deploy, and reach from your local machine through port forwarding.
Prerequisites
- A running OpenShell gateway (
mise run gateway:dockerfor local development) - Docker daemon running
What's in this example
| File | Description |
|---|---|
Dockerfile |
Builds a Python 3.12 image that starts a REST API |
app.py |
Minimal HTTP server with /hello and /health routes |
Quick start
1. Create a sandbox from the Dockerfile with port forwarding
openshell sandbox create \
--from examples/bring-your-own-container/Dockerfile \
--forward 8080 \
-- python /sandbox/app.py
The --from flag accepts a Dockerfile path. The CLI builds the image,
pushes it into the cluster, and creates the sandbox in one step.
The --forward 8080 flag opens an SSH tunnel so localhost:8080 on your
machine reaches the REST API inside the sandbox.
Important: The image's CMD / ENTRYPOINT does not run automatically.
OpenShell replaces it with the sandbox supervisor (which manages SSH access,
network policy, etc.). You must pass your application's start command
after -- so it is executed via SSH once the sandbox is ready.
2. Hit the API
curl http://localhost:8080/hello
# {"message": "hello from OpenShell sandbox!"}
curl http://localhost:8080/hello/world
# {"message": "hello, world!"}
curl http://localhost:8080/health
# {"status": "ok"}
Running your own app
Replace app.py and the Dockerfile with your own application. The
key requirements are:
- Pass your start command explicitly — use
-- <command>on the CLI. The image'sCMD/ENTRYPOINTis replaced by the sandbox supervisor at runtime. - Create a
sandboxuser (uid/gid 1000660000) for non-root execution. Use a high UID (1000000000+) to avoid conflicts with host users when running without user namespace remapping. - Make your application workdir writable by
sandbox. This example creates/sandboxwithsandbox:sandboxownership before copyingapp.py. - Install
iproute2for full network namespace isolation. - Use a standard Linux base image — distroless and
FROM scratchimages are not supported.
TODO(#70): Remove the sandbox user note once custom images are secure by default without requiring manual setup.
How it works
OpenShell handles all the wiring automatically. You build a standard
Linux container image — no OpenShell-specific dependencies or
configuration required. When you create a sandbox with --from,
OpenShell ensures that sandboxing (network policy, filesystem isolation,
SSH access) works the same as with the default image.
Port forwarding is entirely client-side: the CLI spawns a background
ssh -L tunnel through the gateway. The sandbox's embedded SSH daemon
bridges the tunnel to 127.0.0.1:<port> inside the container.
Cleanup
Delete the sandbox when you're done (this also stops port forwards):
openshell sandbox delete <sandbox-name>