Как проводить аудит безопасности Docker-хостов и контейнерной среды | AdminWiki

Как проводить аудит безопасности Docker-хостов и контейнерной среды

30 августа 2026 14 мин. чтения
Содержание статьи

Аудит безопасности Docker-инфраструктуры проводят на трех уровнях: Docker-хост и Docker Engine, образы, запущенные контейнеры. Начинайте с read-only инвентаризации, затем проверяйте доступ к Docker API и docker.sock, права процессов, privileged-режим, capabilities, монтирования, сеть, опубликованные порты и секреты.

Наивысший приоритет у конфигураций, через которые контейнер может получить контроль над хостом или учетными данными: открытый Docker API, проброс /var/run/docker.sock, Privileged=true, доступ на запись к системным каталогам, запуск от root без ограничений, network_mode: host и секреты в образах или переменных окружения. Каждую находку фиксируйте с доказательством, владельцем и сроком исправления. После изменения перечитайте фактическую конфигурацию через docker inspect.

Что проверять в Docker-инфраструктуре в первую очередь

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

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

Три уровня аудита: хост, образы и контейнеры

УровеньОсновной вопросПриоритетные проверки
Docker-хостКто может управлять демоном и хостом?Docker API, docker.sock, группа docker, версии Engine, containerd и runc, firewall, SSH, daemon.json
ОбразыЧто попадает в production-артефакт?Registry, digest, Dockerfile, базовый образ, CVE, SBOM, секреты в слоях
КонтейнерыКакие полномочия реально получил процесс?Пользователь, privileged, capabilities, seccomp, AppArmor или SELinux, mounts, сеть, лимиты

Безопасный образ не компенсирует открытый Docker API. Ограниченный Docker-хост не спасает приложение, если контейнеру передали docker.sock, root-доступ и запись в /etc. Проверяйте все три уровня в одном цикле аудита.

Как подготовить инвентаризацию и зафиксировать исходное состояние

Создайте перечень хостов, окружений, владельцев сервисов и способов деплоя. Зафиксируйте версию ОС, Docker Engine, containerd, runc, количество контейнеров, образов, сетей, volumes и опубликованных портов. Отдельно отметьте ручные контейнеры, которые не создаются через основной CI/CD-процесс.

docker version
docker info
docker ps -a --no-trunc
docker image ls --digests
docker network ls
docker volume ls
ss -lntup

Для содержимого контейнеров используйте структурированный вывод. Перед сохранением результатов исключите или замаскируйте Config.Env. Удобный формат проверки: дата, имя хоста, идентификатор контейнера, команда, параметр, фактическое значение, риск, владелец, срок и статус повторной проверки.

Аудит безопасности Docker-хоста и Docker Engine

Компрометация Docker Engine часто дает атакующему возможность запускать процессы, подключать файловые системы и управлять сетями. Поэтому нарушения на хосте обычно получают критический приоритет, особенно в production-среде с несколькими сервисами или общими данными.

Версии, обновления и состав Docker-компонентов

Зафиксируйте версии Docker Engine, containerd, runc и ядра ОС. Сверьте их с внутренней политикой обновлений, статусом поддержки используемого дистрибутива и актуальными advisory вашей команды. Не помечайте компонент безопасным только по факту успешного запуска.

docker version --format '{{json .}}'
containerd --version
runc --version
uname -r
cat /etc/os-release

Отметьте компоненты с неизвестной датой обновления, локальные сборки и пакеты из нестандартных репозиториев. После обновления Docker Engine повторите проверку работающих контейнеров: меняются значения по умолчанию, поведение runtime и доступные возможности.

Доступ к Docker socket и удаленному API

Членство в группе docker рассматривайте как административный доступ к хосту. Пользователь с доступом к сокету может создать контейнер с монтированием файловой системы хоста или запустить контейнер с расширенными правами. Ограничение sudo без контроля группы docker не решает проблему.

stat -c '%A %U %G %n' /var/run/docker.sock
getent group docker
ps -ef | grep '[d]ockerd'
ss -lntp | grep -E '2375|2376|dockerd'

Найдите TCP-слушатели Docker. Порт 2375 без TLS нельзя оставлять доступным в сети. Для удаленного управления используйте защищенный канал, взаимную аутентификацию и ограничения firewall. Проброс /var/run/docker.sock в обычный прикладной контейнер считайте критической находкой, пока владелец сервиса не докажет необходимость и не предложит изолированную альтернативу.

Защита хоста и конфигурация демона

