Docker rootless mod, Docker daemon'ını ve container'ları root olmayan bir kullanıcı olarak çalıştırır. Amaç, daemon'da veya container çalışma zamanında bir güvenlik açığı bulunsa bile saldırganın sunucuda root yetkisi elde etmesini zorlaştırmaktır. Kurulum için uidmap paketi, /etc/subuid ve /etc/subgid dosyalarında kullanıcıya ayrılmış en az 65.536 alt kimlik ve dockerd-rootless-setuptool.sh install komutu yeterlidir; ön koşullar sağlandığında kurulumun kendisi bile root yetkisi istemez.

Bu yazıda rootless modun nasıl çalıştığını, userns-remap modundan farkını, Ubuntu ve diğer dağıtımlarda kurulumu, systemd ile kullanıcı servisi olarak yönetimi, 1024 altındaki portları açmayı, kaynak limitlerini, ağ sürücülerini, bilinen sınırlamaları ve sık görülen hataların çözümünü resmî belgelere dayanarak anlatıyoruz.

Rootless mod neden var?

Docker Engine güvenlik sayfası, daemon'ın rootless moda geçilmediği sürece root yetkisi gerektirdiğini ve bu yüzden daemon'ı yalnızca güvenilen kullanıcıların kontrol etmesi gerektiğini vurgular. Sebep, Docker'ın güçlü özelliklerinden biridir: bir container'a ana makinedeki herhangi bir dizini, hatta kök dizini erişim kısıtlaması olmadan bağlayabilirsiniz. Daemon root olarak çalıştığında, daemon'a komut verebilen herkes dolaylı olarak sunucunun tamamını yönetebilir. Kurulum sonrası adımlar sayfası da docker grubunun kullanıcıya root düzeyinde yetki verdiğini açıkça yazar; bu konuyu Docker permission denied yazısında ayrıntılı ele alıyoruz.

Rootless mod bu riski daemon'ın kendisini sıradan bir kullanıcıya indirerek azaltır. Daemon ve container'lar bir kullanıcı ad alanı (user namespace) içinde çalışır. Container içinde root görünen süreç, ana makinede o sıradan kullanıcının yetkilerine sahiptir. Rootless mod, birden çok UID ve GID kullanabilmek için gereken newuidmap ve newgidmap dışında SETUID bitli ya da dosya yeteneği (file capability) taşıyan bir programa ihtiyaç duymaz.

Rootless ile userns-remap farkı

Rootless ile userns-remap farkı: Daemon kimliği, Container UID 0, Container UID n, Ayar yeri

İki mod da kullanıcı ad alanı kullanır, ama aynı şey değildir. userns-remap modunda daemon hâlâ root olarak çalışır; yalnızca container içindeki root kullanıcısı ana makinede ayrıcalıksız, yüksek numaralı bir UID'ye eşlenir. Rootless modda ise hem daemon hem container'lar root yetkisi olmadan çalışır. Kimlik eşleme kuralları da farklıdır:

KonuRootless moduserns-remap
Daemon kimliğiSıradan kullanıcıroot
Container UID 0Rootless Docker'ı çalıştıran kullanıcının UID değeri (id -u)/etc/subuid içindeki ilk alt UID
Container UID nn en az 1 iken subuid + (n - 1)subuid + n
Ayar yeriKullanıcının kendi kurulumu ve ~/.config/docker/etc/docker/daemon.json içinde userns-remap
containerd imaj deposu (Engine 29)Sürüm notları bu mod için istisna belirtmez29.0.0 notlarına göre bu modda geçici olarak kullanılamaz

Bu fark bind mount ile bağlanan dizinlerde önem kazanır. Belgelere göre rootless modda ana makinedeki kendi kullanıcınıza ait dosyalar container içinde root sahipliğinde görünür. Container içindeki uygulama örneğin UID 1000 ile çalışıyorsa, ana makinede o dosyalar subuid aralığından gelen bambaşka bir numaraya ait olur. Dizin izinlerini ayarlarken bu eşlemeyi hesaba katmanız gerekir. Bind mount ayrıntıları için Docker bind mount yazısına bakabilirsiniz.

