Files
Russell Bryant c5d1d76d94 refactor(sandbox): replace iptables with nftables for network policy enforcement (#1401)
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>
2026-05-18 16:37:17 -07:00
..

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:docker for 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's CMD / ENTRYPOINT is replaced by the sandbox supervisor at runtime.
  • Create a sandbox user (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 /sandbox with sandbox:sandbox ownership before copying app.py.
  • Install iproute2 for full network namespace isolation.
  • Use a standard Linux base image — distroless and FROM scratch images 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>