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

Корень внутри контейнера — это не то же самое, что корень на хосте, но разделение не является абсолютным. Эксплойты повышения привилегий, нацеленные на среду выполнения, такие как хорошо документированный runc CVE-2019-5736 и подобные недостатки среды выполнения, часто требуют для успеха процесса корневого контейнера.
Некорневые контейнеры устраняют требования корневого процесса, от которых зависят эти эксплойты, значительно сужая поверхность атаки для этого класса уязвимостей, хотя они не устраняют полностью риск выхода из контейнера.
Добавление директивы 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, где это возможно, маршрутизируйте общедоступный трафик через обратный прокси-сервер и публикуйте только то, что действительно требует внешнего доступа. Обратный прокси — это наиболее надежный способ контролировать то, что отображается за пределами хоста.
Игнорирование сетевой изоляции между контейнерами
Любой контейнер в этой сети может без ограничений подключаться к любому другому контейнеру в этой сети. Мост по умолчанию не применяет фильтрацию трафика между разделяющими его контейнерами, и большинство настроек никогда не меняют эту конфигурацию.

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

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

Отдельная проблема – устаревший характер. Официальный образ, который вы получили шесть месяцев назад и с тех пор никогда не восстанавливали, накапливал неисправленные уязвимости Docker с каждой раскрытой CVE в его пакетах. Изображение не испорчено. Это просто уже не актуально.
Отчет Sonatype о состоянии цепочки поставок программного обеспечения за 2024 год обнаружили, что в 95 % случаев используется уязвимый компонент, исправленная версия уже доступна, а 80 % зависимостей приложения остаются необновленными более года. Этот шаблон применим и к базовым образам Docker, поскольку они основаны на одних и тех же пакетах с открытым исходным кодом.
Используйте официальные изображения от проверенных издателей и закрепляйте теги конкретных версий, а не полагайтесь на «последнюю версию». Установите регулярную частоту восстановления, чтобы ваши изображения оставались актуальными.
Секреты жесткого кодирования в файлах Dockerfile и Compose
Учетные данные, записанные в инструкцию Dockerfile ENV или ARG, жестко запрограммированные в блоке среды Compose, передаваемые в качестве аргументов сборки или сохраненные в файле .env, переданном в систему контроля версий, не исчезают при остановке контейнера. Они остаются в истории слоев изображения или в системе контроля версий, доступны всем, кто может к ним обратиться.

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