Ön koşullar

Ana makinede newuidmap ve newgidmap komutları kurulu olmalıdır; çoğu dağıtımda bunları uidmap paketi sağlar. Ayrıca /etc/subuid ve /etc/subgid dosyalarında kullanıcı için en az 65.536 alt UID ve GID tanımlı olmalıdır. Belgelerdeki örnekte testuser kullanıcısının 231072 ile 296607 arasındaki aralığa sahip olduğu şöyle kontrol edilir:

bash
id -u
1001
whoami
testuser
grep ^$(whoami): /etc/subuid
testuser:231072:65536
grep ^$(whoami): /etc/subgid
testuser:231072:65536

Ön koşullar eksikse dockerd-rootless-setuptool.sh install bunu kendisi algılar ve yardım metni gösterir. Dağıtıma özgü birkaç not da vardır. Ubuntu 24.04 ve sonrası, ayrıcalıksız kullanıcı ad alanlarını varsayılan olarak kısıtlar; bir AppArmor profili izin vermedikçe ayrıcalıksız süreçler kullanıcı ad alanı oluşturamaz. docker-ce-rootless-extras paketini deb paketiyle kurduysanız rootlesskit için gereken AppArmor profili apparmor paketiyle birlikte gelir ve elle ayar gerekmez. Kurulum betiğiyle (paketsiz) kurduysanız profili elle eklemeniz gerekir. Arch Linux'ta kernel.unprivileged_userns_clone=1 sysctl ayarı gerekir. RHEL 8 ve benzerlerinde fuse-overlayfs kurulması önerilir, RHEL 9'da bu adım gerekmez.

Kurulum adımları

Sunucuda sistem genelinde (rootful) bir Docker daemon zaten çalışıyorsa belgeler önce onu kapatmayı önerir. Kapatmazsanız sonraki adımda --force parametresi gerekir ve siz kapatana kadar aslında rootful Docker da çalışmaya devam eder:

bash
sudo systemctl disable --now docker.service docker.socket
sudo rm /var/run/docker.sock

Docker 20.10 veya sonrasını RPM ya da DEB paketleriyle kurduysanız dockerd-rootless-setuptool.sh betiği /usr/bin içindedir. Betik yoksa docker-ce-rootless-extras paketini kurmanız gerekir. Ardından betiği root olmayan kullanıcıyla çalıştırırsınız. Paket yöneticisi kullanma yetkiniz yoksa belgeler https://get.docker.com/rootless adresindeki kurulum betiğini gösterir; bu yolda programlar ~/bin altına kurulur ve statik paket olmadığı için s390x desteklenmez. Ubuntu'da Docker Engine kurulumu için Docker Ubuntu kurulumu yazısına bakabilirsiniz.

bash
sudo apt-get install -y docker-ce-rootless-extras

dockerd-rootless-setuptool.sh install

Betik kullanıcıya ait ~/.config/systemd/user/docker.service dosyasını oluşturur, rootless adında bir CLI context'i yaratıp etkinleştirir ve gerekiyorsa PATH ile DOCKER_HOST değişkenlerini ~/.bashrc dosyasına eklemenizi önerir. Belgelerdeki çıktının ilgili satırları şunlardır:

bash
[INFO] Installed docker.service successfully.
[INFO] To control docker.service, run: `systemctl --user (start|stop|restart) docker.service`
[INFO] To run docker.service on system startup, run: `sudo loginctl enable-linger testuser`

[INFO] Creating CLI context "rootless"
Successfully created context "rootless"
[INFO] Using CLI context "rootless"
Current context is now "rootless"

İstemcinin gerçekten rootless daemon'a bağlandığını docker info ile doğrularsınız: çıktıda Context: rootless satırı ve Security Options altında rootless girdisi görünmelidir.

Daemon'ı systemd kullanıcı servisi olarak yönetmek

Daemon'ı systemd kullanıcı servisi olarak yönetmek: Soket, Veri dizini, Daemon yapılandırması

