Files
OpenShell/examples/private-ip-routing
50230616d5 refactor(runtime): retire Community image dependencies (#3386)
* feat(sandbox): default to official Alpine sandbox image

default_sandbox_image() now returns docker.io/library/alpine:3.22, a generic
version-qualified official image, so a fresh install no longer depends on the
community sandbox image catalog. All compute drivers (docker, podman,
kubernetes, vm) inherit this fallback.

Part of #3116.

Signed-off-by: Akram
Signed-off-by: Akram <akram.benaissi@gmail.com>

* feat(deploy): default deployment configs to the official Alpine sandbox image

Update the shared gateway default_image, Helm chart values, the standalone
Kubernetes manifest, and the dev gateway task scripts to use
docker.io/library/alpine:3.22 instead of the community base image, consistent
with default_sandbox_image(). GPU e2e image-build base is left unchanged (CUDA
needs a glibc base).

Part of #3116.

Signed-off-by: Akram
Signed-off-by: Akram <akram.benaissi@gmail.com>

* feat(driver): default to numeric non-root identity for USER-less images

With the default sandbox image now Alpine, images that declare no OCI USER
must start instead of being rejected. When the image declares no USER and
the policy requests none, the Podman and Docker drivers now supply a numeric
non-root identity (DEFAULT_SANDBOX_UID/GID = 1000) instead of rejecting,
matching the numeric-identity behavior of the Kubernetes and VM drivers. The
supervisor's resolved-identity path runs the sandbox as a synthesized
non-root account without the account existing in the image. Images that
declare a USER keep the OCI resolution path unchanged.

Part of #3116.

Signed-off-by: Akram <akram.benaissi@gmail.com>
Signed-off-by: Evan Lezar <elezar@nvidia.com>

* test(conformance): use Alpine workload image

Signed-off-by: Evan Lezar <elezar@nvidia.com>

* refactor(policy): drop community image /app path from default policy

The restrictive default policy granted read-only access to /app, a directory
that only existed in the community base image. A generic Alpine default has no
/app, so remove it. Landlock best-effort already ignores absent paths; this
just stops advertising a community-specific layout in the default.

Part of #3116.

Signed-off-by: Akram
Signed-off-by: Akram <akram.benaissi@gmail.com>

* docs(config): document Alpine default images

Signed-off-by: Evan Lezar <elezar@nvidia.com>

* fix(podman): report early sandbox termination

Signed-off-by: Evan Lezar <elezar@nvidia.com>

* fix(podman): initialize rootless workspace ownership

Signed-off-by: Evan Lezar <elezar@nvidia.com>

* fix(sandbox): qualify NVIDIA Ubuntu default

Signed-off-by: Drew Newberry <anewberry@nvidia.com>

* fix(podman): initialize rootful default workspace

Signed-off-by: Drew Newberry <anewberry@nvidia.com>

* feat(sftp): add native sandbox adapter

Signed-off-by: Drew Newberry <anewberry@nvidia.com>

* fix(sftp): gate runtime helper support to Linux

Signed-off-by: Drew Newberry <anewberry@nvidia.com>

* fix(sftp): support standard OpenSSH file operations

Signed-off-by: Drew Newberry <anewberry@nvidia.com>

* fix(sftp): harden rename and special file handling

Signed-off-by: Drew Newberry <anewberry@nvidia.com>

* refactor(runtime): remove community image dependencies

Signed-off-by: Drew Newberry <anewberry@nvidia.com>

* test(e2e): build provider readiness tool fixture

Signed-off-by: Drew Newberry <anewberry@nvidia.com>

* fix(e2e): use a dedicated Noble fixture for Docker tests

Signed-off-by: Evan Lezar <elezar@nvidia.com>

---------

Signed-off-by: Akram
Signed-off-by: Akram <akram.benaissi@gmail.com>
Signed-off-by: Evan Lezar <elezar@nvidia.com>
Signed-off-by: Drew Newberry <anewberry@nvidia.com>
Co-authored-by: Evan Lezar <elezar@nvidia.com>
Co-authored-by: Drew Newberry <anewberry@nvidia.com>
2026-09-22 14:43:51 +02:00
..

Private IP Routing via allowed_ips

Demonstrates the allowed_ips sandbox policy feature, which lets sandboxes reach services on private IP space (e.g. cluster-internal pods) that would normally be blocked by the proxy's SSRF protection.

How it works

The sandbox proxy blocks all connections to RFC 1918 addresses by default. When an endpoint in the sandbox policy includes an allowed_ips field, the proxy validates the resolved IP against that CIDR allowlist instead of blanket-blocking. Loopback and link-local remain always-blocked regardless.

Save an explicit policy as private-policy.yaml that allows the client binary to reach port 8080 on the configured pod network:

cluster_pods:
  name: cluster_pods
  endpoints:
    - port: 8080
      allowed_ips:
        - "10.42.0.0/16"
  binaries:
    - { path: "/**" }

Launch the demo server

Build the image and push it to a registry that your Kubernetes cluster can pull from:

docker build -t registry.example.com/demo/private-api:latest examples/private-ip-routing/
docker push registry.example.com/demo/private-api:latest

Deploy the pod:

kubectl run private-api \
  --image=registry.example.com/demo/private-api:latest \
  --port=8080 \
  --restart=Never

Wait for it to be running and note the pod IP:

kubectl get pod private-api -o wide

Example output:

NAME          READY   STATUS    IP            NODE
private-api   1/1     Running   10.42.0.128   ...

Verify from a sandbox

Create a sandbox and curl the private API through the proxy. Replace the IP with whatever kubectl get pod showed above:

openshell sandbox create \
  --from registry.example.com/tools/curl:latest \
  --policy ./private-policy.yaml \
  -- bash -c \
  'curl -s --proxytunnel -x http://10.200.0.1:3128 http://10.42.0.128:8080/'

Expected output:

{
  "message": "Hello from the private network!",
  "hostname": "private-api",
  "path": "/",
  "client": "10.42.0.130",
  "timestamp": 1772501542.15
}

The proxy allowed the connection because 10.42.0.128 matches the 10.42.0.0/16 CIDR in allowed_ips. Without that policy field, the same request returns HTTP/1.1 403 Forbidden.

Cleanup

kubectl delete pod private-api