GoSuda

Dockerin, docker buildin ja docker composen suorittaminen ilman juurioikeuksia tai user namespaces-ominaisuuksia

By Lemon Mint views ...

Pikaratkaisu: turvallinen käyttäjätason Docker kolmessa vaiheessa

Jos työskentelet lukitussa Linux-kontissa, CI-ajurissa, Kubernetes Podissa tai AI-agentin hiekkalaatikossa, jossa root, sudo, käyttäjänimiavaruudet (unshare(CLONE_NEWUSER)), mount(2) ja /dev/fuse on estetty, gvx (rungv) on turvallinen ja useita suojakerroksia hyödyntävä ratkaisu täyden docker:dind-moottorin ajamiseen käyttäjätilassa.

Miksi gvx on suunnittelultaan turvallinen (ei oikeuksien eskaloinnin kiertotapa): Toisin kuin isännän /var/run/docker.sock-socketin liittäminen tai docker run --privileged -komento (jotka antavat juuritason vastineen hallinnan isännän ytimeen), gvx ei ohita eikä heikennä mitään isännän turvallisuuskäytäntöä (PR_SET_NO_NEW_PRIVS, seccomp, AppArmor tai ei-juuri-UID-rajoitukset). Sen sijaan rungv lukitsee oman isäntäprosessinsa (PR_SET_NO_NEW_PRIVS + tiukka BPF seccomp -sallintalista) ja ajaa dockerd:n Googlen muistiturvallisessa gVisor (Sentry) -käyttäjätilaytimessä. Kaikki vierasjärjestelmän UID 0 -valtuudet, overlayfs-liitokset (ext4lite) ja iptables-säännöt pysyvät tiukasti eristettyinä hiekkalaatikkoprosessin sisällä.

 1# 1. Asenna rungv käyttäjätilaan (SLSA-todennettu esikäännetty julkaisu tai go install)
 2# Vaihtoehto A: Todenna ja pura SLSA-todennettu esikäännetty binääri GitHub Releasesista
 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# Vaihtoehto B: Tai asenna suoraan lähdekoodista Go:n avulla
 9CGO_ENABLED=0 GOBIN=~/.local/bin go install z.gfire.dev/gvx/cmd/rungv@latest
10
11# 2. Käynnistä docker:dind gvx:n sisällä yhden tiedoston ext4lite-volyymillä
12#    Välittää ~/.gvx/docker.sock-tiedoston (oikeudet 0600) vierasportille 2375
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. Osoita tavallinen Docker CLI ja Docker Compose käyttäjätilan socketiin
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# Tuloste: overlayfs Alpine Linux ... (containerized)
26
27docker build -t app:test .
28docker run --rm app:test
29docker compose up -d

Miksi tavalliset rootless-työkalut epäonnistuvat rajoitetuissa hiekkalaatikoissa

Kun insinööri tai autonominen koodausagentti tarvitsee docker build-, docker run- tai docker compose -komentoja kovennetussa kontissa tai monivuokraajaajossa, tavalliset kiertotavat epäonnistuvat viidessä eri ydinrajoitteessa.

1. Isännän Docker-daemonin socket puuttuu

Komennot docker ps ja docker build epäonnistuvat välittömästi, jos isännän /var/run/docker.sock-socketia ei ole liitetty ympäristöön:

1Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

2. PR_SET_NO_NEW_PRIVS estää sudo- ja setuid-apuohjelmat

Kovennetut kontit (securityContext.allowPrivilegeEscalation: false Kubernetesissa, --security-opt=no-new-privileges Dockerissa tai exebox- / bwrap-hiekkalaatikot) asettavat Linuxin PR_SET_NO_NEW_PRIVS-bitin prosessipuuhun. Yritys nostaa oikeuksia sudo:n tai setuid-binäärien (newuidmap, newgidmap, fusermount3) kautta epäonnistuu:

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. Seccomp- ja sysctl-käytännöt estävät unshare(CLONE_NEWUSER):n

"Rootless"-työkalut (Rootless Docker, Podman, Buildah, nerdctl, bubblewrap) nojaavat silti Linuxin käyttäjänimiavaruuksiin (CLONE_NEWUSER). Ne epäonnistuvat aina, kun:

  • Ulomman kontin oletusarvoinen seccomp-profiili estää unshare(2)- tai clone(CLONE_NEWUSER)-kutsun.
  • Ubuntu 24.04+ ottaa käyttöön asetuksen kernel.apparmor_restrict_unprivileged_userns = 1.
  • Debian- tai RHEL-solmut asettavat arvon kernel.unprivileged_userns_clone = 0 tai user.max_user_namespaces = 0.
  • newuidmap ei voi kirjoittaa tiedostoon /proc/self/uid_map, koska PR_SET_NO_NEW_PRIVS on aktiivinen.