Belgeler rootless daemon'ı systemd ile yönetmeyi kuvvetle önerir. Servis kullanıcı düzeyindedir ve systemctl --user ile yönetilir. Sunucu açıldığında, siz oturum açmasanız bile daemon'ın başlaması için hem servisi etkinleştirmeniz hem de kullanıcı için lingering özelliğini açmanız gerekir:

bash
systemctl --user start docker
systemctl --user enable docker
sudo loginctl enable-linger $(whoami)

Rootless Docker'ı /etc/systemd/system/docker.service altında sistem geneli bir servis olarak çalıştırmak, User= yönergesiyle bile desteklenmez. systemd olmayan bir sistemde dockerd yerine dockerd-rootless.sh çalıştırılır ve $HOME ile $XDG_RUNTIME_DIR tanımlı olmalıdır. $XDG_RUNTIME_DIR yalnızca o kullanıcının erişebildiği, her kapanışta silinen geçici bir dizin olmalı ve /tmp altında olmamalıdır; belgeler /tmp altındaki bir dizinin TOCTOU saldırısına açık olabileceğini belirtir.

Yollar da rootful kurulumdan farklıdır ve hata ayıklarken bunu bilmek zaman kazandırır:

ÖğeRootless varsayılanıNot
Soket$XDG_RUNTIME_DIR/docker.sockXDG_RUNTIME_DIR genellikle /run/user/$UID
Veri dizini~/.local/share/dockerNFS üzerinde olmamalı
Daemon yapılandırması~/.config/dockerİstemcinin kullandığı ~/.docker dizininden farklı

Docker Engine 23.0'dan beri kurulum betiği CLI'yi rootless context'ine otomatik geçirir. İsterseniz soketi DOCKER_HOST ile de gösterebilirsiniz. Context kavramının ayrıntıları docker context ile uzak sunucu yönetimi yazısında:

bash
export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sock
docker run -d -p 8080:80 nginx

docker context use rootless
docker run -d -p 8080:80 nginx

1024 altındaki portlar

Rootless modda -p 80:80 gibi ayrıcalıklı bir ana makine portu istediğinizde daemon "cannot expose privileged port 80" hatası verir. Hata metni üç çıkış yolunu da sayar ve belgeler aynı seçenekleri önerir: ayrıcalıksız bir port kullanmak (örneğin 80 yerine 8080), rootlesskit programına CAP_NET_BIND_SERVICE yeteneği vermek ya da net.ipv4.ip_unprivileged_port_start=0 sysctl ayarını eklemek:

bash
sudo setcap cap_net_bind_service=ep $(which rootlesskit)
systemctl --user restart docker

En sade yol, uygulamayı yüksek bir porttan yayınlayıp 80 ve 443 portlarını önünde çalışan bir reverse proxy'ye bırakmaktır. Compose dosyasında bu yalnızca port eşlemesinin değişmesi anlamına gelir. Reverse proxy kavramı için reverse proxy nedir yazısına bakabilirsiniz:

yaml
services:
  web:
    image: nginx:alpine
    ports:
      - "8080:80"

CPU ve bellek limitleri

--cpus, --memory ve --pids-limit gibi cgroup tabanlı docker run bayrakları rootless modda yalnızca cgroup v2 ve systemd ile çalışır. docker info çıktısında Cgroup Driver değeri none ise koşullar sağlanmamıştır ve rootless mod bu bayrakları sessizce yok sayar. Değer systemd ise koşullar sağlanmıştır, ancak varsayılan olarak root olmayan kullanıcılara genellikle yalnızca memory ve pids denetleyicileri devredilir. Tüm denetleyicileri devretmek için belgelerdeki systemd ayarı kullanılır:

bash
sudo mkdir -p /etc/systemd/system/user@.service.d

Bu dizinde delegate.conf adlı bir dosya oluşturup şu içeriği yazarsınız, ardından sudo systemctl daemon-reload ile systemd'yi yeniden yüklersiniz:

ini
[Service]
Delegate=cpu cpuset io memory pids

