Кен Мьюз опубликовал аналитический материал о внутреннем устройстве rootless Docker, его реальных преимуществах и компромиссах безопасности. Разбор помогает оценить последствия использования такого режима.

В rootless Docker демон dockerd запускается от непривилегированного пользователя, а каждый пользователь получает собственный демон и сокет. RootlessKit создаёт пользовательское пространство имён и настраивает отображения UID через помощники newuidmap и newgidmap.

При компрометации rootless-демона атакующий получает права непривилегированного пользователя хоста. Однако user namespaces открывают непривилегированным пользователям доступ к интерфейсам ядра, которые исторически были доступны root, а контейнерные rootless-сборки могут требовать отключения фильтров seccomp и AppArmor.

Rootless Docker заменяет стандартный bridge-драйвер пользовательскими сетевыми стеками slirp4netns или pasta, что снижает производительность. Если непривилегированный overlayfs недоступен, rootless-режим обычно использует fuse-overlayfs или более медленный native snapshot.

Проверка утверждений:

  • Кен Мьюз опубликовал аналитический материал о внутреннем устройстве rootless Docker, его реальных преимуществах и компромиссах безопасности, чтобы помочь читателю оценить последствия такого режима. (подтверждено первоисточником: доказательство; «This post explores the alternative: rootless Docker. You’ll see how it works under the hood, what it genuinely improves, and why this solution introduces its own set of security trade-offs.»)
  • В rootless Docker демон dockerd запускается от непривилегированного пользователя, а каждый пользователь получает собственный демон и сокет в каталоге наподобие /run/user/1000/docker.sock вместо общего /var/run/docker.sock. (подтверждено первоисточником: доказательство; «Rootless Docker addresses the root-daemon risk by running dockerd itself as an unprivileged user. Each user who wants Docker runs their own personal daemon process, started under their own account. The socket is also per-user, typically at $XDG_RUNTIME_DIR/docker.sock (a per-user directory such as /run/user/1000/docker.sock ) rather than /var/run/docker.sock .»)
  • RootlessKit создаёт пользовательское пространство имён и настраивает отображения UID через setuid-помощники newuidmap и newgidmap, после чего демон может создавать вложенные пространства имён. (подтверждено первоисточником: доказательство; «RootlessKit bootstraps a user namespace and uses helpers to configure UID (User ID) mappings so the process inside appears to be root. These helper programs – newuidmap and newgidmap – are installed with the setuid bit.»)
  • При компрометации rootless-демона атакующий получает права непривилегированного пользователя хоста, а UID 0 сбежавшего из контейнера процесса отображается в непривилегированный UID и не позволяет менять системные файлы, ставить модули ядра или читать данные других пользователей. (подтверждено первоисточником: доказательство; «If a container escape occurs, the escaped process lands inside the user namespace as UID 0. This UID is mapped to a non-root UID on the host. That means it can’t install kernel modules, modify system files, or access other users’ data.»)
  • Rootless BuildKit применяет ту же схему: RootlessKit запускает buildkitd в пользовательском пространстве имён, где тот создаёт дочерние PID-, mount- и UTS-пространства для шагов сборки. (подтверждено первоисточником: доказательство; «RootlessKit bootstraps a user namespace, sets up UID mappings, and then starts buildkitd inside that namespace. From there, buildkitd can create the child PID, mount, and UTS (hostname) namespaces it needs for each build step.»)
  • Если UID пользователя хоста равен 1000, UID 0 внутри пространства имён отображается в 1000 на хосте, а UID 1–65535 — в диапазон из /etc/subuid; поэтому созданные файлы выглядят принадлежащими root внутри контейнера, но принадлежат непривилегированному пользователю на хосте. (подтверждено первоисточником: доказательство; «For example, if your host UID is 1000, the kernel maps UID 0 in the namespace to 1000 on the host, and UIDs 1 through 65535 map to a range defined in /etc/subuid . Files the build creates appear owned by root inside the container, but are actually owned by a non-root user on the host.»)
  • Для запуска rootless BuildKit внутри контейнера, например в Kubernetes pod, требуется seccomp=unconfined. (подтверждено первоисточником: доказательство; «When running BuildKit inside a container (for example in a Kubernetes pod), the container needs seccomp=unconfined .»)
  • На ядрах, где непривилегированное монтирование overlayfs недоступно, rootless-режим обычно переходит на fuse-overlayfs или более медленный native snapshot; ядра Linux 5.11 и новее разрешают непривилегированный overlayfs в user namespace. (подтверждено первоисточником: доказательство; «Instead, it generally falls back to fuse-overlayfs . This is a userspace reimplementation that works through FUSE (Filesystem in Userspace). It may also utilize a slower native snapshot mode with a small performance overhead. Linux kernels 5.11 and later allow unprivileged overlayfs in a user namespace, removing this limitation.»)
  • Rootless Docker не может использовать стандартный bridge-драйвер без корневых сетевых возможностей и вместо него применяет пользовательские сетевые стеки slirp4netns или pasta, что связано с потерями производительности. (подтверждено первоисточником: доказательство; «Instead, rootless Docker uses tools like slirp4netns and pasta to provide isolated networking. They simulate a full network stack entirely in userspace, avoiding the need for kernel-level network configuration but having some performance tradeoffs.»)
  • User namespaces уменьшают последствия компрометации демона, но одновременно открывают непривилегированным пользователям доступ к интерфейсам ядра, исторически доступным root, а контейнерные rootless-сборки могут требовать отключения фильтров seccomp и AppArmor. (подтверждено первоисточником: доказательство; «But the trade-offs are real. User namespaces expand the kernel’s attack surface by exposing privileged interfaces to unprivileged users, and running rootless builds inside containers often requires disabling seccomp and AppArmor protections.»)
  • При сборке по Dockerfile в GitHub Actions Runner Controller привилегии всё равно приходится получать через rootless- или privileged-доступ к API, способным воздействовать на контейнеры узла или даже кластера; избежать этого можно лишь сборкой без контейнеризации. (подтверждено первоисточником: доказательство; «If they want to use the Dockerfile approach to building containers, they need privilege from somewhere. They have to grant access – rootless or privileged – to APIs that can impact all of the containers on the same node (or in extreme cases, across the cluster). The only way to avoid this is to build without a containerization solution.»)

Первоисточники:

оценка 60.8 · тип analysis · ревизия 1 · истории st-cw4hxm