Migrate all sandbox and VM driver network policy enforcement from iptables to nftables. nftables provides atomic ruleset loading, a cleaner rule syntax, and is the standard netfilter interface in modern kernels. Sandbox bypass enforcement (openshell-sandbox): - Replace iptables chain of individual rule insertions with a single atomic nftables ruleset load via nft -f - New nft_ruleset module with pure functions for ruleset generation and unit tests - Combine log and reject rules in one inet family table (handles both IPv4 and IPv6 in a single ruleset) - Fall back to reject-only ruleset when kernel lacks nft_log support - Enable net.netfilter.nf_log_all_netns so log rules work from non-init network namespaces - Use temp file for nft ruleset loading instead of stdin for compatibility with minimal VM guest environments VM TAP networking (openshell-driver-vm): - Replace iptables NAT/forwarding rules with nftables equivalents - New nft_ruleset module for TAP network rule generation with unit tests - Atomic table-per-TAP-device lifecycle (create/destroy) - Host-side rules provide NAT infrastructure and defense-in-depth isolation (input chain restricts VM to gateway port only, forward chain blocks unsolicited inbound); primary security enforcement happens inside the VM guest via the sandbox supervisor's own rules VM init script: - Load nft kernel modules at sandbox init - Enable nf_log_all_netns sysctl for bypass detection logging OCSF / docs: - Update firewall rule engine references from iptables to nftables - Document host firewall interaction model and two-layer enforcement architecture in VM driver README and compute drivers reference Closes #1335 Signed-off-by: Russell Bryant <rbryant@redhat.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>