За замовчуванням процес у контейнері працює від root (UID 0). Перевірити просто: docker run --rm alpine id - покаже uid=0(root).
Чому це небезпечно, якщо контейнер ізольований? Ізоляція не абсолютна:
- root у контейнері - той самий root ядра, що й на хості (без user namespaces). Вразливість у ядрі чи середовищі виконання, помилкова конфігурація (
--privileged, змонтованийdocker.sock, змонтовані каталоги хоста) - і процес отримує права root на хості; - змонтовані каталоги: root у контейнері може змінювати й видаляти файли хоста в bind mount, створювати файли, які потім не видалиш без
sudo; - зламаний застосунок (RCE через вразливість у коді) отримує повні права всередині контейнера: встановити інструменти, змінити бінарні файли, читати всі файли.
Як запустити від звичайного користувача:
RUN addgroup -g 1000 app && adduser -u 1000 -G app -D app
USER app
або під час запуску:
docker run --user 1000:1000 myapp
services:
app:
user: "1000:1000"
Що зазвичай ламається і як виправити:
- порти нижче 1024 - звичайний користувач їх не відкриє. Застосунок слухає 8080, а зовні публікується
-p 80:8080; - права на каталоги для запису (
storage,bootstrap/cacheу Laravel) -chownпри збиранні образу; - bind mount у розробці - UID у контейнері має збігатися з UID користувача на хості, інакше файли належатимуть «чужому» користувачу. Laravel Sail для цього використовує змінні
WWWUSER/WWWGROUP.
Офіційні образи: php-fpm запускає робочі процеси від www-data, хоча головний процес стартує від root; nginx має варіанти nginx-unprivileged. Для власних образів USER - стандартна практика, а сканери безпеки й Kubernetes-політики (runAsNonRoot) перевіряють це автоматично.