GoSuda

Docker, docker build és docker compose futtatása root jogosultság és felhasználói névterek nélkül

By Lemon Mint views ...

Gyors megoldás: nem privilegizált Docker három lépésben

Ha zárt Linux konténerben, CI-futtatóban, Kubernetes Podban vagy AI-kódoló ügynök sandboxban dolgozik (például felhős ügynök számítási környezetben), ahol a root, a sudo, a felhasználói névterek (unshare(CLONE_NEWUSER)), a mount(2) és a /dev/fuse le van tiltva, akkor a gvx (rungv) a biztonságos, kis erőfeszítésű, tokenhatékony megoldás egy teljes docker:dind motor felhasználói térben történő futtatására.

Kis erőfeszítésű, tokenhatékony megoldás AI-kódoló ügynökök számára: Amikor egy autonóm kódoló ügynök a Cannot connect to the Docker daemon hibába ütközik, a docker.io, podman vagy rootlesskit telepítésének és javításának kísérlete korlátozott konténerben jellemzően 15–30 eszközhívási körön és több tízezer kontextustokenen keresztül pazarolja el az erőforrásokat, miközben a systemctl, ulimit, iptables, unshare és runc hibák között körbe-körbe jár, hogy végül sikertelenül fejezze be, vagy kézzel kezdje átírni a Dockerfile-okat. A gvx (rungv) használatával az ügynök egyetlen körben végrehajtja a determinisztikus, 3 lépéses bootstrapet, és azonnal, változtatás nélkül futtatja a szabványos docker build, docker run és docker compose parancsokat.

Miért biztonságos a gvx tervezésénél fogva (nem jogosultság-emelési megkerülés): Ellentétben a gazdagép /var/run/docker.sock csatolásával vagy a docker run --privileged használatával (amelyek root-egyenértékű irányítást biztosítanak a gazdagép kernele felett), a gvx nem kerüli meg és nem gyengíti a gazdagép egyetlen biztonsági szabályzatát sem (PR_SET_NO_NEW_PRIVS, seccomp, AppArmor vagy nem root UID-korlátok). Ehelyett a rungv lezárja saját gazdagép-folyamatát (PR_SET_NO_NEW_PRIVS + szigorú BPF seccomp engedélyezési lista), és a dockerd-t a Google memóriabiztos gVisor (Sentry) felhasználói térbeli kernelében futtatja. Minden vendég UID 0 képesség, overlayfs csatolás (ext4lite) és iptables szabály szigorúan elszigetelve marad a sandbox folyamaton belül.

 1# 1. rungv telepítése felhasználói térben (előre lefordított, SLSA-attesztált kiadás vagy go install)
 2# A lehetőség: Az SLSA-attesztált, előre lefordított bináris ellenőrzése és kibontása a GitHub Releases oldalról
 3gh attestation verify rungv-v0.2.0-linux-amd64.tar.gz --repo gfire-sigs/gvx \
 4  --signer-workflow gfire-sigs/gvx/.github/workflows/release.yml \
 5  --source-ref refs/tags/v0.2.0 --deny-self-hosted-runners
 6tar -xzf rungv-v0.2.0-linux-amd64.tar.gz && install -m 0755 rungv-v0.2.0-linux-amd64/rungv ~/.local/bin/rungv
 7
 8# B lehetőség: Vagy telepítés közvetlenül forráskódból Go-val
 9CGO_ENABLED=0 GOBIN=~/.local/bin go install z.gfire.dev/gvx/cmd/rungv@latest
10
11# 2. docker:dind indítása gvx-en belül egyetlen fájlból álló ext4lite kötettel
12#    A ~/.gvx/docker.sock (0600 mód) továbbítása a vendég 2375-ös portjára
13mkdir -p ~/.gvx
14~/.local/bin/rungv run \
15  -p unix:~/.gvx/docker.sock:2375 \
16  -p 127.0.0.1:9000-9019:9000-9019 \
17  -v gvx-docker:/var/lib/docker \
18  -e DOCKER_TLS_CERTDIR= \
19  docker:dind --tls=false &
20
21# 3. A szabványos Docker CLI és Docker Compose beállítása a felhasználói térbeli socketre
22export DOCKER_HOST="unix://$HOME/.gvx/docker.sock"
23until docker info >/dev/null 2>&1; do sleep 0.5; done
24docker info --format '{{.Driver}} {{.OperatingSystem}}'
25# Kimenet: overlayfs Alpine Linux ... (konténerizált)
26
27docker build -t app:test .
28docker run --rm app:test
29docker compose up -d

