gvx: Spúšťanie Linux Containers, Docker a Kubernetes v jednom neprivilegovanom procese

Úvod: Bezpečné kontajnery s posilnenou ochranou bez roota a hostiteľských démonov
Spúšťanie Linuxových kontajnerov, príkazu docker build alebo Kubernetes na vývojovom počítači, CI runneri alebo viacnájomnom cloudovom uzle si zvyčajne vynúti nepríjemný bezpečnostný kompromis:
- Na Linuxe štandardné OCI runtime (
runc,crun,runsc) vyžadujú buď oprávneniaroot, sprístupnenie hostiteľského/var/run/docker.sock,--privileged(CAP_SYS_ADMIN), alebo používateľské menné priestory (unshare(CLONE_NEWUSER)), ktoré rozširujú útočnú plochu hostiteľského jadra. - Na Windows a macOS kontajnerové enginy (
Docker Desktop,Podman Machine,Lima,OrbStack) spúšťajú úplné virtuálne stroje s jadrom Linuxu vo WSL2, Hyper-V aleboVirtualization.frameworka v rámci tohto VM prevádzkujú perzistentný démon na pozadí.
gvx (CLI rungv a Go SDK z.gfire.dev/gvx/pkg/gvx) poskytuje bezpečnú alternatívu s nulovými oprávneniami. Je vytvorený ako fork projektu Google gVisor, ktorého upstream sa dá sledovať, a obsahuje jeho používateľskopriestorové jadro Linuxu (Sentry) a používateľskopriestorový sieťový zásobník (netstack). gvx spúšťa nemodifikované binárne súbory linux/amd64 a linux/arm64 vo formáte ELF64 a kontajnery OCI priamo vnútri jediného neprivilegovaného, sebazamknutého hostiteľského procesu na systémoch Windows, macOS a Linux.
Bezpečnostná záruka (trojvrstvová obrana do hĺbky):
gvxnikdy neoslabuje hranice zabezpečenia hostiteľského OS, nikdy neinštaluje ovládače jadra a nikdy nevyžadujeroot,sudo,--privilegedna hostiteľovi aniCLONE_NEWUSER. Pred vykonaním jedinej inštrukcie hosťagvxzamkne svoj vlastný hostiteľský proces pomocou Windows Restricted Tokens a Job Objects, macOS Seatbelt (deny default) alebo LinuxPR_SET_NO_NEW_PRIVS+ BPFseccomp. Všetky systémové volania hosťa, virtuálne privilégiáUID 0, pripojenia (VFS2) a sieťové tabuľky (netstack) sú prísne ohraničené v rámci bezpečného z hľadiska pamäte jadra GoSentry.
| Runtime | Hostiteľský OS | Studený štart | Pamäťová stopa | Potrebný správca alebo sudo | Démon VM na pozadí | Priame spustenie OCI obrazu |
|---|---|---|---|---|---|---|
gvx (whpx / hvf) | Windows (amd64, arm64) a macOS (arm64) | ~20 ms | ~30 MiB | Nie | Nie | Áno |
gvx (systrap) | Windows (amd64, arm64) a Linux (amd64, arm64) | ~25 až 65 ms | ~31 MiB | Nie | Nie | Áno |
| WSL2 / Docker Desktop | Windows a macOS | 800 až 2500 ms | > 512 MiB | Áno (počiatočné nastavenie) | Áno | Vyžaduje démon |
| QEMU (Full System) | Windows a macOS | 1500 až 4000 ms | > 256 MiB | Nie | Nie | Vyžaduje diskový obraz |
Na systémoch Windows ani macOS sa nespúšťa žiadne jadro Linux VM. Na hostiteľovi nebeží žiadny démon na pozadí. Na hostiteľskom OS nie sú potrebné root, sudo, používateľské menné priestory (CLONE_NEWUSER), mount(2), ovládače TUN/TAP ani oprávnenia CAP_NET_ADMIN. Vo vnútri tohto neprivilegovaného procesu gvx spúšťa Docker-in-Docker (docker:dind), docker build, docker compose a viacuzlový vysoko dostupný Kubernetes (k3s s vloženým etcd a sieťovým pluginom Calico CNI).
Životný cyklus kontajnera a trojvrstvové zamknutie hostiteľa
Každá sandboxová oblasť gvx beží v rámci jedného neprivilegovaného hostiteľského procesu a presadzuje trojfázový životný cyklus: vopred otvorenie všetkých potrebných deskriptorov súborov a soketov hostiteľa, zamknutie hostiteľského procesu OS prostredníctvom pkg/hostlockdown a vstup do vnútorného výkonného cyklu Sentry.