Syntyvät virheet näyttävät tältä:

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. mount(2) on estetty ilman isännän CAP_SYS_ADMIN-oikeutta

Vaikka ympäristö sallisi CLONE_NEWUSER:n, uuden /proc-liitoksen luominen sisäkkäiseen mount-nimiavaruuteen epäonnistuu, jos ulompi kontti on peittänyt /proc-alipuita (/proc/acpi, /proc/kcore, /proc/keys) tai jättänyt mount(2)-kutsun seccomp-suodattimen ulkopuolelle:

1mount("/proc", "/proc", "proc", MS_NOSUID|MS_NODEV|MS_NOEXEC, NULL): Operation not permitted
2OCI 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
3bwrap: Creating new namespace failed: Operation not permitted

5. Puuttuva /dev/fuse rikkoo fuse-overlayfs:n

Rootless-konttimoottorit, jotka eivät voi liittää ytimen overlayfs-järjestelmää, siirtyvät fuse-overlayfs-ratkaisuun. Minimaalisissa konteissa tai Kubernetes-podeissa ilman /dev/fuse-laitteen läpivientiä fuse-overlayfs epäonnistuu välittömästi:

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

Miten gvx ajaa docker:dind-moottorin kokonaan käyttäjätilassa

gvx ohittaa kaikki viisi ydinrajoitetta, koska se ei pyydä isännän Linux-ydintä luomaan nimiavaruuksia, liittämään tiedostojärjestelmiä tai määrittämään verkkoliittymiä. Sen sijaan rungv ajaa sisäisen käyttäjätilan Linux-ytimen (gVisor Sentry) ja käyttäjätilan verkkopinon (netstack) yhdessä tavallisessa, ei-juurioikeuksisessa prosessissa.

Käyttäjätason Docker-in-Docker gvx:llä

1. Muistissa olevat nimiavaruudet ja liitostaulu (VFS2)

Kun dockerd, containerd ja runc suoritetaan rungv:n sisällä, systrap sieppaa niiden järjestelmäkutsut ja ohjaa ne prosessin sisäiseen Sentry-ytimeen isännän ytimen sijaan:

  • unshare(2), clone(2), pivot_root(2), chroot(2) ja mount(2) toimivat Sentryn muistissa olevan tehtävähierarkian ja VFS2-liitostaulun (procfs, sysfs, tmpfs, devpts, cgroupfs v2) kanssa, kun isäntäprosessi rungv toimii sinun ei-juurioikeuksisella isäntä-UID:lla.

2. Natiivi overlayfs yhden tiedoston ext4lite-volyymeillä

Kun välität -v gvx-docker:/var/lib/docker (tai --mount type=volume,src=/disk/gvx-docker.ext4,dst=/var/lib/docker), gvx liittää sisäänrakennetun ext4lite-tiedostojärjestelmän kohtaan /var/lib/docker.

Koska ext4lite toteuttaa JBD2-journaloidun ext4-tiedostojärjestelmän yhden isäntätiedoston (gvx-docker.ext4) sisällä ja tukee trusted.overlay.*-laajennettuja attribuutteja, merkkityyppisiä whiteout-laitteita (0:0), d_type-tietoa ja RENAME_EXCHANGE-toimintoa, dockerd käyttää vierasjärjestelmässä natiivia overlayfs-tallennusajuria. Monivaiheiset docker build -operaatiot jakavat Copy-on-Write-kerroksia ilman /dev/fuse-laitetta ja ilman Dockerin vfs-varajärjestelmän aiheuttamaa levytilan räjähdysmäistä kasvua.

3. Käyttäjätilan docker0-silta ja iptables-legacy

Kun docker:dind käynnistyy gvx:n sisällä:

  • Vierasjärjestelmän dockerd luo docker0-sillan (172.17.0.1/16), liittää virtuaalisia veth-pareja sisäkkäisille konteille ja ohjelmoi NAT- (DOCKER, POSTROUTING) ja FILTER-ketjut addrtype- ja conntrack-vastaavuuksilla gvx:n käyttäjätilan netstack-pinossa.
  • Kun välität -p unix:~/.gvx/docker.sock:2375, sidotaan isännän Unix-domain-socket (oikeudet 0600) ja yhteydet välitetään suoraan hiekkalaatikon sisällä olevan dockerd:n porttiin 2375.

Vertailu olemassa oleviin konttityökaluihin