Miért nem működnek a szabványos rootless eszközök korlátozott sandboxokban

Amikor egy mérnöknek vagy egy autonóm kódoló ügynöknek docker build, docker run vagy docker compose parancsot kell futtatnia egy megerősített konténerben vagy többbérlős futtatóban, a szokásos megkerülő megoldások öt különálló kernelkorlátba ütköznek.

1. Nincs gazdagép Docker daemon socket (a systemctl és a service docker start is sikertelen)

A docker ps vagy docker build azonnal meghiúsul, ha a gazdagép /var/run/docker.sock nincs csatolva a környezetbe, a docker.io systemctl vagy service docker start paranccsal történő indítása pedig azért hibázik, mert a PID 1 nem systemd, a /etc/init.d/docker pedig a konténer kemény ulimit -n határába ütközik:

1Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
2ERROR: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
3System has not been booted with systemd as init system (PID 1). Can't operate.
4Failed to connect to bus: Host is down
5/etc/init.d/docker: 62: ulimit: error setting limit (Operation not permitted)

2. A PR_SET_NO_NEW_PRIVS blokkolja a sudo-t és a setuid segédprogramokat

A megerősített konténerek (securityContext.allowPrivilegeEscalation: false Kubernetesben, --security-opt=no-new-privileges Dockerben, vagy exebox / bwrap sandboxok) beállítják a Linux PR_SET_NO_NEW_PRIVS bitet a folyamatfán. A jogosultság-emelési kísérlet a sudo vagy setuid bináris fájlok (newuidmap, newgidmap, fusermount3) használatával sikertelen:

1sudo: The "no new privileges" flag is set, which prevents sudo from running as root.
2sudo: effective uid is not 0, is /usr/bin/sudo on a file system with the 'nosuid' option set or an NFS file system without root privileges?

3. A seccomp és a sysctl szabályzatok blokkolják az unshare(CLONE_NEWUSER) hívást

A „rootless” címkével forgalmazott eszközök (Rootless Docker, Podman, Buildah, nerdctl, bubblewrap) továbbra is a Linux felhasználói névterekre (CLONE_NEWUSER) támaszkodnak. Meghiúsulnak, amikor:

  • A külső konténer alapértelmezett seccomp profilja blokkolja az unshare(2) vagy a clone(CLONE_NEWUSER) hívást.
  • Az Ubuntu 24.04+ engedélyezi a kernel.apparmor_restrict_unprivileged_userns = 1 beállítást.
  • Debian vagy RHEL csomópontokon a kernel.unprivileged_userns_clone = 0 vagy a user.max_user_namespaces = 0 beállítás van érvényben.
  • A newuidmap nem tud írni a /proc/self/uid_map fájlba, mert a PR_SET_NO_NEW_PRIVS aktív.

A kapott hibák a következőképpen néznek ki:

1unshare: unshare failed: Operation not permitted
2cannot clone: Operation not permitted
3Error: cannot re-exec process to join the existing user namespace
4newuidmap: write to uid_map failed: Operation not permitted
5RootlessKit: parent: failed to start the child: fork/exec /proc/self/exe: operation not permitted

4. A mount(2) és a pivot_root(2) blokkolt a docker build során gazdagép CAP_SYS_ADMIN nélkül

Még ha a környezet engedélyezi is a CLONE_NEWUSER használatát, vagy a dockerd kényszerítetten --iptables=false --bridge=none --storage-driver=vfs opciókkal indul, a docker build az első RUN utasításnál meghiúsul, mert egy friss /proc csatolása vagy a pivot_root(2) hívása egy beágyazott csatolási névtérben blokkolt:

1ERROR: failed to solve: process "/bin/sh -c ..." did not complete successfully:
2mount("/proc", "/proc", "proc", MS_NOSUID|MS_NODEV|MS_NOEXEC, NULL): Operation not permitted
3OCI runtime create failed: runc create failed: unable to start container process: error during container init: error mounting "proc" to rootfs at "/proc": mount proc:/proc (via /proc/self/fd/6), flags: 0xe: operation not permitted
4OCI runtime create failed: runc create failed: unable to start container process: error during container init: error jailing process inside rootfs: pivot_root .: invalid argument
5bwrap: Creating new namespace failed: Operation not permitted

5. A hiányzó /dev/fuse megtöri a fuse-overlayfs-t

