agent-infra / agent-infra/sandbox
Support running the container as non-root (rootless) for hardened Kubernetes environments
- Ngôn ngữ chính
- Python
- Star
- 5.9k
- Fork
- 529
- Merge trung bình
- 4 giờ 8 phút
- Pull request đã merge (30 ngày)
- 4
Mô tả
## Problem
The image is root-first: `run.sh` → `gem_init.sh` → `gem.sh` run as **root**, performing `useradd`, `chown`, sudoers setup and `su - gem`, and then `supervisord` starts as root and drops each program to `user=gem`.
This makes the image unusable on platforms that **mandate** `runAsNonRoot` / a restricted PodSecurity or admission policy (e.g. GKE Autopilot's hardening policy, OpenShift's default SCC, any cluster enforcing `runAsNonRoot: true`). Starting the container as a non-root UID crashes immediately, e.g.:
```
mkdir: cannot create directory '/var/run/gem': Permission denied
mkdir: cannot create directory '/var/log/gem': Permission denied
```
and, further along, `supervisord: Error: Can't drop privilege as nonroot user`.
Tested on `ghcr.io/agent-infra/sandbox:1.10.0` and `1.11.0`.
## Request
First-class rootless support — ideally the bootstrap detects `euid != 0` and skips the privilege-management steps, with the runtime paths being user-writable/configurable, so downstreams don't have to patch the image.
## What we did to make it run as UID 1000 (as a reference workaround)
All applied in a downstream layer, without editing the large `gem.sh`:
1. **Pre-create + `chown` every runtime dir at build time** (`/var/run/gem`, `/var/log/gem`, `/var/log/nginx`, `/var/lib/aio-sandbox` + nginx temp dirs, `/tmp/.X11-unix`, `/run/user/`, `/etc/browser/policies/managed`, `/opt/gem`, `/opt/aio`, …), and ensure the user exists. `mkdir -p` on an existing dir is an idempotent no-op for non-root, and `chmod` works on owned dirs.
2. **PATH shims** so that, when already non-root, `chown` becomes a no-op and `su - -c CMD` runs `CMD` directly (delegating to the real binary when root).
3. **supervisord**: drop `user=root`, move the socket/pid file to a user-writable dir, and strip the per-program `user=` lines (supervisord can't `setuid` when non-root, even to the same user).
4. **nginx**: point `pid` at a user-writable path and add a main-context `error_log` (otherwise it falls back to the root-owned compile default `/var/log/nginx/error.log`).
5. **`browser-supervisor.py`**: skip the privilege drop (`initgroups`/`setgid`/`setuid`) and the pid-file `chown` when already running as the target uid — otherwise the `preexec_fn` raises `Operation not permitted` and Chromium never starts. Chromium also needs `--no-sandbox` under non-root (the existing `BROWSER_NO_SANDBOX` env covers this).
With the above, the container runs entirely as UID 1000 and all services (nginx gateway, opencode, jupyter, code-server, VNC, browser + CDP, mcp) come up healthy.
Hướng dẫn đóng góp
Đánh giá
Issue này chưa được đánh giá.