Ominaisuus / RajoiteTavallinen Docker (dockerd)Rootless Docker / PodmanKaniko / Buildah (ilman oikeuksia)gvx (rungv + docker:dind)
Vaatii isännän root- tai sudo-oikeudetKylläEiEiEi
Toimii, kun PR_SET_NO_NEW_PRIVS=1EiEi (newuidmap epäonnistuu)OsittainKyllä
Toimii, kun unshare(CLONE_NEWUSER) on estetty (EPERM)Ei sovelluEiBuildah: Ei / Kaniko: KylläKyllä
Toimii ilman /dev/fuse-laitettaKyllä (käyttää ytimen overlay2-ajuria)Vain hitaan vfs-kopioinnin kauttaKylläKyllä (overlayfs ext4lite-levyllä)
Tukee docker build -komentoa (BuildKit)KylläKyllä (jos userns on sallittu)Vain image-rakennus (ei ajoaikaa)Kyllä
Tukee docker run- ja docker compose up -komentojaKylläKyllä (jos userns on sallittu)EiKyllä
Toimii Windowsissa ja macOS:ssä ilman Linux-VM:ääEi (vaatii WSL2:n tai VM:n)Ei (vaatii Linux-VM:n)EiKyllä (whpx, hvf, systrap)

Tarkat isäntäjärjestelmän ydinvaatimukset Linuxissa

gvx ei vaadi lainkaan korotettuja valtuuksia (CapEff: 0000000000000000) eikä käyttäjänimiavaruuksia. Linux-isännällä rungv nojaa vain kolmeen tavalliseen ei-juurioikeuksiseen ydinprimitiiviin:

  1. ptrace(PTRACE_ATTACH) omaan lapsisäikeeseensä kerran alustuksen aikana: systrap käynnistää paikallisen stub-apusäikeen käynnistyessään, liittyy siihen alustaakseen jaetun muistin kontekstin ja irrottautuu. Jos isäntä asettaa arvon kernel.yama.ptrace_scope = 3 (joka kytkee ptrace-kutsut pois käytöstä koko järjestelmässä) tai estää ptrace-kutsun ulomman seccomp-suodattimen kautta, systrap:n alustus ei voi valmistua. (Asetuksella yama.ptrace_scope = 1, joka on oletus Ubuntussa ja Debianissa, gvx onnistuu, koska vanhemman ja lapsen välinen jäljitys on sallittu.)
  2. seccomp(SECCOMP_SET_MODE_FILTER): Käytetään vierasjärjestelmän järjestelmäkutsujen sieppaamiseen kontin stub-säikeistä. Kuten tämän sarjan osassa 3 käsitellään, gvx toimii sekä silloin, kun SECCOMP_FILTER_FLAG_NEW_LISTENER on käytettävissä, että silloin, kun se palauttaa arvon EBUSY sisäkkäisessä hiekkalaatikossa.
  3. mmap(..., PROT_EXEC, ...): Käytetään vierasjärjestelmän ELF-segmenttien ja systrap:n jaetun muistin trampoliinin kuvaamiseen.

Päästä päähän -esimerkki: monikonttisovelluksen rakentaminen ja testaaminen ilman juurioikeuksia

Seuraava skripti suorittaa täydellisen docker build -komennon ja kahden kontin integraatiotestin (redis ja sovelluskontti) käyttäjätason istunnossa:

 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# Rakenna image käyttäen overlayfs-tiedostojärjestelmää ext4lite-levyllä
20docker build -t demo-ping:latest .
21
22# Luo siltaverkko, käynnistä Redis ja varmista yhteys konttien välillä
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# Tuloste: PONG
27
28# Siivoa työkuormakontit ja pysäytä hiekkalaatikko
29docker rm -f cache
30docker network rm demo-net
31kill -INT $DIND_PID

Lisälukemista tästä sarjasta

  1. gvx: Linux-konttien, Dockerin ja Kubernetesin ajaminen yhdessä käyttäjätason prosessissa: gvx:n arkkitehtuurin yleiskatsaus, sen alustakohtaiset suoritusmoottorit (whpx, hvf, systrap), VFS2 (erofs, ext4lite, hostfs v2) ja netstack.
  2. Docker-, docker build- ja docker compose -komentojen ajaminen ilman juurioikeuksia tai käyttäjänimiavaruuksia (tämä kirjoitus)
  3. Docker-in-Docker gVisorin ja sisäkkäisten hiekkalaatikoiden sisällä gvx:n avulla: Miten gvx ratkaisee modprobe-, iptables-nft-, overlay2 gofer-ajurilla ja sisäkkäisen SECCOMP_FILTER_FLAG_NEW_LISTENER-kutsun (EBUSY) gVisor- (runsc) -ympäristössä.
  4. Nopeat eristetyt Docker-ympäristöt AI-agenttien RL-ajoihin gvx:llä: Rinnakkaisten SWE-bench- ja RL-ajoympäristöjen skaalaaminen 100 millisekunnin Copy-on-Write .ext4-volyymien palautuksilla.