Проверьте правила firewall, SSH-доступ, учетные записи администраторов, журналы и конфигурацию демона. Конфигурация обычно находится в /etc/docker/daemon.json, но фактические аргументы запуска могут добавляться через systemd override.

cat /etc/docker/daemon.json
systemctl cat docker
systemctl show docker --property=ExecStart
journalctl -u docker --since '7 days ago'

Отдельно проверяйте insecure-registries, нестандартные hosts, отключенную проверку TLS и временные исключения. Rootless-режим снижает последствия части сценариев, но не отменяет аудит образов, монтирований, сети и секретов. Для размещения изолированных production-узлов пригодна облачная инфраструктура с отдельными серверами и сегментацией сети, например Timeweb Cloud; конфигурацию Docker и права доступа все равно нужно проверять на каждом узле.

Проверка безопасности Docker-образов

Образ проверяют до публикации и повторно после публикации. Новая CVE может появиться в уже используемой зависимости, даже если сборка раньше прошла контроль. Храните результаты сканирования вместе с digest образа, датой и правилами исключений.

Источник, тег и неизменяемый идентификатор образа

Тег удобен для чтения, но его можно переназначить на другой образ. Digest однозначно связывает деплой с конкретным набором слоев. В критичных окружениях фиксируйте образ по digest и контролируйте, кто имеет право публиковать артефакты в registry.

docker image inspect registry.example.local/app:1.8.2 \
  --format '{{index .RepoDigests 0}}'

Тег latest не используйте как единственный идентификатор в production. Укажите версию, digest, источник сборки и ответственного за публикацию. Если digest отсутствует в записи релиза, восстановить точный состав развернутого образа будет сложнее.

Dockerfile и минимизация поверхности атаки

Проверьте базовый образ, список пакетов, копирование файлов и пользователя запуска. В runtime-образ не должны попадать компиляторы, менеджеры пакетов, тестовые данные, отладочные утилиты и ключи сборки, если приложение без них работает.

FROM golang:1.24 AS build
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /out/app ./cmd/app

FROM gcr.io/distroless/static-debian12
COPY --from=build /out/app /app
USER 65532:65532
ENTRYPOINT ["/app"]

Проверьте наличие USER, многостадийной сборки и корректного .dockerignore. Файлы .env, приватные ключи, каталоги .git, дампы баз данных и локальные конфигурации не должны попадать в build context. Не передавайте секреты через ARG, если команда сборки может сохранить их в истории слоя.

Уязвимости и секреты в слоях

Сканируйте ОС-пакеты, языковые зависимости и содержимое образа. Trivy и Grype находят известные уязвимости, Syft формирует SBOM. Результат сканера требует ручной оценки: важны доступность уязвимого кода, роль сервиса, наличие компенсирующих ограничений и срок исправления.

trivy image --severity HIGH,CRITICAL --ignore-unfixed app@sha256:example
grype app@sha256:example
syft app@sha256:example -o cyclonedx-json

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

Практические команды для сканирования и настройки запуска контейнеров собраны в чек-листе безопасности Docker-контейнеров.

Проверка безопасности запущенных контейнеров

Compose-файл или шаблон деплоя не всегда отражает фактическое состояние. Override-файлы, переменные CI/CD, ручной запуск и изменения после развертывания могут выдать контейнеру другие права. Источник истины для runtime-проверки: docker inspect.

docker inspect <container> --format '{{json .HostConfig}}'
docker inspect <container> --format '{{json .Config}}'

Пользователь, root и Linux capabilities

Контейнер по умолчанию должен запускать прикладной процесс от непривилегированного пользователя. Проверьте поле Config.User, фактический UID процесса и права на подключенные volumes. Пустое значение User обычно означает запуск от root внутри контейнера.

docker inspect <container> --format 'User={{.Config.User}}'
docker exec <container> id
docker inspect <container> --format 'CapAdd={{json .HostConfig.CapAdd}} CapDrop={{json .HostConfig.CapDrop}} SecurityOpt={{json .HostConfig.SecurityOpt}}'

Удаляйте capabilities по принципу минимальных привилегий. Для большинства веб-приложений не нужны SYS_ADMIN, SYS_PTRACE, NET_ADMIN и DAC_READ_SEARCH. Включайте no-new-privileges, используйте seccomp и профиль AppArmor или SELinux, если стек и ОС их поддерживают.

Privileged-режим и доступ к устройствам

