GoSuda

Kök Yetkisi veya Kullanıcı Ad Alanları Olmadan Docker, docker build ve docker compose Çalıştırma

By Lemon Mint views ...

Hızlı Çözüm: Üç Adımda Ayrıcalıksız Docker'ı Güvenli Biçimde Çalıştırma

Kilitli bir Linux konteynerinde, CI çalıştırıcısında, Kubernetes Pod'unda veya root, sudo, kullanıcı ad alanları (unshare(CLONE_NEWUSER)), mount(2) ve /dev/fuse erişiminin engellendiği bir AI ajanı sandbox'ında çalışıyorsanız, gvx (rungv), tam bir docker:dind motorunu kullanıcı alanında çalıştırmak için güvenli, derinlemesine savunma (defense-in-depth) çözümüdür.

gvx Neden Tasarım Gereği Güvenlidir (Ayrıcalık Yükseltme Geçici Çözümü Değildir): Ana makinenin /var/run/docker.sock soketini bağlamanın ya da docker run --privileged komutunu çalıştırmanın (bunlar ana makine çekirdeği üzerinde root eşdeğeri denetim sağlar) aksine, gvx herhangi bir ana makine güvenlik politikasını (PR_SET_NO_NEW_PRIVS, seccomp, AppArmor veya root olmayan UID sınırları) atlamaz ya da zayıflatmaz. Bunun yerine rungv, kendi ana makine sürecini kilitler (PR_SET_NO_NEW_PRIVS + katı BPF seccomp izin listesi) ve dockerd'yi Google'ın bellek güvenli gVisor (Sentry) kullanıcı alanı çekirdeğinin içinde çalıştırır. Tüm konuk UID 0 yetenekleri, overlayfs bağlamaları (ext4lite) ve iptables kuralları sandbox sürecinin içinde sıkı biçimde yalıtılmış kalır.

 1# 1. rungv'yi kullanıcı alanına kurun (önceden derlenmiş, SLSA ile doğrulanmış sürüm veya go install)
 2# Seçenek A: GitHub Releases üzerinden SLSA ile doğrulanmış önceden derlenmiş ikili dosyayı doğrulayın ve çıkarın
 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# Seçenek B: Veya Go ile doğrudan kaynak koddan kurun
 9CGO_ENABLED=0 GOBIN=~/.local/bin go install z.gfire.dev/gvx/cmd/rungv@latest
10
11# 2. docker:dind'i tek dosyalık bir ext4lite birimiyle gvx içinde başlatın
12#    ~/.gvx/docker.sock (mod 0600) soketini konuk 2375 portuna iletir
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. Standart Docker CLI ve Docker Compose'u kullanıcı alanı soketine yönlendirin
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# Çıktı: overlayfs Alpine Linux ... (konteynerleştirilmiş)
26
27docker build -t app:test .
28docker run --rm app:test
29docker compose up -d

Kısıtlı Sandbox'larda Standart Rootless Araçları Neden Başarısız Olur

Bir mühendis veya otonom kodlama ajanı, sertleştirilmiş bir konteyner ya da çok kiracılı bir çalıştırıcı içinde docker build, docker run veya docker compose komutlarını çalıştırmak istediğinde, standart geçici çözümler beş ayrı çekirdek engelinde başarısız olur.

1. Ana Makine Docker Daemon Soketi Yok

Ana makinenin /var/run/docker.sock soketi ortama bağlanmadığında docker ps veya docker build komutları hemen başarısız olur:

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

2. PR_SET_NO_NEW_PRIVS, sudo ve Setuid Yardımcı Programlarını Engeller

