Docker можно использовать в production месяцами без каких-либо видимых проблем. Контейнеры запускаются, приложения отвечают, ничего не ломается. А потом один открытый порт или одно неверно выставленное разрешение даёт атакующему точку входа, которую ему не пришлось искать с трудом. Большинство ошибок безопасности в Docker не выглядят как ошибки — до тех пор, пока что-то не идёт не так.
В этой статье разобраны конкретные конфигурации, которые создают угрозы для контейнерных сред, что именно каждая из них даёт атакующему, а в конце приведён чеклист, который можно применить к своей инфраструктуре прямо сейчас.
Почему безопасность Docker сложнее, чем кажется
Контейнеры создают ощущение изоляции. Запускаете один — он работает в собственном пространстве процессов, и изнутри соседний контейнер как будто не существует. Изоляция есть, но она неполная. Контейнеры разделяют ядро хоста, а значит, процесс внутри контейнера при определённых условиях может получить доступ к хост-системе целиком.
По умолчанию Docker настроен под удобство разработчика, а не под production-окружение. Root-доступ включён. Все порты можно привязать ко всем интерфейсам. Мониторинг во время выполнения отсутствует. Большинство разработчиков принимают эти настройки, выкатывают контейнер и идут дальше. Для старта это нормально — как готовая конфигурация безопасности это не работает.
Согласно Отчёт Red Hat «2024 State of Kubernetes Security», 67% организаций задерживали или замедляли развёртывание приложений из-за проблем с безопасностью контейнеров или Kubernetes. Как правило, причиной были не атаки, а то, что команды обнаруживали: конфигурация контейнеров требует дополнительной защиты, которую изначально не заложили.
Мы часто видим контейнеры, работающие в production с той же конфигурацией, что была на локальной машине разработчика. Именно здесь ошибки безопасности Docker накапливаются незаметно — без видимых симптомов, пока не случится аудит или сбой.
Ошибки, которые создают эти уязвимости, конкретны, предсказуемы и в большинстве своём устранимы — начиная с уровня конфигурации.
Типичные ошибки конфигурации Docker
Большинство взломов контейнеров начинаются не с эксплойта нулевого дня. Они начинаются с конфигурации, выставленной в первый день без особых раздумий о сетевой экспозиции или области привилегий.
Настройки Docker по умолчанию сделаны так, чтобы всё просто работало. Разрыв между «работает» и «защищено» — это и есть то место, где накапливаются риски безопасности контейнеров Docker, особенно в самостоятельно размещённых инфраструктурах, которые развернули и забыли.
Мы часто видим такую картину: контейнеры на серверах с публичным IP с теми же привязками портов, настройками пользователей и сетевыми конфигурациями, что были при первоначальном развёртывании.
Запуск контейнеров от root
Когда вы запускаете контейнер Docker без указания пользователя, он работает от имени root. Это означает, что любой процесс внутри контейнера, включая ваше приложение, имеет привилегии root в пространстве имён контейнера.

Root внутри контейнера — это не то же самое, что root на хосте, однако граница между ними не абсолютна. Эксплойты для повышения привилегий, направленные против среды выполнения — например, хорошо задокументированный runc CVE-2019-5736 и аналогичные уязвимости — как правило, требуют, чтобы процесс в контейнере работал от имени root.
Контейнеры без root-привилегий устраняют это требование, на котором основаны подобные эксплойты, и существенно сужают поверхность атаки для данного класса уязвимостей. Впрочем, риск побега из контейнера они не исключают полностью.
Решить эту проблему позволяет директива USER в Dockerfile. В некоторых официальных образах уже есть непривилегированный пользователь, которого можно активировать с помощью USER, однако многие образы по-прежнему работают от root без готового пользователя для приложения. В таких случаях создайте пользователя в Dockerfile перед переключением на него. В большинстве случаев это единственное изменение полностью устраняет целый класс рисков, связанных с повышением привилегий.
Открытый доступ к лишним портам из интернета
Когда вы публикуете порт через Docker, Docker напрямую добавляет собственные правила iptables. Эти правила применяются раньше, чем правила брандмауэра на уровне хоста. Это известное поведение, описанное сообществом и задокументированное в руководстве Docker по фильтрации пакетов, а не ошибка конфигурации. Из-за него UFW и аналогичные инструменты не блокируют порты, которые Docker уже открыл.