cpuset denetleyicisini devretmek systemd 244 veya sonrasını gerektirir. Engine 29.0.0 sürüm notlarının cgroup v1'i kullanımdan kaldırılmış (deprecated) ilan ettiğini de hatırlatalım; destek en az Mayıs 2029'a kadar sürecek, ancak belgeler en kısa sürede cgroup v2'ye geçmeyi önerir. Limitlerin kendisini Docker CPU ve bellek limiti yazısında anlatıyoruz.

Ağ: RootlessKit sürücüleri

Rootless modda ağ, RootlessKit'in ağ ve port sürücüleriyle sağlanır ve kullanıcı alanında çalışan bir TCP/IP yığını kullanılır. Belgeler bunun çekirdek içindeki yığından genellikle daha yavaş olduğunu söyler. Engine 29.5.0 ile gvisor-tap-vsock yeni varsayılan ağ sürücüsü oldu ve slirp4netns artık Docker paketleriyle kurulmuyor; belgelerdeki tabloya göre slirp4netns kuruluysa varsayılan odur. 29.8.0 ile RootlessKit 3.1.0'a güncellendi ve yalnızca IPv4 destekleyen, pasta ağ sürücüsüyle çalışan pesto port sürücüsü eklendi.

29.5 öncesinde --net=host RootlessKit'in ağ ad alanı içinde kalıyordu; container'ın dinlediği portlara gerçek ana makine ağından ulaşılamıyordu. Engine 29.5 ve sonrasında bu sınırlama kalktı ve belgeler yavaş ağ için bir çözüm olarak --net=host kullanımını gösterir, ancak container'ın ana makine ağ ad alanını paylaşmasının güvenlik açısından istenmeyebileceğini de ekler. Bir diğer konu kaynak IP adresidir: docker run -p varsayılan olarak istemcinin kaynak IP adresini container'a taşımaz. RootlessKit 3.0 ve sonrasında bunun sebebi userland-proxy ile uyumsuzluktur ve çözüm ~/.config/docker/daemon.json dosyasına şunu eklemektir:

json
{"userland-proxy": false}

Ardından systemctl --user restart docker ile daemon yeniden başlatılır; belgeler bazı sistemlerde br_netfilter çekirdek modülünü de yüklemeniz gerekebileceğini belirtir. Bazı dağıtımlarda ping varsayılan olarak çalışmaz; bunun için net.ipv4.ping_group_range = 0 2147483647 sysctl ayarı eklenir.

Bilinen sınırlamalar

Bilinen sınırlamalar: Depolama sürücüleri, Desteklenmeyen özellikler, IP adresi, Yetenekler
  • Depolama sürücüleri: Yalnızca overlay2 (çekirdek 5.11 veya sonrası), fuse-overlayfs (çekirdek 4.18 veya sonrası ve paket kurulu), btrfs ve vfs desteklenir. Ayrıntılar için storage driver yazısı.
  • Desteklenmeyen özellikler: AppArmor, checkpoint, overlay ağı ve SCTP portlarının yayınlanması.
  • IP adresi: docker inspect içindeki IPAddress RootlessKit'in ağ ad alanına aittir ve ana makineden nsenter kullanmadan erişilemez; bunun yerine -p ile port yayınlayın.
  • Yetenekler: --cap-add ile eklenen yetenekler yalnızca container'ın kullanıcı ad alanının yönettiği kaynaklara uygulanır; ana makine veya küresel kaynaklar üzerinde yetki vermez.
  • Veri dizini: Docker data-root dizininin NFS üzerinde olması desteklenmez; bu sınırlama rootless moda özgü değildir.

Overlay ağının desteklenmemesi, rootless modu çok sunuculu Swarm kümelerinde düşünüyorsanız önemlidir; Swarm servisleri sunucular arası iletişim için overlay ağı kullanır. Swarm için Docker Swarm kurulumu yazısına bakabilirsiniz.

Sık görülen hatalar ve çözümleri