Pred odovzdaním riadenia prvej inštrukcii hosťa gvx vopred otvorí svoje cachované deskriptory vrstiev obrazu .erofs, deskriptory súborov zväzkov .ext4, handle *os.Root pre /workspace a sieťové sokety hostiteľa, potom zavolá hostlockdown.Apply():
- Windows NT (
lockdown_windows.go): VoláAdjustTokenPrivilegessSE_PRIVILEGE_REMOVED, aby odobrala oprávnenia na mieste, naviaže obmedzený impersonačný tokenDISABLE_MAX_PRIVILEGEs nízkou integritou (S-1-16-4096), priradí proces k anonymnému Job Object sJOB_OBJECT_LIMIT_ACTIVE_PROCESS = 1(čím blokuje vytváranie akýchkoľvek podriadených procesov) a aktivujeDisallowWin32kSystemCalls = 1cezSetProcessMitigationPolicy. - macOS XNU (
lockdown_darwin.go): NastavíRLIMIT_NPROC = 0a aplikuje profil Seatbelt (sandbox_init_with_parameters) začínajúci na(version 1)(deny default), ktorý blokujeprocess-fork,process-exec*a všetky nové otvorenia súborov hostiteľa. - Linux (
lockdown_linux.go+pkg/gvx/syscallfilter_linux.go): NastavíPR_SET_NO_NEW_PRIVSa nainštaluje allowlist BPFseccompjadraSentrynaprieč všetkými vláknami (SECCOMP_FILTER_FLAG_TSYNC) s explicitnými pravidlamiEPERMpreexecve,execveat,clone,openatasocket.
Multiplatformové zachytávanie systémových volaní a stránkovanie 4 KB (pkg/sentry/platform)
Binárne súbory ELF64 systému Linux predpokladajú granularitu pamäťových stránok 4 KB (0x1000) pre mapovanie segmentov mmap(MAP_FIXED). Funkcie Windows VirtualAlloc a MapViewOfFile3 však vynucujú zarovnanie na 64 KB (0x10000) a macOS na čipoch Apple Silicon (darwin/arm64) používa hostiteľské stránky s veľkosťou 16 KB (0x4000). Každý OS navyše vyžaduje iný mechanizmus na zachytenie inštrukcií Linuxu SYSCALL (amd64) a SVC #0 (arm64) bez spustenia virtuálneho stroja s Linuxom.
gvx rieši oba problémy v rámci štyroch vykonávacích backendov, ktoré implementujú pkg/sentry/platform.Context:

1. Hardvérový engine pre Windows: platform/whpx (WinHvPlatform.dll)
Na windows/amd64 a windows/arm64 platform/whpx vytvára ľahkú hypervízorovú partíciu cez WHvCreatePartition bez spustenia jadra operačného systému hosťa:
- Dekuplér stránkovania 64 KB na 4 KB:
whpxraz zaregistruje každú 64 MiB arénupgalloc.MemoryFilev partícii cezWHvMapGpaRange. Následné volaniaMapFileaUnmapupravujú iba tabuľky stránok hosťa v rámci partície a vynucujú presné oprávneniaR/W/Xna úrovni 4 KB, napriek alokačnej granularite 64 KB systému Windows. - Výmena registrov bez API cez
CommPage:- Na
amd64saSYSCALLhosťa z Ring-3 presúva do stubuMSR_LSTARbežiaceho v Ring-0 v rámci partície (stubgen_x86.go), ktorý uloží registre GPR rýchlej cesty systémových volaní (RAX, RDI, RSI, RDX, R10, R8, R9, RIP, RSP) do zdieľanej stránkyCommPages veľkosťou 4 KB a vykonáHLT, aby ukončilWHvRunVirtualProcessor. - Na
arm64saSVC #0hosťa z EL0 presúva do vektorov EL1 (stubgen_a64.go), uložíX0..X8, SP_EL0, ELR_EL1, PSTATEdoCommPagea načíta z nepodloženej GPA nula, čím vyvolá pamäťový výstup späť doSentry.
- Na
2. Hardvérový engine pre macOS: platform/hvf (Hypervisor.framework)
Na čipoch Apple Silicon (darwin/arm64) platform/hvf spúšťa vlákna kontajnerov vo vCPU frameworku Hypervisor.framework (hv_vm_create, hv_vcpu_run):
- Dvojstupňová translácia MMU 4 KB cez 16 KB: Stage-2 (
hv_vm_map) mapuje časti pamäťových súborov po 1 GiB do priestoru Intermediate Physical Address (IPA) raz, s granularitou hostiteľskej stránky 16 KB, s oprávneniamiHV_MEMORY_READ | HV_MEMORY_WRITE | HV_MEMORY_EXEC. Vo vnútri vCPU stub EL1bluepill(bluepill_arm64.go) nastavíTCR_EL1.TG0 = 0b00(granulu 4 KB) vTTBR0_EL1a naplní záznamy tabuliek stránok Stage-1 s veľkosťou 4 KB s presnými oprávneniamiR-XaleboRW-(UXN=1). Keďže ARM64 MMU vynucuje prienik oprávnení Stage-1 a Stage-2, hardvér zachytáva chyby oprávnení na presných hraniciach 4 KB. - Zachytenie systémového volania:
SVC #0hosťa z EL0 sa presúva doVBAR_EL1na EL1, uloží registre do zdieľanej stránkyCommPages veľkosťou 4 KB a vykonáHVC #0, aby sa vrátil zhv_vcpu_rundo vlákna GoSentry.
3. Používateľskorežimová záložná možnosť pre Windows: platform/systrap (winsystrap)
Keď hardvérová virtualizácia nie je dostupná (napríklad v rámci vnorených cloudových VM), winsystrap spúšťa kód hosťa v používateľskom režime na windows/amd64 a windows/arm64:
- Hardvérová izolácia
CR3/TTBR0_EL1: Vlákna hosťa bežia v izolovaných podprocesoch stubov, ktoré sa spúšťajú z vygenerovaného spustiteľného súboru s veľkosťou 1 KB (stubimage_xplat.go) ohraničeného tokenom s nízkou integritou a Job Object. - Patchovanie binárneho kódu na mieste a IPC
winSysmsg: Naamd64patcher (patcher_amd64_xplat.go) nahrádza 2-bajtové inštrukciesyscall(0f 05) 5-bajtovými skokmijmp rel32(alebo breakpointovými pascamiCC 90, keď nie je dostupné 5-bajtové okno) do ostrova rýchlej cesty. Naarm64sasvc #0patchuje vetvouBdo slotu ostrova. Ostrov uloží registre do zdieľanej stránkywinSysmsga synchronizuje sa soSentrycezWaitOnAddressaWakeByAddressSingle, zatiaľ čo nepatchované pasce a chyby stránok sa zastavujú na Windows Debug Object (WaitForDebugEventEx).
4. Používateľskorežimový engine pre Linux: platform/systrap
Na linux/amd64 a linux/arm64 systrap spúšťa vlákna hosťa (sysmsg), ktoré zachytávajú systémové volania hosťa cez SECCOMP_RET_TRAP (SIGSYS) a binárne patchujú miesta syscall do zdieľaného trampolína v pamäti (sysmsg) synchronizovaného cez SYS_FUTEX. Zároveň stub syscallThread (syscall_thread.go) vykonáva operácie nad adresným priestorom (mmap, munmap, clone) cez SECCOMP_RET_USER_NOTIF (_RUN_SECCOMP_LOOP). Keď gvx beží vo vonkajšej sandboxe gVisor (runsc), kde jediný slot SECCOMP_FILTER_FLAG_NEW_LISTENER vracia EBUSY, gvx automaticky prepne syscallThread na slučku futexu v zdieľanej pamäti (_RUN_SYSCALL_LOOP), ako je podrobne opísané v 3. časti tejto série.
Ako gvx mapuje systémové volania Linuxu hosťa na virtuálne podsystémy a hostiteľské handly
Keď platformový engine zachytí SYSCALL (amd64) alebo SVC #0 (arm64) inštrukciu hosťa a zapíše registre hosťa do stránky s veľkosťou 4 KB (CommPage, sysmsg alebo winSysmsg), riadenie sa vráti do goroutine úlohy Sentry v jazyku Go (pkg/sentry/kernel/task_syscall.go). Namiesto preposielania systémových volaní Linuxu podkladovému jadru hostiteľského OS Task.doSyscall() uloží pôvodný stav registrov (SyscallSaveOrig()), vyhodnotí všetky filtre BPF seccomp a zastavenia ptrace v rámci hosťa a odošle číslo systémového volania cez linux.AMD64 alebo linux.ARM64 (pkg/sentry/syscalls/linux/linux64.go, pokrývajúce približne 370 systémových volaní Linuxu) do štyroch interných domén:

| Doména systémových volaní | Reprezentatívne systémové volania Linuxu hosťa | Interný podsystém gvx (pkg/sentry) | Interakcia s hranicou hostiteľského OS (po hostlockdown) |
|---|---|---|---|
| A. Proces, menný priestor, pripojenia a synchronizácia | clone, execve, unshare, setns, mount, umount2, pivot_root, setuid, capset, futex, epoll_wait, pipe2 | kernel.Task, virtuálne poverenia, tabuľka futexov a VFS2 v pamäti (procfs, sysfs, cgroupfs v2, tmpfs, overlayfs) | Nulové systémové volania hostiteľa (100 % stav v pamäti v Go; úplne neviditeľné pre hostiteľský OS) |
B. Virtuálna pamäť (MM) | mmap, munmap, mremap, mprotect, brk, madvise, memfd_create | mm.MemoryManager (strom VMA s 4 KB) a pgalloc.MemoryFile | Obojsmerné aktualizácie tabuliek stránok po 4 KB cez WHvMapGpaRange, hv_vm_map + TTBR0_EL1 alebo stub mmap/mprotect |
C. Súbory a úložisko (VFS2) | openat, pread64, pwrite64, getdents64, statx, renameat2, setxattr, mknod, inotify_add_watch | Smerovač tabuľky pripojení vfs.VirtualFilesystem (fsimpl/erofs, fsimpl/ext4lite, fsimpl/hostfs v2) | Obojsmerné pread/pwrite nad 1 pripnutým deskriptorom .erofs alebo 1 deskriptorom .ext4, alebo rozsahovo ohraničené relatívne prechody nad *os.Root |
| D. Sieťovanie a Netfilter | socket, bind, listen, connect, sendmsg, recvmsg, netlink, setsockopt(IPT_SO_SET_REPLACE) | Používateľskopriestorový pkg/tcpip (lo, eth0, docker0, veth, vxlan, wireguard, ipset, iptables-legacy) | Komunikácia v rámci sandboxu nepoužíva žiadne systémové volania hostiteľa; externá komunikácia sa mapuje na net.Dial/net.Listen (-net=nat) alebo na 1 UDP soket (-net=wg) |
Keď handler vráti (rval, ctrl, err), Task.doSyscallInvoke() prevedie každú chybu na záporný errno Linuxu (-ExtractErrno(err, sysno)), zapíše návratovú hodnotu späť do zdieľanej stránky registrov (RAX na amd64, X0 na arm64) a obnoví vykonávanie hosťa.
Úložisko (VFS2) a dvojitá používateľskopriestorová sieť (netstack)
Všetky súborové a sieťové operácie hosťa sa obsluhujú vnútri jadra Go Sentry prostredníctvom troch súborových systémov VFS2 a dvoch dráh pkg/netbackend:

| Úložný engine | Úloha pripojenia v gvx | Podkladový hostiteľský zdroj | Volania openat / NtCreateFile na hostiteľovi počas behu | Kontroly jednotlivých súborov programom Windows Defender (WdFilter.sys) |
|---|---|---|---|---|
fsimpl/erofs | Nižšie vrstvy OCI obrazov určené len na čítanie | Jeden súbor <sha256>.erofs na vrstvu | 0 | 0 |
fsimpl/ext4lite | Pomenované zväzky (-v name:/path) | Jeden súbor <name>.ext4 na zväzok | 0 | 0 |
fsimpl/hostfs v2 | Pracovný priečinok hostiteľa (-workspace, -v /host:/guest) | Pripnutý hostiteľský adresár *os.Root | O(depth) pri každom neskrytom otvorení | 1 pri každom zatvorení hostiteľského súboru |
Prečo ext4lite záleží pre Docker, databázy a správcov balíkov
Extrahovanie alebo zapisovanie desiatok tisíc súborov kontajnera priamo na Windows NTFS alebo macOS APFS spúšťa skenovanie antivírusovými minifiltrami (WdFilter.sys), kolízie citlivosti na veľkosť písmen a chýbajúce rozšírené atribúty POSIX.
pkg/sentry/fsimpl/ext4lite implementuje čistý súborový systém ext4 v jazyku Go vnútri jedného vopred otvoreného hostiteľského súboru (%LOCALAPPDATA%\gvx\cache\volumes\<name>.ext4 na Windows, ~/Library/Caches/gvx/volumes/<name>.ext4 na macOS alebo ~/.cache/gvx/volumes/<name>.ext4 na Linuxe), s týmito vlastnosťami:
- Bloky 4 KiB a dynamické skupiny blokov 16 MiB (
meta_bg): Rastie dynamicky bez zastavení pri alokácii riedkych súborov (fallocatena Linuxe,fcntl(F_PREALLOCATE)na macOS,FileAllocationInfona Windows) a pri čistom odpojení zhutňuje nepoužité koncové skupiny. - Žurnál JBD2 v ordered režime (inode 8): Atomické potvrdzovanie transakcií s kontrolnými súčtmi CRC-32 a blokmi revoke, spolu s obnovou
fsckLite. - Podpora hornej vrstvy
overlayfs: Implementuje rozšírené atribútytrusted.overlay.*asecurity.capability, whiteouty znakových zariadení (0:0), hlásenie záznamov adresárovd_typeaRENAME_EXCHANGE.
Praktické úlohy: Docker Engine, Kubernetes (k3s + Calico) a Go SDK
Inštalácia rungv: prekompilované vydania s overeným SLSA alebo go install
Môžete stiahnuť prekompilovaný archív rungv pre linux/amd64, linux/arm64, darwin/arm64, windows/amd64 alebo windows/arm64 zo stránky GitHub Releases (každý je zostavený pipeline pre vydania SLSA s balíkom dôkazov pôvodu Sigstore a súborom SHA256SUMS), alebo nainštalovať priamo zo zdrojového kódu pomocou go install:
1# Možnosť A: Stiahnite prekompilované vydanie a overte pôvod zostavenia SLSA
2gh attestation verify rungv-v0.2.0-linux-amd64.tar.gz --repo gfire-sigs/gvx \
3 --signer-workflow gfire-sigs/gvx/.github/workflows/release.yml \
4 --source-ref refs/tags/v0.2.0 --deny-self-hosted-runners
5shasum -a 256 -c SHA256SUMS --ignore-missing
6tar -xzf rungv-v0.2.0-linux-amd64.tar.gz
7
8# Možnosť B: Inštalácia priamo cez Go (Linux / Windows)
9CGO_ENABLED=0 go install z.gfire.dev/gvx/cmd/rungv@latest
Na macOS (
darwin/arm64) je prekompilovaný archív vydania už podpísaný oprávnenímcom.apple.security.hypervisor(xattr -d com.apple.quarantine rungvodstráni karanténu prehliadača). Ak zostavujete lokálne pomocougo installalebogo buildna macOS, podpíšte binárny súbor príkazomcodesign --sign - --entitlements entitlements.plist --force $(which rungv).
1. Spustenie neprivilegovaného Docker Engine (docker:dind)
Podľa dokumentu docs/docker-engine.md môžete spustiť nemodifikovaný kontajner docker:dind v rámci rungv na systémoch Windows, macOS alebo Linux a ovládať ho pomocou vášho hostiteľského rozhrania docker CLI:
1# 1. Vytvorte hostiteľský adresár pre preposlaný Unix soket
2mkdir -p ~/.gvx
3
4# 2. Spustite docker:dind v sandboxe gvx so zväzkom ext4lite
5rungv run \
6 -p unix:~/.gvx/docker.sock:2375 \
7 -p 127.0.0.1:9000-9019:9000-9019 \
8 -v gvx-docker:/var/lib/docker \
9 -e DOCKER_TLS_CERTDIR= \
10 docker:dind --tls=false
V druhom termináli nasmerujte vaše hostiteľské rozhranie docker CLI na soket sandboxu:
1docker context create gvx --docker host=unix://$HOME/.gvx/docker.sock
2docker context use gvx
3
4docker info --format '{{.Driver}} {{.OperatingSystem}}'
5# Výstup: overlayfs Alpine Linux ... (containerized)
6
7docker build -t myapp ./app
8docker compose up -d
2. Spustenie Kubernetes (k3s + Calico) v neprivilegovaných sandboxoch
Keďže gvx implementuje /dev/kmsg, cgroup v2 (vrah OOM memory.max a obmedzenie šírky pásma cpu.max), /proc/diskstats, zariadenia netlink wireguard a vxlan, ipset a iptables-legacy (addrtype, conntrack, statistic, recent), nemodifikovaný obraz rancher/k3s sa dostane do stavu Ready v rámci jediného procesu rungv:
1mkdir -p ~/.gvx/k3s
2
3rungv run \
4 -e IPTABLES_MODE=legacy \
5 -p 127.0.0.1:6443:6443 \
6 -p 127.0.0.1:30000-30019:30000-30019 \
7 -v k3s:/var/lib/rancher \
8 --mount type=bind,src=$HOME/.gvx/k3s,dst=/output \
9 rancher/k3s:v1.31.4-k3s1 server \
10 --disable=traefik,servicelb \
11 --write-kubeconfig=/output/kubeconfig.yaml \
12 --write-kubeconfig-mode=644
Môžete tiež pripojiť viacero uzlov gvx cez WireGuard (flannel-backend=wireguard-native alebo sieť wg0 typu mesh) so vysokou dostupnosťou vloženého etcd, alebo spustiť Calico (calico-vxlan.yaml s FELIX_IPTABLESBACKEND=Legacy), aby sa Kubernetes NetworkPolicy vynucovala úplne v používateľskom priestore.
3. Vkladanie Linuxových kontajnerov do Go cez z.gfire.dev/gvx/pkg/gvx
Aplikácie v jazyku Go môžu vkladať Linuxové kontajnery priamo bez externého démona kontajnerov:
1package main
2
3import (
4 "context"
5 "fmt"
6 "os"
7
8 "z.gfire.dev/gvx/pkg/gvx"
9)
10
11func main() {
12 ctx := context.Background()
13 sb, err := gvx.New(ctx, gvx.Config{
14 Platform: gvx.PlatformAuto,
15 NetworkMode: gvx.NetModeNAT,
16 OCIImage: "alpine:3.20",
17 WorkspacePath: "./repo",
18 Argv: []string{"/usr/bin/git", "status"},
19 Stdout: os.Stdout,
20 Stderr: os.Stderr,
21 })
22 if err != nil {
23 fmt.Fprintf(os.Stderr, "init sandbox: %v\n", err)
24 os.Exit(1)
25 }
26 defer sb.Close()
27
28 exitCode, err := sb.Run(ctx)
29 if err != nil {
30 fmt.Fprintf(os.Stderr, "run sandbox: %v\n", err)
31 os.Exit(1)
32 }
33 os.Exit(exitCode)
34}
Ďalšie čítanie v tejto sérii
- gvx: Spúšťanie Linuxových kontajnerov, Dockera a Kubernetes v jednom neprivilegovanom procese (tento príspevok)
- Spúšťanie Docker, docker build a docker compose bez roota alebo používateľských menných priestorov: Ako zaviesť
docker:dindv zamknutých sandboxoch, kde sú blokovanésudo,unshare(CLONE_NEWUSER),mount(2)a/dev/fuse. - Spúšťanie Docker-in-Docker vnútri gVisor a vnorených sandboxov s gvx: Prečo
apt-get install docker.ioa vnorenýrunsczlyhávajú vnútrigVisorcez päť bariér jadra a akogvxspúšťa vnorenýdocker:dindpomocou slučky futexu v zdieľanej pamäti. - Rýchle izolované Docker prostredia pre RL rollouty agentov AI s gvx: Škálovanie
SWE-bencha rollout učenia agentov pomocou posilňovania s stovkami paralelných neprivilegovaných inštanciídocker:dinda 100-milisekundovými resetmi zväzkov.ext4typu copy-on-write.