Docker пишет правила напрямую в iptables, обходя настройки UFW и firewalld на многих хостах Linux. Это означает, что порт, привязанный к 0.0.0.0, может быть доступен извне, даже если брандмауэр кажется настроенным. Группы безопасности облака и правила цепочки DOCKER-USER всё же могут заблокировать такой трафик, поэтому реальный уровень доступности зависит от конкретной конфигурации сети.
По возможности привязывайте сервисы к 127.0.0.1, направляйте публичный трафик через обратный прокси и публикуйте только те порты, которые действительно требуют внешнего доступа. Обратный прокси — наиболее надёжный способ контролировать, что именно доступно снаружи хоста.
Игнорирование сетевой изоляции между контейнерами
Любой контейнер в этой сети может свободно обращаться к любому другому контейнеру в ней. Стандартный bridge не фильтрует трафик между контейнерами, которые его используют, и большинство установок никогда не меняют эту конфигурацию.

Если один контейнер окажется скомпрометирован, открытый канал связи становится путём для горизонтального перемещения. Frontend-контейнер может обратиться к базе данных, внутреннему API или любому другому сервису в той же стандартной bridge-сети — даже если такой доступ изначально не предполагался.
Пользовательские сети дают явный контроль над тем, какие контейнеры могут общаться между собой, однако единая кастомная сеть для всех сервисов по-прежнему допускает свободный обмен трафиком между контейнерами. Настоящая изоляция требует размещения сервисов, которым не нужно взаимодействовать, в отдельных сетях. Отключение стандартного bridge — это отправная точка, а не конечная цель.
Небрежное отношение к сокету Docker
Сокет Docker по пути /var/run/docker.sock — это управляющий интерфейс всего движка Docker. Монтирование его в контейнер открывает контейнеру прямой доступ API к демону, работающему на хосте.

Имея такой доступ, контейнер может запускать новые контейнеры, монтировать каталоги хоста, просматривать и изменять работающие контейнеры и фактически управлять хост-машиной. Поверхность атаки сопоставима с root-доступом на хосте, поэтому любой инструмент, которому требуется доступ к сокету, заслуживает тщательной проверки.
В большинстве случаев существуют более безопасные альтернативы: ограниченные API или инструменты управления Docker которые не требуют доступа к сокету. Docker-в-Docker несёт собственные компромиссы в плане безопасности и эксплуатации и не является простой заменой.
Ошибки в конфигурации создают первоначальную уязвимость. Выбор образов и зависимостей определяет, как эта уязвимость накапливается со временем.
Ошибки с образами и секретами, которые переживают контейнер
Когда вы останавливаете контейнер, ошибки конфигурации внутри него останавливаются вместе с ним. Когда вы пересобираете образ, содержащий уязвимость или жёстко заданные учётные данные, проблема запускается вместе с контейнером. Ошибки на уровне образа не сбрасываются между деплоями.
Они перемещаются вместе с образом в каждую среду, которая его скачивает, в каждый реестр, который его хранит, и к каждому члену команды, который его запускает. Такая устойчивость делает управление образами и секретами отдельной категорией рисков, требующей самостоятельного аудита — в отрыве от конфигурации.
Мы часто видим такую картину: образ, тщательно выбранный в начале проекта и ни разу не пересобранный с тех пор, постепенно уходит от того уровня безопасности, который он представлял изначально.
Использование ненадёжных или устаревших образов
Публичные реестры открыты для всех. Вредоносные образы распространялись через Docker Hub — со встроенными криптомайнерами и бэкдорами в истории слоёв, которые сохраняются после перезапуска контейнеров. Проверка перед скачиванием важна, особенно для образов от неофициальных или неизвестных издателей.

Отдельная проблема — устаревание. Официальный образ, скачанный полгода назад и ни разу не пересобранный с тех пор, накопил неисправленные уязвимости Docker с каждым CVE, раскрытым против его пакетов. Образ не сломан. Он просто больше не актуален.
Отчёт Sonatype «2024 State of the Software Supply Chain» показал, что в 95% случаев, когда используется уязвимый компонент, исправленная версия уже доступна, а 80% зависимостей приложений не обновляются более года. Эта закономерность характерна и для базовых образов Docker, поскольку они опираются на те же пакеты с открытым исходным кодом.
Используйте официальные образы от проверенных издателей и фиксируйте конкретные теги версий вместо «latest». Настройте регулярный цикл пересборки, чтобы образы оставались актуальными.
Жёсткое задание секретов в Dockerfile и Compose-файлах
Учётные данные, прописанные в инструкции ENV или ARG в Dockerfile, заданные напрямую в блоке environment в Compose, переданные как аргументы сборки или сохранённые в файле .env, закоммиченном в систему контроля версий, не исчезают при остановке контейнера. Они остаются в истории слоёв образа или в репозитории и доступны всем, кто может до них добраться.