Hata veya belirtiSebepÇözüm
fork/exec /proc/self/exe: operation not permittedunprivileged_userns_clone değeri 0kernel.unprivileged_userns_clone=1 ekleyip sudo sysctl --system
fork/exec /proc/self/exe: no space left on devicemax_user_namespaces çok küçükuser.max_user_namespaces=28633 ekleyip sudo sysctl --system
No subuid ranges found for user/etc/subuid ve /etc/subgid yapılandırılmamışÖn koşullardaki aralıkları ekleyin
could not get XDG_RUNTIME_DIRXDG_RUNTIME_DIR tanımsızsystemd sistemde pam_systemd ile oturum açın
Failed to connect to bus: No such file or directorysudo -iu ile kullanıcı değiştirmekssh kullanici@localhost veya machinectl shell kullanici@
Daemon açılışta başlamıyorLingering kapalısudo loginctl enable-linger $(whoami)
lchown ... invalid argument (pull sırasında)subuid ve subgid girdisi yetersizEn az 65.536 girdi tanımlayın
--cpus ve --memory yok sayılıyorcgroup v1 moducgroup v2 ve systemd kullanın

Belgelerin özellikle uyardığı bir tuzak, root oturumundan sudo su veya sudo -iu ile kullanıcıya geçip kurulum yapmaktır. Bu durumda rootlesskit systemd'yi doğru algılayamaz ve "systemd not detected" mesajı çıkabilir. Oturum açamayan kullanıcılar için systemd-container paketindeki machinectl komutu önerilir: sudo machinectl shell myuser@.

Kaldırma

Kullanıcı servisini kaldırmak için dockerd-rootless-setuptool.sh uninstall çalıştırılır. Bu araç Docker programlarını ve verileri silmez. Veri dizinini silmek için rootlesskit rm -rf ~/.local/share/docker kullanılır.~/.bashrc dosyasına eklediğiniz PATH ve DOCKER_HOST satırlarını da kaldırın. Paketle kurduysanız docker-ce-rootless-extras paketini, betikle kurduysanız ~/bin altındaki programları silersiniz.

bash
dockerd-rootless-setuptool.sh uninstall
rootlesskit rm -rf ~/.local/share/docker

Sık Sorulan Sorular

Rootless mod docker grubuna kullanıcı eklemekten daha mı güvenli?

Belgelere göre docker grubu kullanıcıya root düzeyinde yetki verir, çünkü grup üyesi root olarak çalışan daemon'a komut verebilir. Rootless modda daemon'ın kendisi sıradan kullanıcı olarak çalışır, bu yüzden daemon'ı ele geçiren biri ana makinede o kullanıcının yetkileriyle sınırlı kalır. Bedeli yukarıdaki sınırlamalar ve ek yapılandırmadır.

Rootless ve rootful Docker aynı sunucuda birlikte çalışabilir mi?

Belgeler kuruluma geçmeden önce sistem geneli daemon'ı kapatmayı önerir; kapatmazsanız kurulum --force ister ve rootful Docker da çalışmaya devam eder. Belgeler bunun bilinen bir sorununun olmadığını, ancak kapatana kadar rootful Docker'ı da çalıştırdığınızı belirtir.

Docker in Docker rootless çalıştırılabilir mi?

Evet. Rootful bir Docker içinde rootless Docker çalıştırmak için docker:<version>-dind yerine docker:<version>-dind-rootless imajı kullanılır. Bu imaj UID 1000 ile çalışır, ancak seccomp, AppArmor ve mount maskelerini kapatmak için yine --privileged gerekir.

Rootless daemon'a uzaktan nasıl bağlanırım?

SSH ile bağlanmak için uzak sunucuda $DOCKER_HOST değişkeninin tanımlı olması gerekir; ardından docker -H ssh://kullanici@sunucu kullanılabilir. TCP ile açmak için belgeler DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS değişkenini ve TLS bayraklarını birlikte gösterir. Uzak erişimin güvenli kurulumu Docker daemon uzak erişim yazısında.

Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: Docker öğrenme rehberi · Docker permission denied çözümü · Docker daemon uzak erişim · Docker CPU ve bellek limiti · docker context · VPS güvenlik sertleştirme