A rootless konténermotorok, amelyek nem tudják csatolni a kernel overlayfs-t, a fuse-overlayfs-re térnek vissza. Minimális konténerekben vagy olyan Kubernetes podokban, amelyekben nincs /dev/fuse eszközátengedés, a fuse-overlayfs azonnal meghiúsul:

1fuse: device not found, try 'modprobe fuse' first
2fusermount3: failed to open /dev/fuse: No such file or directory
3error initializing graphdriver: driver not supported: fuse-overlayfs

Hogyan futtatja a gvx a docker:dind-et teljesen felhasználói térben

A gvx mind az öt kernelkorlátot kikerüli, mert nem kéri a gazdagép Linux kerneljétől névterek létrehozását, fájlrendszerek csatolását vagy hálózati interfészek konfigurálását. Ehelyett a rungv egy belső, felhasználói térbeli Linux kernelt (a gVisor Sentry-t) és egy felhasználói térbeli hálózati vermet (netstack) futtat egyetlen, hagyományos, nem privilegizált folyamaton belül.

Nem privilegizált Docker-in-Docker futtatása gvx-szel

1. Memórián belüli névterek és csatolási tábla (VFS2)

Amikor a dockerd, a containerd és a runc a rungv belsejében fut, a systrap elfogja a rendszerhívásaikat, és a folyamaton belüli Sentry kernelhez irányítja azokat, nem pedig a gazdagép kerneljéhez:

  • Az unshare(2), clone(2), pivot_root(2), chroot(2) és mount(2) a Sentry memórián belüli feladathierarchiáján és VFS2 csatolási tábláján (procfs, sysfs, tmpfs, devpts, cgroupfs v2) működik, miközben a gazdagépen futó rungv folyamat az Ön nem privilegizált gazdagép-UID-jén fut.

2. Natív overlayfs egyfájlos ext4lite köteteken

Amikor a -v gvx-docker:/var/lib/docker (vagy a --mount type=volume,src=/disk/gvx-docker.ext4,dst=/var/lib/docker) opciót használja, a gvx beépített ext4lite fájlrendszerét csatolja a /var/lib/docker útvonalra.

Mivel az ext4lite egy JBD2-naplózott ext4 fájlrendszert valósít meg egyetlen gazdagépfájlon belül (gvx-docker.ext4), támogatja a trusted.overlay.* bővített attribútumokat, a karakteres whiteout eszközöket (0:0), a d_type-ot és a RENAME_EXCHANGE műveletet, a dockerd a vendégen belül a natív overlayfs tárolóillesztőjét használja. A többfázisú docker build műveletek másolás-íráskor (Copy-on-Write) rétegeket osztanak meg /dev/fuse nélkül, és a Docker vfs tartalék illesztőjének lemezterület-robbanása nélkül.

3. Felhasználói térbeli docker0 híd és iptables-legacy

Amikor a docker:dind a gvx-en belül elindul:

  • A vendég dockerd létrehozza a docker0 hidat (172.17.0.1/16), virtuális veth párokat csatol a beágyazott konténerekhez, és a gvx felhasználói térbeli netstack-jén belül addrtype és conntrack egyezésekkel programozza a NAT (DOCKER, POSTROUTING) és a FILTER láncokat.
  • A -p unix:~/.gvx/docker.sock:2375 opció megadása egy gazdagép-oldali Unix tartomány socketet köt (0600 mód), és a kapcsolatokat közvetlenül a sandboxon belüli dockerd 2375-ös portjára továbbítja.

Összehasonlítás a meglévő konténereszközökkel

Képesség / KorlátozásSzabványos Docker (dockerd)Rootless Docker / PodmanKaniko / Buildah (nem privilegizált)gvx (rungv + docker:dind)
Gazdagép root vagy sudo szükségesIgenNemNemNem
Működik PR_SET_NO_NEW_PRIVS=1 mellettNemNem (a newuidmap hibázik)RészbenIgen
Működik, ha az unshare(CLONE_NEWUSER) tiltott (EPERM)Nem alkalmazhatóNemBuildah: Nem / Kaniko: IgenIgen
Működik /dev/fuse nélkülIgen (kernel overlay2 használatával)Csak lassú vfs másoláson keresztülIgenIgen (overlayfs ext4lite-on)
Támogatja a docker build (BuildKit) parancsotIgenIgen (ha a userns engedélyezett)Csak image építés (nincs futtatókörnyezet)Igen
Támogatja a docker run és docker compose up parancsokatIgenIgen (ha a userns engedélyezett)NemIgen
Fut Windowson és macOS-en Linux VM nélkülNem (WSL2 / VM szükséges)Nem (Linux VM szükséges)NemIgen (whpx, hvf, systrap)