Флаг Privileged=true почти снимает стандартные ограничения контейнера. В production он допустим только для узкого технического сценария с документированным обоснованием, изолированным узлом и дополнительным контролем. Проверьте подключенные устройства и правила DeviceCgroupRules.

docker inspect <container> --format 'Privileged={{.HostConfig.Privileged}} Devices={{json .HostConfig.Devices}} DeviceRules={{json .HostConfig.DeviceCgroupRules}}'

Особого внимания требуют доступ к /dev, GPU-устройствам, блочным устройствам, сокетам runtime и каталогам Docker. Комбинация privileged-контейнера с docker.sock или доступом на запись к хостовой файловой системе получает критический уровень риска.

Read-only filesystem и лимиты ресурсов

Для сервисов без необходимости записывать в корневую файловую систему включайте read_only: true. Каталоги для временных файлов добавляйте отдельными writable mounts или tmpfs. Это усложняет закрепление вредоносного кода внутри контейнера.

docker inspect <container> --format 'Readonly={{.HostConfig.ReadonlyRootfs}} Memory={{.HostConfig.Memory}} NanoCPUs={{.HostConfig.NanoCPUs}} Pids={{.HostConfig.PidsLimit}} Restart={{.HostConfig.RestartPolicy.Name}}'

Проверьте memory limit, CPU limit, pids-limit, restart policy и healthcheck. Контейнер без ограничений может исчерпать память, CPU или PID хоста и остановить соседние сервисы. Лимиты выбирают по фактическому профилю нагрузки, затем проверяют под нагрузочным тестом.

Опасные монтирования, сеть и секреты в продакшене

Монтирования, сеть и способ передачи секретов формируют фактические границы доступа сервиса. Здесь часто встречаются настройки, добавленные для отладки и оставленные в production после завершения работ.

Bind mounts, volumes и доступ к файловой системе хоста

Проверьте все mounts, тип, источник, назначение и режим доступа. Bind mount дает контейнеру доступ к пути хоста, поэтому любой каталог оценивайте как отдельное разрешение. Наиболее опасны /, /etc, /var/run, /var/lib/docker, docker.sock, домашние каталоги администраторов, SSH-ключи, облачные credentials и резервные копии.

docker inspect <container> --format '{{range .Mounts}}{{println .Type .Source "->" .Destination "RW=" .RW}}{{end}}'

Предпочитайте named volumes для данных приложения и монтирования ro для конфигураций, когда запись не нужна. Проброс docker.sock в CI-агент, панель управления или мониторинг требует отдельного анализа. Ограниченный proxy, выделенный builder и отдельный управляющий узел снижают число процессов с прямым доступом к Docker API.

Сетевые режимы, опубликованные порты и межсервисный доступ

Проверьте network_mode: host, опубликованные порты, общие bridge-сети и доступ к административным endpoints. Контейнер в host network использует сетевой стек хоста, поэтому стандартная сетевая изоляция Docker для него не работает.

docker inspect <container> --format 'NetworkMode={{.HostConfig.NetworkMode}} Ports={{json .NetworkSettings.Ports}}'
docker network inspect <network>
ss -lntup

Сопоставьте каждый порт с потребителем: публичный HTTP(S), внутренний API, мониторинг, база данных или административный интерфейс. Публикация на 0.0.0.0 открывает сервис на всех сетевых интерфейсах хоста. Для внутренних компонентов используйте закрытую сеть Docker, firewall и явные правила межсервисного доступа.

Подробные варианты настройки bridge-сетей, volumes и cgroups разобраны в практическом гайде по сетям и безопасности Docker.

Переменные окружения, Compose-файлы и Docker secrets

Проверьте Env, Compose-файлы, .env, переменные CI/CD, конфигурацию приложения и логи. Секрет в environment variable может быть виден через inspect, диагностику процесса, дампы и ошибки приложения. Для production используйте выделенное хранилище секретов или Docker secrets там, где это подходит архитектуре.

docker inspect <container> --format '{{range .Config.Env}}{{println .}}{{end}}' | sed -E 's/(=.*)/=***MASKED***/'
find . -maxdepth 3 \( -name '.env' -o -name 'docker-compose*.yml' -o -name 'compose*.yaml' \)

Значения параметров должны быть заданы явно и согласованно. Например, при развертывании Authentik заменяйте демонстрационные UID, GID, REDIS_PASSWORD и AUTHENTIK_SECRET_KEY на собственные. Пароль Redis должен совпадать во всех связанных настройках, иначе сервисы не подключатся, а команда может временно ослабить защиту для диагностики.

