Проброс /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 следует рассматривать как потенциальный мост на уровень узла. План реагирования:
- Изоляция. Ограничьте сеть для Pod/контейнера, зафиксируйте состояние (снимки, логи).
- Аудит действий API. Проверьте историю создания контейнеров, монтирования, изменения сетей и подключённые образы.
- Проверка узла. Поиск неизвестных процессов/служб, новых пользователей, изменённых конфигураций, таймеров.
- Ротация секретов. Ключи, токены, пароли — всё, до чего мог быть доступ, меняется в приоритетном порядке.
- Восстановление из чистого состояния. Пересборка образов и переразвёртывание; «ремонт на месте» возможен, но рискован.
- Постмортем. Почему проброс появился, почему его не поймали проверки, как предотвратить повторение.
Краткий чек-лист для продакшена
- Не монтируйте
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 и политики на уровне платформы. Комбинация этих мер позволяет отказаться от опасной конфигурации или сделать её строго контролируемой в исключительных случаях. Это снижает вероятность побега из контейнера и упрощает расследование, если что-то идёт не по плану.