Container Escape через Docker Socket Exposure: как не превратить контейнер в «админку» всего сервера

Container Escape через Docker Socket Exposure: как не превратить контейнер в «админку» всего сервера

Проброс /var/run/docker.sock внутрь контейнера делает приложение полноценным клиентом Docker API на хосте. На практике это означает возможность запускать и останавливать контейнеры, монтировать директории хоста и управлять сетевой конфигурацией — то есть получать доступ, эквивалентный административному по оценке самой Docker . Если такой контейнер скомпрометирован, «побег» на уровень узла возможен без эксплуатации уязвимостей ядра.

Почему организации до сих пор идут на это? Чаще всего — ради скорости сборок в CI, удобства инструментов управления или «временной» диагностики. Эти сценарии понятны, но цена компромисса высока: контейнер получает возможность выполнять действия, которые обычно доступы только на уровне узла, а удалённый API без корректной защиты превращается в прямую точку входа — его разрешают только с TLS и строгой аутентификацией .

В этой статье разбираем механизм риска при экспонировании сокета, типовые конфигурации, из-за которых он появляется, признаки в Compose и Kubernetes, а также практические способы закрыть проблему: прокси над Docker API с минимально достаточными правами, rootless-режим и user namespaces, политики на уровне платформы и безопасные альтернативы в цепочке сборки.

Цель — дать практичные шаги, которые можно внедрить без радикальной перестройки процессов: от быстрой проверки инфраструктуры до устойчивых политик и мониторинга, помогающих предупредить инцидент ещё на этапе конфигурации.

Что такое Docker socket и почему он критичен

Docker-демон принимает команды по локальному Unix-сокету /var/run/docker.sock. Любой процесс, имеющий доступ к этому сокету, может управлять жизненным циклом контейнеров, сетями и томами, а также запускать новые контейнеры с произвольными параметрами. По сути, членство пользователя в группе docker приравнивается к администраторским правам на узле — это прямо обозначено в документации .

Отдельно стоит отметить риск удалённого API Docker по TCP: его можно включать только с шифрованием и аутентификацией клиентов, иначе это эквивалент «административного» порта наружу см. рекомендации по защите доступа .

Почему проброс docker.sock опасен

Монтируя сокет хоста внутрь контейнера, вы передаёте приложению возможность управлять Docker-демоном. Если злоумышленник получает доступ в этот контейнер (RCE, скомпрометированный токен, уязвимая библиотека), то следующий шаг тривиален: запустить новый контейнер с нужными привилегиями, смонтировать директории хоста, изменить сеть. Никаких специальных эксплойтов — достаточно штатного функционала API.

  • Контроль контейнеров на узле. Создание, остановка, пересоздание — как для штатного оператора.
  • Доступ к файловой системе. Запуск контейнера с монтированием / или нужных директорий хоста.
  • Эскалация прав. Старт привилегированных контейнеров, манипуляции с capabilities, сетевые изменения.
  • Сокрытие следов. Большинство действий выглядят как легитимные операции Docker API и не всегда сразу бросаются в глаза в журналах.

Типовые источники риска

Проброс сокета редко появляется «сам по себе». Чаще всего это побочный эффект удобства и стремления к скорости.

  • CI/CD с «Docker внутри Docker». Раннеру для сборки образов монтируют сокет — и это остаётся в конфигурации надолго.
  • Инструменты управления и автообновления. Portainer, Watchtower и аналоги требуют доступ к демону и нередко получают его шире, чем необходимо.
  • Диагностика и временные решения. Временный доступ для отладки со временем превращается в постоянную настройку.
  • Kubernetes с hostPath. Манифесты, где в Pod подмешан сокет Docker/Containerd (/var/run/docker.sock, /run/containerd/containerd.sock), что нарушает изоляцию и противоречит Pod Security Standards .

Последовательность атаки при наличии доступа к Docker API

Последовательность минималистична: проникновение в контейнер → обнаружение смонтированного сокета → обращение к Docker API → запуск новых контейнеров с нужными монтированиями/правами → доступ к узлу. С технической стороны это стандартные API-вызовы. Поэтому важно предотвращать саму возможность доступа, а не рассчитывать на то, что такие операции останутся незамеченными.

Как обнаружить проблему: проверочный план

Начните с инвентаризации и статического анализа конфигураций. Цель — оперативно найти, где и почему появился проброс.

Docker Compose и одиночные хосты

  • Просмотрите файлы Compose на наличие volumes с путём /var/run/docker.sock.
  • Проверьте вспомогательные контейнеры (Portainer, Watchtower, раннеры): действительно ли им необходим прямой сокет, в какой области и под чьим пользователем.