Не вставляйте значения секретов в команды, сообщения, скриншоты и отчет. Если ключ попал в Git, образ, CI-лог или registry, считайте его скомпрометированным: выполните ротацию, удалите утечку из актуальной конфигурации и проверьте историю артефактов.

Как быстро найти нарушения с помощью команд и инструментов

Автоматизация ускоряет первичный скрининг, но не принимает решение о приемлемости исключения. Сканер может отметить capability как риск, хотя она нужна узкому сервису. Аудитор должен проверить назначение контейнера, компенсирующие меры и область доступа.

Read-only инвентаризация контейнеров и образов

Начните с выборки объектов и точечной проверки опасных параметров. Команды ниже ничего не меняют.

docker ps -aq | xargs -r docker inspect \
  --format '{{.Name}} privileged={{.HostConfig.Privileged}} user={{.Config.User}} network={{.HostConfig.NetworkMode}} readonly={{.HostConfig.ReadonlyRootfs}}'

docker ps -aq | xargs -r docker inspect \
  --format '{{.Name}} {{range .Mounts}}{{.Source}}:{{.Destination}}:rw={{.RW}} {{end}}'

docker ps -aq | xargs -r docker inspect \
  --format '{{.Name}} ports={{json .NetworkSettings.Ports}} caps={{json .HostConfig.CapAdd}}'

Сохраните результаты с идентификатором хоста и датой. Не отправляйте сырой docker inspect во внешний сервис: в нем могут быть переменные окружения, пути к конфигурациям и сведения о внутренней топологии.

Автоматический аудит хоста и конфигураций

Docker Bench for Security помогает проверить типовые настройки Docker-хоста и сверить их с контрольными рекомендациями. Линтеры Dockerfile и Compose-файлов полезны до деплоя: они выявляют запуск от root, проблемные инструкции и небезопасные параметры, пока изменение дешевле исправить.

Инструментальный отчет не закрывает находку автоматически. Сверяйте результат с реальным контейнером через docker inspect, проверьте владельца исключения и срок его пересмотра. Для регулярного контроля действий Docker Engine настройте журналирование и auditd по инструкциям из руководства по мониторингу и аудиту Docker.

Сканирование образов, зависимостей и SBOM

Добавьте сканирование в CI/CD до публикации образа. Блокируйте релиз при найденных Critical CVE, если для них есть исправление и уязвимый компонент реально попадает в runtime. Исключения храните рядом с кодом или в системе учета: CVE, причина, владелец, дата пересмотра.

  1. Соберите образ с версией и digest.
  2. Сформируйте SBOM через Syft.
  3. Запустите Trivy или Grype по образу и SBOM.
  4. Оцените находки, назначьте исправления и исключения.
  5. После публикации повторяйте сканирование образов в registry по расписанию.

Периодическое пересканирование нужно потому, что база уязвимостей меняется без пересборки образа. Для production полезно сравнивать результаты с предыдущим запуском и отдельно отслеживать появление новых Critical и High находок.

Чек-лист аудита Docker и план исправлений

Чек-лист превращает разовую проверку в повторяемый процесс. Для каждого пункта храните статус: пройдено, нарушение, допустимое исключение, требуется уточнение. Неподтвержденное предположение не должно становиться основанием для закрытия риска.

Как классифицировать находки по критичности

УровеньПримерыДействие
КритическийОткрытый Docker API без TLS, docker.sock в прикладном контейнере, privileged с чувствительным mount, секрет в публичном образеОграничить доступ или остановить рискованный путь, ротировать секрет, провести повторную проверку
ВысокийRoot без обоснования, запись в системный каталог, host network, административный порт на 0.0.0.0, отсутствуют memory и pids limitsИсправить в ближайшем релизе, назначить владельца и срок
СреднийMutable tag без digest, устаревший базовый образ, отсутствие healthcheck, лишняя сетьВключить в план технических работ и контролировать срок
НизкийНеполная документация исключения, устаревшая запись инвентаризацииИсправить в регламентном цикле

Критичность зависит от эксплуатируемости и ущерба. Root-процесс в одноразовом изолированном тестовом контейнере и root-процесс в публичном production-сервисе имеют разный риск. Контекст не отменяет необходимость документировать исключение.

Минимальный формат отчета

ПолеЧто записать
ОбъектХост, контейнер, образ, сеть или volume; ID и имя
Фактическое состояниеПараметр и значение без раскрытия секрета
ДоказательствоКоманда, фрагмент конфигурации, дата и хеш артефакта
РискВероятный путь эксплуатации и последствия
ИсправлениеКонкретное изменение конфигурации или процесса
Ответственный и срокВладелец сервиса, дата устранения, дата повторной проверки