Автономные инструменты мониторинга и управления обычно поставляются с веб-интерфейсом, доступным на всех сетевых интерфейсах. Оставить тех, кто находится на общедоступном IP-адресе без аутентификации, — это контейнерный эквивалент оставления панели администратора разблокированной.
Аутентификация, обратный прокси-сервер и размещение в частной сети являются базовыми. Контроль доступа — это шаг настройки, который вы добавляете в любой интерфейс управления, а не то, что включено в комплект поставки.
Тот же принцип применим и к Управление Docker CLI и GUI; Доступ к демону на уровне администратора несет одинаковый риск независимо от интерфейса.
Не отслеживать, что делают ваши контейнеры
Если контейнер скомпрометирован, действия злоумышленника оставляют след: изменения поведения процессов, необычные сетевые подключения и неожиданные изменения файлов. Без сбора журналов этот след не существует в той форме, по которой вы можете действовать.
Централизованный сбор журналов, ведение журнала аудита контейнеров и инструменты мониторинга во время выполнения предоставляют вам данные для обнаружения аномальной активности до того, как она усугубится. Целью не является анализ каждой строки. У него есть данные, когда вам нужно провести расследование.
Контейнерные установки, которые работают в рабочей среде в автоматическом режиме, без конвейера журналов и предупреждений, не требуют минимального обслуживания. Они не проверяются. Это два разных рабочих состояния.
Почему инфраструктурная среда также имеет значение
Безопасность контейнера начинается с настройки, но настройка выполняется поверх инфраструктуры. Хост с неправильно настроенной сетью, общими ресурсами или без фильтрации на сетевом уровне создает условия, которые влияют на каждый контейнер над ним. Правильная настройка контейнера и правильная конфигурация сервера — две отдельные задачи.
Многие бреши в безопасности Docker усугубляются условиями, которые наследуют сами контейнеры:
- Сервер общего пользования без аппаратной изоляции между арендаторами.
- Ядро хоста работает без исправлений
- Хост без встроенной фильтрации на уровне сети.
Это не устраняет необходимость выполнения описанных выше шагов настройки, поскольку правильное усиление защиты контейнера имеет значение независимо от уровня инфраструктуры. Переход на изолированную инфраструктуру устраняет из уравнения еще один уровень беспокойства.
В Cloudzy мы предлагаем два пути в зависимости от того, что требуется для вашей установки:
- Linux VPS: чистая среда для самостоятельного развертывания Docker и выполнения шагов по усилению защиты, описанных в этой статье.
- Портейнер VPS: опция в один клик с предустановленным Portainer; сервер загружается, и вы уже в дашборде
Оба варианта работают в одной и той же инфраструктуре: виртуализация KVM, процессоры AMD Ryzen 9 с тактовой частотой до 5,7 ГГц, память DDR5, твердотельное хранилище NVMe, сеть со скоростью до 40 Гбит/с и бесплатная защита от DDoS с помощью фильтрации BuyVM в 12 точках по всему миру с соглашением об уровне обслуживания 99,95 %.
Более подробно о запуске Portainer на VPS мы расскажем в отдельной статье.
Практический контрольный список безопасности для развертываний Docker
Ошибки безопасности Docker, описанные выше, в основном происходят из-за единичных конфигурационных решений, принятых один раз и никогда не пересматриваемых. Использование этого контрольного списка для существующей установки позволяет выявить эти пробелы. Он работает как аудит, а не как руководство по развертыванию.
В этих лучших практиках безопасности Docker описано, как защитить контейнеры Docker от наиболее распространенных ошибок конфигурации, описанных выше.
Краткий справочник: все 9 ошибок
| Ошибка | Категория | Однострочное исправление |
| Запуск от имени пользователя root | Конфигурация | Добавлять ПОЛЬЗОВАТЕЛЬ директива для вашего Dockerfile |
| Порты привязаны к 0.0.0.0 | Конфигурация | Привязка к 127.0.0.1 и маршрутизация через обратный прокси. |
| Нет сетевой изоляции | Конфигурация | Разделите сервисы по отдельным определяемым пользователем сетям в зависимости от потребностей доступа. |
| Докер-разъем установлен | Конфигурация | Снимите крепление; используйте ограниченные API или альтернативы |
| Ненадежные или устаревшие изображения | Изображение | Используйте официальные изображения с прикрепленными тегами версий. |
| Жестко закодированные секреты | Изображение | Переместите учетные данные в переменные среды выполнения или в диспетчер секретов. |
| Нет графика восстановления образа | Изображение | Установите ежемесячную частоту восстановления; автоматизируйте, где это возможно |
| Неаутентифицированные информационные панели | Доступ | Добавьте аутентификацию и переместите интерфейсы управления в частные сети. |
| Нет сбора журналов контейнера | Доступ | Настройте централизованное ведение журнала и мониторинг времени выполнения. |
Мы рекомендуем сначала запустить его на существующих конфигурациях, поскольку именно здесь, скорее всего, уже присутствуют пробелы.
Контейнеры, работающие без полномочий root: Проверьте свои Dockerfiles на наличие директивы USER. Если его нет, контейнер запускается от имени пользователя root.
Привязки портов ограничены локальным хостом или прокси: Запустите docker ps и проверьте привязки портов. Запись 0.0.0.0:PORT может быть общедоступной на хостах, где ее не блокирует никакая вышестоящая группа безопасности, внешний брандмауэр или правило цепочки DOCKER-USER.
Используемые пользовательские мостовые сети: Контейнеры на мосту Docker по умолчанию могут свободно связываться друг с другом. Контейнеры на одном и том же определяемом пользователем мосте по-прежнему могут взаимодействовать друг с другом, поэтому для фактической изоляции разделите службы по разным сетям по границе доверия.
Сокет Docker не монтируется в контейнеры: Установите флажок «Создать файлы и запустить аргументы». Если /var/run/docker.sock отображается как том, подтвердите, что это необходимо и намеренно.
Базовые изображения от проверенных издателей с закрепленными версиями: FROM ubuntu:latest извлекает неуказанную, потенциально устаревшую версию. Прикрепить к конкретному выпуску.
Никаких секретов в файлах Dockerfile, файлах Compose или аргументах сборки: История слоев изображений сохраняет учетные данные после удаления контейнера. Используйте секреты создания, секреты Swarm, создания секретных средств передвижения или внешний менеджер секретов. Переменные среды выполнения лучше, чем жестко закодированные значения, но все равно появляются в выходных данных и журналах проверки.
Определен график восстановления образа: Старые образы накапливают уязвимости. Ежемесячная периодичность перестройки позволяет управлять окном воздействия для большинства настроек.
Интерфейсы управления аутентификацией: Любая панель управления с общедоступным IP-адресом без аутентификации является открытой точкой входа. Размещение в частной сети предпочтительнее, где это возможно.
Собираются журналы контейнера: Без конвейера журналов обнаружение инцидентов зависит от видимого воздействия на систему. Это запоздалый сигнал к действию.
Заключение
Конфигурация Docker по умолчанию создана для удобства, а не для безопасности. Большинство ошибок, описанных в этой статье, связаны с настройками, которые никогда не менялись после первоначального развертывания, а не с изощренными атаками.
Исправления в основном представляют собой единоразовые решения по настройке: директива USER, изменение привязки порта, пользовательская сеть, график перестройки. Ни один из них не требует новых инструментов для большинства настроек.
Правильная настройка контейнера — это первая задача. Инфраструктура, на которой он работает, является второй. Оба имеют значение, и ни одно не заменяет другое.