Sertleştirilmiş konteynerler (Kubernetes'te securityContext.allowPrivilegeEscalation: false, Docker'da --security-opt=no-new-privileges veya exebox / bwrap sandbox'ları), süreç ağacında Linux PR_SET_NO_NEW_PRIVS bitini ayarlar. sudo veya setuid ikili dosyaları (newuidmap, newgidmap, fusermount3) aracılığıyla yetki yükseltmeye çalışmak başarısız olur:

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 ve Sysctl Politikaları unshare(CLONE_NEWUSER) Çağrısını Engeller

"Rootless" olarak pazarlanan araçlar (Rootless Docker, Podman, Buildah, nerdctl, bubblewrap) yine de Linux kullanıcı ad alanlarına (CLONE_NEWUSER) dayanır. Şu durumlarda başarısız olurlar:

  • Dış konteynerin varsayılan seccomp profili unshare(2) veya clone(CLONE_NEWUSER) çağrısını engellerse.
  • Ubuntu 24.04 ve üzeri kernel.apparmor_restrict_unprivileged_userns = 1 ayarını etkinleştirirse.
  • Debian veya RHEL düğümleri kernel.unprivileged_userns_clone = 0 veya user.max_user_namespaces = 0 ayarlarını uygularsa.
  • PR_SET_NO_NEW_PRIVS etkin olduğu için newuidmap, /proc/self/uid_map dosyasına yazamazsa.

Ortaya çıkan hatalar şu şekildedir:

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. Ana Makine CAP_SYS_ADMIN Olmadan mount(2) Engellenir

Bir ortam CLONE_NEWUSER kullanımına izin verse bile, dış konteyner /proc alt ağaçlarını maskelemişse (/proc/acpi, /proc/kcore, /proc/keys) veya seccomp içinde mount(2) çağrısını bırakmışsa, iç içe bir mount ad alanında yeni bir /proc bağlamak başarısız olur:

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. Eksik /dev/fuse, fuse-overlayfs Çalışmasını Bozar

Çekirdek overlayfs bağlayamayan rootless konteyner motorları fuse-overlayfs kullanmaya geri döner. /dev/fuse aygıt geçişi olmayan minimal konteynerlerde veya Kubernetes pod'larında fuse-overlayfs hemen başarısız olur:

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

gvx, docker:dind'i Tamamen Kullanıcı Alanında Nasıl Çalıştırır

gvx, Linux çekirdeğinden ad alanları oluşturmasını, dosya sistemlerini bağlamasını veya ağ arayüzlerini yapılandırmasını istemediği için beş çekirdek engelinin tamamını aşar. Bunun yerine rungv, sıradan ayrıcalıksız tek bir süreç içinde dahili bir kullanıcı alanı Linux çekirdeği (gVisor Sentry) ve bir kullanıcı alanı ağ yığını (netstack) çalıştırır.

gvx ile ayrıcalıksız Docker-in-Docker çalıştırma

1. Bellek İçi Ad Alanları ve Bağlama Tablosu (VFS2)

dockerd, containerd ve runc, rungv içinde çalıştığında, systrap bu süreçlerin sistem çağrılarını yakalar ve bunları ana makine çekirdeğine değil, süreç içi Sentry çekirdeğine yönlendirir:

  • unshare(2), clone(2), pivot_root(2), chroot(2) ve mount(2), rungv ana makine süreci sizin ayrıcalıksız ana makine UID'nizde çalışırken Sentry'nin bellek içi görev hiyerarşisi ve VFS2 bağlama tablosu (procfs, sysfs, tmpfs, devpts, cgroupfs v2) üzerinde işlem yapar.

2. Tek Dosyalık ext4lite Birimleri Üzerinde Yerel overlayfs

-v gvx-docker:/var/lib/docker (veya --mount type=volume,src=/disk/gvx-docker.ext4,dst=/var/lib/docker) parametresini geçtiğinizde, gvx yerleşik ext4lite dosya sistemini /var/lib/docker dizinine bağlar.

ext4lite, tek bir ana makine dosyası (gvx-docker.ext4) içinde JBD2 günlüklü bir ext4 dosya sistemi uygular ve trusted.overlay.* genişletilmiş öznitelikleri, karakter whiteout aygıtlarını (0:0), d_type ve RENAME_EXCHANGE desteğini içerir. Bu nedenle dockerd, konuk sistemde yerel overlayfs depolama sürücüsünü kullanır. Çok aşamalı docker build işlemleri, /dev/fuse gerektirmeden ve Docker'ın vfs yedek sürücüsünün yol açtığı disk alanı patlamasına neden olmadan Copy-on-Write katmanlarını paylaşır.

3. Kullanıcı Alanı docker0 Köprüsü ve iptables-legacy

docker:dind, gvx içinde başladığında:

  • Konuk dockerd, docker0 köprüsünü (172.17.0.1/16) oluşturur, iç içe konteynerler için sanal veth çiftlerini ekler ve NAT (DOCKER, POSTROUTING) ile FILTER zincirlerini, gvx'in kullanıcı alanı netstack yığını içinde addrtype ve conntrack eşleşmeleriyle programlar.
  • -p unix:~/.gvx/docker.sock:2375 parametresini geçmek, ana makinede bir Unix alan soketi (mod 0600) bağlar ve bağlantıları doğrudan sandbox içindeki dockerd'nin 2375 portuna iletir.

Mevcut Konteyner Araçlarıyla Karşılaştırma

Yetenek / KısıtStandart Docker (dockerd)Rootless Docker / PodmanKaniko / Buildah (Ayrıcalıksız)gvx (rungv + docker:dind)
Ana makine root veya sudo gerektirir miEvetHayırHayırHayır
PR_SET_NO_NEW_PRIVS=1 ile çalışır mıHayırHayır (newuidmap başarısız)KısmenEvet
unshare(CLONE_NEWUSER) engellendiğinde (EPERM) çalışır mıGeçerli değilHayırBuildah: Hayır / Kaniko: EvetEvet
/dev/fuse olmadan çalışır mıEvet (çekirdek overlay2 kullanır)Yalnızca yavaş vfs kopyası ileEvetEvet (ext4lite üzerinde overlayfs)
docker build (BuildKit) destekler miEvetEvet (userns izin verilirse)Yalnızca imaj oluşturma (çalışma zamanı yok)Evet
docker run ve docker compose up destekler miEvetEvet (userns izin verilirse)HayırEvet
Linux VM olmadan Windows ve macOS üzerinde çalışır mıHayır (WSL2 / VM gerektirir)Hayır (Linux VM gerektirir)HayırEvet (whpx, hvf, systrap)

Linux Üzerinde Tam Ana Makine Çekirdek Gereksinimleri

gvx, sıfır yükseltilmiş yetenek (CapEff: 0000000000000000) ve sıfır kullanıcı ad alanı gerektirir. Bir Linux ana makinesinde rungv, yalnızca üç standart ayrıcalıksız çekirdek ilkeline dayanır:

  1. Başlatma sırasında kendi alt iş parçacığında bir kez ptrace(PTRACE_ATTACH): systrap, başlangıçta yerel bir stub yardımcı iş parçacığı oluşturur, paylaşılan bellek bağlamını başlatmak için buna bağlanır ve ardından ayrılır. Ana makine kernel.yama.ptrace_scope = 3 ayarını yaparsa (bu, sistem genelinde tüm ptrace işlemlerini devre dışı bırakır) veya dış seccomp filtresinde ptrace çağrısını engellerse, systrap başlatması tamamlanamaz. (Ubuntu ve Debian'da varsayılan olan yama.ptrace_scope = 1 ayarında ebeveynden alt sürece izlemeye izin verildiği için gvx başarılı olur.)
  2. seccomp(SECCOMP_SET_MODE_FILTER): Konteyner stub iş parçacıklarından gelen konuk sistem çağrılarını yakalamak için kullanılır. Bu serinin 3. bölümünde ele alındığı gibi, gvx, SECCOMP_FILTER_FLAG_NEW_LISTENER kullanılabilir olduğunda da, iç içe bir sandbox içinde EBUSY döndürdüğünde de çalışır.
  3. mmap(..., PROT_EXEC, ...): Konuk ELF segmentlerini ve systrap paylaşılan bellek trambolinini eşlemek için kullanılır.

Uçtan Uca Örnek: Root Olmadan Çok Konteynerli Bir Uygulamayı Derleme ve Test Etme

Aşağıdaki betik, ayrıcalıksız bir kullanıcı oturumu içinde tam bir docker build ve iki konteynerli entegrasyon testi (redis + uygulama konteyneri) çalıştırır:

 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# İmajı ext4lite üzerindeki overlayfs kullanarak derleyin
20docker build -t demo-ping:latest .
21
22# Bir köprü ağı oluşturun, Redis'i başlatın ve konteynerler arasındaki bağlantıyı doğrulayın
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# Çıktı: PONG
27
28# İş yükü konteynerlerini temizleyin ve sandbox'ı durdurun
29docker rm -f cache
30docker network rm demo-net
31kill -INT $DIND_PID

Bu Serideki Diğer Okumalar

  1. gvx: Tek Bir Ayrıcalıksız Süreçte Linux Konteynerlerini, Docker'ı ve Kubernetes'i Çalıştırma: gvx'in mimari genel bakışı, çapraz platform yürütme motorları (whpx, hvf, systrap), VFS2 (erofs, ext4lite, hostfs v2) ve netstack.
  2. Docker, docker build ve docker compose'u Root veya Kullanıcı Ad Alanı Olmadan Çalıştırma (bu yazı)
  3. gvx ile gVisor ve İç İçe Sandbox'lar İçinde Docker-in-Docker Çalıştırma: gvx'in modprobe, iptables-nft, gofer üzerinde overlay2 ve gVisor (runsc) içinde iç içe SECCOMP_FILTER_FLAG_NEW_LISTENER (EBUSY) sorunlarını nasıl çözdüğü.
  4. gvx ile AI Ajanı RL Rollout'ları için Hızlı İzole Docker Ortamları: 100 milisaniyelik Copy-on-Write .ext4 birim sıfırlamalarıyla paralel SWE-bench ve RL rollout ortamlarının ölçeklendirilmesi.