Вместо пароля указывайте маску и источник: например, REDIS_PASSWORD присутствует в Config.Env, значение скрыто. Такой отчет помогает подтвердить риск без создания дополнительной утечки.

Повторная проверка после исправлений

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

docker compose up -d
 docker inspect <container> --format 'User={{.Config.User}} Privileged={{.HostConfig.Privileged}} Readonly={{.HostConfig.ReadonlyRootfs}}'
docker logs <container> --tail 100

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

Периодичность и события для внепланового аудита

Проводите полный аудит по внутреннему регламенту и запускайте внеплановую проверку после обновления Docker Engine, миграции на другой хост, смены базового образа, изменения сетевой схемы, добавления privileged-доступа, передачи docker.sock или инцидента. Критичные проверки образов и Dockerfile включайте в CI/CD при каждом релизе.

Для общей программы контроля, включая Docker, Kubernetes и Nginx, используйте практический план аудита IT-инфраструктуры. История отчетов помогает увидеть повторяющиеся исключения и сервисы, где риски возвращаются после обновлений.

Типичные ошибки при аудите безопасности Docker

Проверять только образы и игнорировать хост

Сканирование CVE не обнаружит открытый Docker API, слабые права на docker.sock, небезопасные firewall-правила или устаревшую конфигурацию демона. Образ без известных уязвимостей может работать на хосте, где любой член группы docker получает фактический административный доступ.

Включайте в каждый аудит проверку ОС, Docker Engine, прав пользователей, сокета и TCP endpoints. Это обязательная часть, а не дополнительная опция.

Считать Compose-файл источником истины

Compose-файл может отличаться от работающей конфигурации из-за override-файлов, переменных окружения, профилей и ручных действий администратора. Контейнер, созданный командой docker run, вообще не попадет в репозиторий с Compose-конфигурацией.

Сравнивайте декларацию с docker inspect, списками контейнеров, сетей, mounts и опубликованных портов. Отдельно разберите объекты без понятного владельца или pipeline-источника.

Вывести секреты ради удобства диагностики

Лог с паролем, токеном или приватным ключом превращает аудит в новый канал утечки. Маскируйте переменные в скриптах и отчетах. Не просите коллег присылать секретные значения в чат.

При обнаружении секрета в образе, Git, логах или Compose-файле выполните ротацию. Простое удаление строки не возвращает контроль над значением, которое уже могло попасть в кэш, историю Git или registry.

Вопросы и ответы по аудиту Docker

Нужно ли всегда запускать контейнеры не от root?

По умолчанию запускайте прикладной процесс от непривилегированного пользователя. Проверьте права на volumes и временные каталоги, затем задайте USER в Dockerfile или параметр user в Compose. Исключение документируйте с причиной, владельцем и компенсирующими ограничениями: read-only filesystem, удаленные capabilities, seccomp, AppArmor или SELinux, отсутствие опасных mounts.

Насколько опасен проброс docker.sock?

Доступ к docker.sock дает доступ к Docker API. Во многих сценариях это позволяет создать контейнер с доступом к ресурсам хоста, читать подключенные данные или управлять другими контейнерами. Не передавайте сокет обычному приложению. Используйте ограниченный proxy, отдельный builder или выделенный управляющий узел.

Достаточно ли Docker Bench и сканера образов?

Нет. Docker Bench и сканеры образов полезны для стандартизации типовых проверок, поиска CVE и ошибок конфигурации. Они не определяют бизнес-необходимость privileged-доступа, не знают допустимые сетевые потоки конкретного сервиса и не гарантируют совпадение Compose-файла с runtime-конфигурацией.

Как часто повторять аудит Docker-хоста?

Повторяйте автоматические проверки при каждом изменении Dockerfile, образа и deployment-конфигурации. Полный аудит хоста и работающих контейнеров проводите по регламенту команды и после событий высокого риска: обновления Engine, сетевых изменений, миграции, появления нового администратора, добавления docker.sock или privileged-контейнера. После каждого исправления обязательна точечная повторная проверка.

Рабочий порядок для production: инвентаризация, проверка Docker API и прав, анализ образов, проверка фактических параметров контейнеров, аудит mounts и сети, контроль секретов, устранение критичных находок, повторная проверка и фиксация результата в отчете.

Поделиться:
Сохранить гайд? В закладки браузера