Почему контейнеры не должны запускаться от root по умолчанию?
Узнайте, почему запуск контейнеров от root опасен и как применить принцип наименьших привилегий через специальных пользователей, capabilities и политики безопасности в production.
Запуск контейнеров от root — одна из самых распространённых и самых опасных ошибок конфигурации в production-окружениях. Это незаметно расширяет поверхность атаки каждой рабочей нагрузки, и большинство команд не осознают проблему, пока инцидент её не обнажит.
Что на самом деле означает «запуск от root»
По умолчанию многие образы контейнеров (особенно минималистичные или устаревшие) запускают свой основной процесс как UID 0 внутри контейнера. Поскольку контейнеры используют ядро хоста совместно с другими контейнерами и самим хостом, root внутри контейнера — это не то же самое, что root на полностью изолированной виртуальной машине, но всё равно намного мощнее, чем должно быть. Если злоумышленник добивается выполнения кода внутри контейнера с правами root, он получает:
- Полный доступ на чтение/запись к любым файлам, примонтированным в контейнер, независимо от запланированных прав доступа
- Возможность устанавливать пакеты, изменять бинарники или подделывать состояние приложения
- Гораздо более лёгкий путь для выхода из контейнера, если присутствует уязвимость в ядре или runtime
- Дополнительное преимущество при комбинировании с неправильно настроенными volumes, например с примонтированным Docker socket или путём хостовой файловой системы
Даже без kernel exploit, доступ root внутри контейнера резко увеличивает область поражения любой уязвимости уровня приложения (SSRF, ошибки десериализации, произвольная запись в файл и т. д.).
Почему это важнее в оркестрируемых окружениях
В Kubernetes-кластерах контейнер от root в сочетании с избыточными Linux capabilities или permissive security context может позволить злоумышленнику:
- Изменять
/procили/sysспособами, влияющими на хост - Повысить привилегии, если включены
hostPID,hostNetworkилиhostIPC - Использовать примонтированный service account token для латерального движения по кластеру
- Выбраться на ноду, если установлен
privileged: trueили предоставлены опасные capabilities вродеSYS_ADMIN
Сам пользователь root — не всегда уязвимость, это комбинация root плюс чрезмерно щедрые kernel capabilities, хост-примонтирования или совместное использование namespace, которая превращает компрометацию контейнера в компрометацию всего кластера.
Практические шаги по hardening
1. Установите non-root пользователя в образе
Явно определите non-root пользователя в Dockerfile вместо того, чтобы полагаться на значения по умолчанию:
FROM node:20-slim
RUN useradd --uid 10001 --shell /usr/sbin/nologin appuser
USER appuser
2. Принудите это на уровне оркестратора
Не полагайтесь только на образ — примените политику на уровне runtime. В Kubernetes используйте securityContext:
securityContext:
runAsNonRoot: true
runAsUser: 10001
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
runAsNonRoot: true заставляет pod не пройти admission, если образ пытается запуститься как UID 0, гарантируя вам жёсткое ограничение, а не принцип на основе соглашения.
3. Отключите ненужные capabilities
Большинству приложений не нужны любые из стандартных Linux capabilities, предоставляемых контейнерам. Отключите всё и добавляйте обратно только то, что строго необходимо (редкие случаи вроде привязки к low ports могут потребовать NET_BIND_SERVICE).
4. Избегайте privileged mode и совместного использования хост-namespace
privileged: true, hostNetwork: true и hostPID: true должны быть зарезервированы для очень специфических инфраструктурных рабочих нагрузок (вроде определённых CNI или агентов мониторинга) — никогда для обычных контейнеров приложений.
5. Сканируйте и применяйте политики с инструментами
Используйте admission controllers или policy engines (например, Kyverno, OPA/Gatekeeper) для автоматического отклонения развёртываний, нарушающих эти правила, вместо того чтобы полагаться на ручной code review. Дополните это сканированием образов в CI, чтобы поймать root-пользователя в образах до их попадания в кластер.
Многоуровневая, а не идеальная защита
Запуск от non-root не устраняет риск полностью — kernel-level container escapes существуют независимо от пользователя внутри контейнера — но удаляет огромный класс простых техник повышения привилегий и латерального движения. В сочетании с read-only файловыми системами, отключёнными capabilities и restrictive network policies это формирует один из самых дешёвых и эффективных уровней в стратегии defense-in-depth для безопасности контейнеров.
Хотите углубиться в hardening cloud-native рабочих нагрузок? Изучите связанные материалы Korra Studio по Cloud security и DevOps pipeline hardening, чтобы построить остальную часть вашей стратегии defense-in-depth.
Написано с помощью ИИ, проверено и опубликовано Михалом Пильхом (CISSP), Korra Studio.
Это одна заметка из базы знаний Korra Studio — платформа сочетает каждую тему с наставничеством один на один.
Начать бесплатноarrow_forward