Это одна из наиболее часто упускаемых из виду ошибок в безопасности Docker, потому что в процессе разработки она не проявляется явно. API-ключ в инструкции ENV работает корректно. Но он также находится в вашем репозитории, запечён в образе и распространяется везде, куда этот образ попадает.
Современный Docker Compose поддерживает встроенный механизм секретов, который монтирует учётные данные во время выполнения без запекания их в образ. Механизм secrets API в Docker и внешние менеджеры секретов следуют тому же принципу. Именно эти решения позволяют полностью исключить учётные данные из артефактов сборки и закоммиченных файлов.
Переменные среды во время выполнения лучше жёстко заданных учётных данных, но они по-прежнему доступны через вывод Docker inspect, логи и дампы при сбоях. Это шаг вперёд по сравнению с запечёнными секретами, но не окончательное решение.
Нерегулярное обновление образов контейнеров
Запускать один и тот же образ месяцами — распространённая привычка. С каждым днём после раскрытия новой уязвимости, пока вы не пересобрали образ, ваши контейнеры работают с окном уязвимости, которое растёт без каких-либо видимых изменений.
Составьте регулярное расписание пересборок. По возможности автоматизируйте этот процесс и периодически запускайте сканер уязвимостей для текущих образов. Цель не в том, чтобы достичь совершенства. Цель — сократить время между выходом патча и его деплоем.
Контроль доступа и мониторинг нередко откладываются на потом при быстром деплое. Именно в этих категориях инциденты дольше всего остаются незамеченными.
Пробелы в контроле доступа и видимости
После того как контейнер запущен с надёжной конфигурацией и актуальными образами, остаются две категории сбоев. Обе по природе своей незаметны: слабый контроль доступа не даст о себе знать, пока кто-нибудь им не воспользуется, а пробел в мониторинге — пока вам не придётся расследовать активность, которая так и не была залогирована.
То же самое Исследование Red Hat 2024 года показало, что у 42% команд не хватает необходимых инструментов для защиты контейнеров и устранения связанных с ними угроз.
Пробелы в мониторинге, как правило, обнаруживаются уже в ходе расследования инцидентов, а не до них. К тому моменту, когда видимость становится приоритетом, команда обычно реагирует на произошедшее, а не предотвращает его.
Слабая аутентификация и открытые панели управления
Панель управления контейнерами на публичном IP без аутентификации не требует искушённого атакующего. Достаточно знать адрес. Этот порог ниже, чем большинство команд привыкло думать.