Pontos gazdagép-kernel követelmények Linuxon

A gvx nulla megemelt képességet (CapEff: 0000000000000000) és nulla felhasználói névteret igényel. Linux gazdagépen a rungv mindössze három szabványos, nem privilegizált kernel-primitívre támaszkodik:

  1. ptrace(PTRACE_ATTACH) a saját gyermekszálán, egyszer, inicializáláskor: A systrap indításkor egy helyi stub segédszálat hoz létre, hozzá csatolódik a megosztott memória kontextus inicializálásához, majd leválik róla. Ha a gazdagép a kernel.yama.ptrace_scope = 3 beállítást használja (ami rendszerszinten letiltja a ptrace-t), vagy a ptrace-t egy külső seccomp szűrő blokkolja, a systrap inicializálás nem fejeződhet be. (A yama.ptrace_scope = 1 mellett, ami az Ubuntu és Debian alapértelmezése, a gvx sikeresen fut, mert a szülőtől a gyermek felé irányuló nyomkövetés engedélyezett.)
  2. seccomp(SECCOMP_SET_MODE_FILTER): A konténer stub szálakból érkező vendég rendszerhívások elfogására szolgál. Ahogy a ebben a sorozatban található 3. részben bemutatjuk, a gvx működik akkor is, ha a SECCOMP_FILTER_FLAG_NEW_LISTENER elérhető, és akkor is, ha egy beágyazott sandboxon belül EBUSY értékkel tér vissza.
  3. mmap(..., PROT_EXEC, ...): A vendég ELF szegmensek és a systrap megosztott memóriás trambulin leképezésére szolgál.

Végpontok közötti példa: Többkonténeres alkalmazás építése és tesztelése root nélkül

Az alábbi szkript egy teljes docker build és egy kétkonténeres integrációs tesztet (redis + alkalmazáskonténer) futtat nem privilegizált felhasználói munkamenetben:

 1mkdir -p ~/.gvx
 2rungv run \
 3  -p unix:~/.gvx/docker.sock:2375 \
 4  -v gvx-docker:/var/lib/docker \
 5  -e DOCKER_TLS_CERTDIR= \
 6  docker:dind --tls=false &
 7DIND_PID=$!
 8
 9export DOCKER_HOST="unix://$HOME/.gvx/docker.sock"
10until docker info >/dev/null 2>&1; do sleep 0.5; done
11
12mkdir -p /tmp/demo-app && cd /tmp/demo-app
13cat <<'EOF' > Dockerfile
14FROM alpine:3.20
15RUN apk add --no-cache redis
16CMD ["redis-cli", "-h", "cache", "ping"]
17EOF
18
19# Az image építése overlayfs használatával ext4lite-on
20docker build -t demo-ping:latest .
21
22# Híd hálózat létrehozása, a Redis indítása, és a konténerek közötti kapcsolat ellenőrzése
23docker network create demo-net
24docker run -d --name cache --network demo-net redis:7-alpine
25docker run --rm --network demo-net demo-ping:latest
26# Kimenet: PONG
27
28# A munkaterhelési konténerek eltávolítása és a sandbox leállítása
29docker rm -f cache
30docker network rm demo-net
31kill -INT $DIND_PID

További olvasmányok ebben a sorozatban

  1. gvx: Linux konténerek, Docker és Kubernetes futtatása egyetlen nem privilegizált folyamatban: A gvx architektúrájának áttekintése, platformfüggetlen végrehajtó motorjai (whpx, hvf, systrap), VFS2 (erofs, ext4lite, hostfs v2) és netstack.
  2. Docker, docker build és docker compose futtatása root vagy felhasználói névterek nélkül (ez a bejegyzés)
  3. Docker-in-Docker futtatása gVisor és beágyazott sandboxokon belül a gvx-szel: Hogyan oldja meg a gvx a modprobe, iptables-nft, overlay2 a gofer-en és a beágyazott SECCOMP_FILTER_FLAG_NEW_LISTENER (EBUSY) problémáit a gVisor (runsc) belsejében.
  4. Gyors, izolált Docker környezetek AI-ügynök RL rollout-okhoz a gvx-szel: Párhuzamos SWE-bench és RL rollout környezetek skálázása 100 milliszekundumos, másolás-íráskor működő .ext4 kötetvisszaállítással.