Kubernetes

  • Ищите hostPath на сокеты рантайма: Docker/Containerd/CRI-O.
  • Проверьте, включены ли Pod Security уровня baseline/restricted, и есть ли политика, блокирующая подобные монтирования.

Статический анализ IaC

  • Используйте сканеры конфигураций: Trivy Config , Checkov , KICS . В их правилах есть сигнатуры на опасные hostPath и доступ к сокетам.

Журналы и телеметрия

  • Включите аудит Docker/Kubernetes: фиксируйте создание контейнеров, добавление монтирований, изменение сетей. Это позволяет заметить злоупотребления.
  • Отслеживайте обращения к удалённым портам 2375/2376 и внутренним Unix-сокетам через средства наблюдения.

Меры предотвращения: как снизить риск без радикальной перестройки процессов

Полный отказ от проброса — идеальная цель. Но в реальной инфраструктуре часто нужны компромиссы. Ниже — практики, которые снижают риск до приемлемого уровня.

Избегайте прямого доступа к демону

Для сборок используйте инструменты, которые не требуют docker.sock:

  • Kaniko — сборка образов без доступа к демону, публикация напрямую в реестр.
  • Docker BuildKit в изолированном или rootless-режиме: кэш, параллелизм, без прямого доступа к хосту.
  • Podman и Buildah — альтернативы для ряда сценариев сборки и управления контейнерами.

Если доступ всё же нужен — ограничьте его прокси и RBAC

Не выдавайте контейнеру «голый» сокет. Поставьте прокси над Docker API и включите только необходимые эндпоинты. Популярный вариант — docker-socket-proxy , где права включаются по переменным окружения (подход «белых списков»).

Rootless Docker и user namespaces

Запуск демона без прав суперпользователя снижает последствия компрометации. Совместите с user namespaces, чтобы UID внутри контейнера маппился на непривилегированный UID на хосте Rootless Docker , userns-remap .

Политики на уровне платформы

Запретите опасные монтирования централизованно: даже если кто-то попытается — платформа отклонит запрос.

Kyverno (пример политики)

{ "apiVersion": "kyverno.io/v1", "kind": "ClusterPolicy", "metadata": { "name": "deny-runtime-sockets" }, "spec": { "validationFailureAction": "enforce", "rules": [{ "name": "block-runtime-sockets", "match": { "resources": { "kinds": ["Pod"] } }, "validate": { "message": "Монтирование сокетов рантайма запрещено", "deny": { "conditions": { "any": [{ "key": "{{ request.object.spec.volumes[].hostPath.path || '' }}", "operator": "AnyIn", "value": ["/var/run/docker.sock","/run/containerd/containerd.sock","/var/run/crio/crio.sock"] }] } } } }] } } 

OPA Gatekeeper (пример constraint)

apiVersion: constraints.gatekeeper.sh/v1beta1 kind: K8sDenyHostPath metadata: name: deny-runtime-sockets spec: match: kinds: - apiGroups: [""] kinds: ["Pod"] parameters: blockedPaths: - "/var/run/docker.sock" - "/run/containerd/containerd.sock" - "/var/run/crio/crio.sock" 

Усиление песочницы

  • Включите профили seccomp, AppArmor/SELinux и флаг no-new-privileges по умолчанию см. рекомендации Docker .
  • Минимизируйте Linux capabilities: оставляйте только необходимые для работы приложения.
  • В Kubernetes используйте Pod Security уровня restricted и SecurityContext с запретом привилегированных контейнеров.

Удалённый Docker API — только с TLS и mTLS

Если по архитектуре нужен удалённый доступ к демону, применяйте TLS, проверку клиентских сертификатов и сетевую изоляцию (ACL, VPN, частные сегменты) официальный гайд .

Специальные инструменты (Portainer, Watchtower)

Для таких сервисов выделяйте отдельный узел/namespace, включайте TLS, ведите подробный аудит действий и ограничивайте эндпоинты API через прокси. Это не «рядовые» приложения и к ним нужен отдельный контроль.

CI/CD без проброса сокета

Сборка образов — главный источник соблазна «смонтировать сокет». Сегодня есть зрелые альтернативы.

  • Kaniko — сборка в контейнере, артефакт сразу уходит в реестр; поддерживается кэширование слоёв.
  • BuildKit — предоставляет производительность и кэш без необходимости управлять демоном на хосте; поддерживает rootless.
  • Эфемерные раннеры — если нужен полноценный Docker, выполняйте сборку на отдельной VM и удаляйте её по завершении.
  • Целостность цепочки поставки — подпись образов (Cosign/Sigstore), аттестации (SLSA) и политика приёма только подписанных артефактов.