Инструменты мониторинга и управления на собственных серверах, как правило, поставляются с веб-интерфейсом, доступным на всех сетевых интерфейсах. Оставить его на публичном IP без аутентификации - это контейнерный эквивалент незаблокированной административной панели.
Базовый минимум: аутентификация, обратный прокси и размещение в приватной сети. Контроль доступа - это шаг настройки, который добавляется к любому интерфейсу управления, а не что-то, что включено по умолчанию.
Тот же принцип применим к Docker CLI и GUI управлению; доступ уровня администратора к демону несёт одинаковый риск вне зависимости от интерфейса.
Отсутствие мониторинга действий внутри контейнеров
Если контейнер скомпрометирован, активность атакующего оставляет след: изменения в поведении процессов, нетипичные сетевые соединения, неожиданные изменения файлов. Без сбора логов этот след существует не в том виде, с которым можно работать.
Централизованный сбор логов, аудит контейнеров и инструменты мониторинга среды выполнения дают данные для обнаружения аномальной активности до того, как она разрастётся. Цель не в том, чтобы анализировать каждую строку, а в том, чтобы данные были доступны в нужный момент расследования.
Контейнеры, работающие в продакшене без пайплайна логов и оповещений, - это не простота в обслуживании. Это отсутствие контроля. Между этими двумя состояниями большая разница.
Почему инфраструктурная среда тоже важна
Безопасность контейнеров начинается с конфигурации, но конфигурация работает поверх инфраструктуры. Хост с некорректно настроенной сетью, общими ресурсами или без фильтрации на сетевом уровне создаёт условия, которые влияют на каждый контейнер выше. Правильно настроить контейнеры и правильно настроить сервер - это две разные задачи.
Многие пробелы в безопасности Docker усугубляются условиями, которые контейнеры наследуют от инфраструктуры:
- Сервер с общей арендой без аппаратной изоляции между арендаторами
- Хост с непропатченным ядром
- Хост без встроенной фильтрации на сетевом уровне
Это не отменяет необходимости шагов по настройке, описанных выше: правильное усиление контейнеров важно вне зависимости от уровня инфраструктуры. Начало работы на изолированной инфраструктуре просто убирает один уровень рисков из уравнения.
В Cloudzy мы предлагаем два варианта в зависимости от требований вашей конфигурации:
- Linux VPS: чистая среда для самостоятельного развёртывания Docker и применения шагов по усилению безопасности, описанных в этой статье
- Portainer VPS: вариант в один клик с предустановленным Portainer; сервер загружается, и вы сразу попадаете в панель управления
Оба варианта работают на одной инфраструктуре: виртуализация KVM, процессоры AMD Ryzen 9 CPU с частотой буста до 5.7 GHz, память DDR5, хранилище NVMe SSD, сеть до 40 Gbps и бесплатная защита DDoS через фильтрацию BuyVM — в 12 дата-центрах по всему миру с гарантией доступности 99.95% SLA.
Подробнее о запуске Portainer на VPS мы рассказываем в отдельной статье.
Практический чеклист безопасности для развёртывания Docker
Большинство ошибок безопасности Docker, описанных выше, возникают из-за разовых решений при настройке, к которым больше не возвращаются. Этот чеклист помогает найти такие пробелы в уже работающей конфигурации. Это инструмент аудита, а не руководство по развёртыванию.
Эти рекомендации по безопасности Docker описывают, как защитить контейнеры Docker от наиболее распространённых ошибок конфигурации, перечисленных выше.
Краткий справочник: все 9 ошибок
| Ошибка | Категория | Быстрое решение |
| Запуск от root | Конфигурация | Добавьте USER директиву в ваш Dockerfile |
| Порты привязаны к 0.0.0.0 | Конфигурация | Привяжите к 127.0.0.1 и направьте трафик через обратный прокси |
| Нет сетевой изоляции | Конфигурация | Разделите сервисы по отдельным пользовательским сетям в соответствии с правами доступа. |
| Сокет Docker смонтирован | Конфигурация | Уберите монтирование; используйте scoped API или альтернативные решения |
| Ненадёжные или устаревшие образы | Образ | Используйте официальные образы с зафиксированными тегами версий |
| Секреты прописаны в коде | Образ | Перенесите учётные данные в переменные среды или менеджер секретов |
| Нет расписания пересборки образов | Образ | Установите ежемесячное расписание пересборки образов; автоматизируйте там, где это возможно |
| Дашборды без аутентификации | Доступ | Добавьте аутентификацию и перенесите интерфейсы управления в приватные сети |
| Логи контейнеров не собираются | Доступ | Настройте централизованный сбор логов и мониторинг времени выполнения |
Рекомендуем сначала запустить его на существующих конфигурациях — именно там пробелы в безопасности встречаются чаще всего.
Контейнеры запущены не от root: Проверьте Dockerfiles на наличие директивы USER. Если её нет, контейнер запускается от root.
Привязка портов ограничена localhost или проксируется: Запустите docker ps и проверьте привязки портов. Запись вида 0.0.0.0:PORT означает, что порт публично доступен на хостах, где отсутствует security group, внешний файрвол или правило цепочки DOCKER-USER.
Используются пользовательские bridge-сети: Контейнеры в стандартной bridge-сети Docker могут свободно обращаться друг к другу. Контейнеры в одной пользовательской bridge-сети также могут взаимодействовать между собой — поэтому разносите сервисы по отдельным сетям в соответствии с границами доверия для реальной изоляции.
Сокет Docker не монтируется в контейнеры: Проверьте Compose-файлы и аргументы запуска. Если /var/run/docker.sock указан как volume, убедитесь, что это необходимо и сделано намеренно.
Базовые образы от проверенных издателей с фиксированными версиями: FROM ubuntu:latest загружает неопределённую и потенциально устаревшую версию. Укажите конкретный релиз.
Никаких секретов в Dockerfiles, Compose-файлах или аргументах сборки: История слоёв образа сохраняет учётные данные даже после удаления контейнера. Используйте Compose secrets, Swarm secrets, смонтированные секреты сборки или внешний менеджер секретов. Переменные окружения во время выполнения лучше, чем хардкод, но всё равно отображаются в выводе inspect и логах.
Определено расписание пересборки образов: Устаревшие образы накапливают уязвимости. Ежемесячная пересборка позволяет удерживать окно воздействия на приемлемом уровне для большинства конфигураций.
Интерфейсы управления защищены аутентификацией: Любой дашборд на публичном IP без аутентификации — это открытая точка входа. По возможности предпочтительнее размещать их в приватной сети.
Логи контейнеров собираются: Без настроенного pipeline сбора логов обнаружить инцидент можно только по очевидному влиянию на систему. Это слишком поздний сигнал для реагирования.
Заключение
Конфигурация Docker по умолчанию рассчитана на удобство, а не на безопасность. Большинство ошибок, описанных в этой статье, связаны с настройками, которые так и не были изменены после первоначального развёртывания, а не со сложными атаками.
Большинство исправлений — это разовые решения по настройке: директива USER, изменение привязки порта, создание отдельной сети, расписание пересборки. Для большинства конфигураций они не требуют никаких дополнительных инструментов.
Правильная настройка контейнера — первая задача. Инфраструктура, на которой он работает, — вторая. Важно и то, и другое, и одно не заменяет другое.