Мониторинг и оповещения

Даже при строгих политиках стоит контролировать события, связанные с управлением контейнерами.

  • Аномалии Docker/K8s: создание контейнеров вне релизных процедур, запуск с --privileged, появление hostPath на сокеты.
  • Сетевые признаки: обращения к 2375/2376, неожиданный трафик к демону с нетипичных хостов.
  • Аудит Kubernetes: фильтрация по verbs create/patch для Pod/DaemonSet/Deployment с проверкой volumes/hostPath.

Что делать, если «сокет уже внутри»

Контейнер с доступом к Docker API следует рассматривать как потенциальный мост на уровень узла. План реагирования:

  1. Изоляция. Ограничьте сеть для Pod/контейнера, зафиксируйте состояние (снимки, логи).
  2. Аудит действий API. Проверьте историю создания контейнеров, монтирования, изменения сетей и подключённые образы.
  3. Проверка узла. Поиск неизвестных процессов/служб, новых пользователей, изменённых конфигураций, таймеров.
  4. Ротация секретов. Ключи, токены, пароли — всё, до чего мог быть доступ, меняется в приоритетном порядке.
  5. Восстановление из чистого состояния. Пересборка образов и переразвёртывание; «ремонт на месте» возможен, но рискован.
  6. Постмортем. Почему проброс появился, почему его не поймали проверки, как предотвратить повторение.

Краткий чек-лист для продакшена

  • Не монтируйте docker.sock и сокеты рантайма в приложения, которым это не критично.
  • Если доступ необходим — только через прокси с белыми списками методов и учётной записью с минимальными правами.
  • Используйте rootless Docker и/или userns-remap там, где возможно.
  • В Kubernetes применяйте Pod Security (restricted), Kyverno/Gatekeeper, NetworkPolicy.
  • Собирайте образы через Kaniko/BuildKit; для исключений — эфемерные раннеры.
  • Включите аудит Docker/K8s и оповещения на опасные паттерны.
  • Регулярно сканируйте IaC (Trivy/Checkov/KICS) и блокируйте PR с пробросом сокетов.

Частые вопросы

«У нас закрытый контур. Это действительно проблема?»

Да. Внутренний периметр снижает вероятность внешней атаки, но не исключает компрометацию учётных данных или уязвимость в приложении. Доступ к Docker API предоставляет слишком много полномочий, чтобы рассчитывать на «закрытую» сеть как основной барьер.

«Portainer/Watchtower без сокета не работают. Что делать?»

Выделить отдельный узел/namespace, ограничить эндпоинты API через прокси, включить TLS и детальный аудит. Это допустимая конфигурация при условии минимизации прав и постоянного контроля.

«SELinux/AppArmor решают проблему?»

Эти механизмы полезны и обязательны как часть слоёной защиты. Однако, имея доступ к Docker API, злоумышленник действует в рамках разрешённых интерфейсов демона. Политики на уровне платформы и ограничение API всё равно необходимы.

«Нужна разовая диагностика. Можно ненадолго?»

Только в изолированной среде и под запись, с временными правами и последующим удалением ресурса. Предпочтительно использовать прокси с разрешением только необходимых методов и на отдельном хосте.

Итоги

Проброс docker.sock — это не «удобный компромисс», а канал прямого управления узлом. Хорошая новость в том, что существуют зрелые альтернативы: инструменты сборки без сокета, прокси над API с минимально достаточными правами, rootless-режим, user namespaces и политики на уровне платформы. Комбинация этих мер позволяет отказаться от опасной конфигурации или сделать её строго контролируемой в исключительных случаях. Это снижает вероятность побега из контейнера и упрощает расследование, если что-то идёт не по плану.

API container DevSecOps Docker Kubernetes безопасность контейнеров
Alt text
Обращаем внимание, что все материалы в этом блоге представляют личное мнение их авторов. Редакция SecurityLab.ru не несет ответственности за точность, полноту и достоверность опубликованных данных. Вся информация предоставлена «как есть» и может не соответствовать официальной позиции компании.

КИИ Basic от Security Vision для СМБ!

Защита критической инфраструктуры стала проще! Security Vision выпустила решение КИИ Basic, автоматизирующее категорирование и защиту объектов КИИ по 127 ПП РФ и 187-ФЗ.

Сертифицировано ФСТЭК, автоматизация ключевых процессов, простое внедрение и доступная цена.

Реклама. 16+, ООО «Интеллектуальная безопасность», ИНН 7719435412