heroImage: “/images/blog-heros/how-to-secure-docker-containers-in-production.png”
Как защитить Docker-контейнеры в production
В отчёте ActiveState за 2026 год (ActiveState’s 2026 report) были опрошены 250 руководителей DevSecOps из Северной Америки. Каждый респондент назвал контейнеризацию критически важной для production-стратегии, а 82% заявили, что, вероятно, столкнулись как минимум с одной атакой, связанной с контейнерами, за предыдущие 12 месяцев. В том же отчёте выяснилось, что 91% считают ограниченную видимость компонентов контейнеров своей главной зоной слепого пятна в безопасности.
Сканирование Docker-образа — это один механизм контроля, а не программа production-безопасности. Оно показывает, что находится внутри образа, но не показывает, какие привилегии, mount’ы, сети, доступ к daemon или runtime-поведение получает этот образ.
Поэтому защищайте Docker в production в порядке риска: укрепите образ, ограничьте deployment, защитите daemon и host, отслеживайте runtime-поведение и сделайте эти механизмы контроля самым простым путём для разработчиков. Цель — безопасный default, которым разработчики смогут пользоваться без создания security ticket для каждого обычного обновления.
SentinelOne приводит показатель 85% для инцидентов, связанных с контейнерами, в 2023 году, но эта более старая цифра, опубликованная поставщиком, использует другой временной период и не должна объединяться с результатами опроса ActiveState.
А текст alt выглядит так: Жизненный цикл безопасности контейнера: этапы build, registry, deploy, runtime и response; опрос ActiveState 2026 года показывает, что 82% организаций столкнулись с нарушением безопасности контейнеров.
В этой статье
- Почему одного checklist по безопасности Docker недостаточно
- Защитите образ до того, как он попадёт в ваш registry
- Сделайте небезопасные runtime-настройки сложными для отправки
- Уберите secrets и Docker socket из зоны поражения
- CIS обнаруживает drift, но не доказывает безопасность
- Добавьте runtime detection, потому что сканирование не видит поведение
- Создайте путь к golden image, которым разработчики будут пользоваться
- Выбирайте инструменты по отсутствующему механизму контроля
- Превратите механизмы контроля в регулярный production-цикл
Почему одного checklist по безопасности Docker недостаточно
Checklist объединяет разные риски в одну кучу: уязвимости образов, избыточные capabilities, открытые sockets, слабая конфигурация host и подозрительные процессы требуют разных механизмов контроля в разных точках.
ActiveState сообщает, что 90% по-прежнему используют слегка изменённые public images, однако 77% больше доверяют curated catalogues, чем public registries. Это противоречие указывает на проблему workflow: catalogue, для которого требуется security approval на каждый patch, превращается в очередь, которую разработчики обходят.
Поэтому соблюдайте следующий порядок. Каждый этап закрывает отдельный сценарий отказа:
- Соберите небольшой, отслеживаемый образ.
- Храните и проверяйте точный artifact.
- Отклоняйте небезопасные deployment-настройки.
- Сократите то, что host и daemon могут открыть наружу.
- Отслеживайте поведение в реальном времени и назначьте ответственного за реагирование.
- Автоматизируйте обновления и исключения.
Считайте цифры опроса ориентиром, а не доказательством.
Защитите образ до того, как он попадёт в ваш registry
Рассмотрим небольшой сервис orders-api, собранный на основе public Python image. Его первый Dockerfile может выглядеть так:
FROM python:latest
WORKDIR /app
COPY . .
RUN apt-get update \
&& apt-get install -y build-essential curl \
&& pip install -r requirements.txt
ENV DATABASE_PASSWORD=change-me
CMD ["python", "app.py"]
Плавающий tag latest нарушает воспроизводимость. Компиляторы и package managers остаются в runtime image, процесс запускается от root, а пароль сохраняется в истории образа.
Используйте multi-stage build. Закрепите base на version или digest из вашего процесса работы с supported base. Выбирайте minimal, distroless, Alpine или scratch runtime, если приложение это поддерживает. В меньших runtime содержится меньше packages, хотя distroless images усложняют интерактивную отладку. До внедрения такого образа задокументируйте метод отладки.
В этом примере используется virtual environment, поэтому путь к зависимостям явен:
FROM python:<pinned-build-version> AS build
WORKDIR /build
RUN python -m venv /venv
ENV PATH="/venv/bin:$PATH"
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app.py .
FROM <pinned-minimal-python-runtime>
WORKDIR /app
COPY --from=build /venv /venv
COPY --from=build /build/app.py .
ENV PATH="/venv/bin:$PATH"
USER 10001:10001
CMD ["python", "app.py"]
Используйте .dockerignore, чтобы локальная конфигурация, credentials, tests и build output не попадали в build context:
.git
.env
tests/
__pycache__/
*.pem
Dockerfile задаёт user и contents; CI должен их принудительно проверять. Выполняйте сканирование во время build и в CI с помощью Trivy, Grype, Clair или Anchore. Policy, а не простое количество CVE, определяет, какие находки блокируют release: учитывайте severity, exploitability, reachability и необходимость package.
Подписывайте и проверяйте image до deployment — Cosign является одним из вариантов. Записывайте source revision, build job, digest и signer как evidence для release.
Ограничьте круг лиц, которые могут выполнять push в production repositories. Храните immutable tags или выполняйте deployment по digest из доверенных источников с проверенными подписями.
Исправленный orders-api удаляет DATABASE_PASSWORD из образа и считывает runtime secret, показанный ниже.
latest — не стратегия versioning. «Он однажды прошёл scan» — не доказательство того, что production artifact остаётся безопасным.
Сделайте небезопасные runtime-настройки сложными для отправки
Исходный Compose service также требует исправлений:
services:
api:
image: orders-api:latest
ports:
- "8080:8080"
- "9090:9090"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
DATABASE_PASSWORD: change-me
Он публикует ненужный port и монтирует Docker socket. Он передаёт credential в качестве environment value. В нём отсутствуют resource limits. Root filesystem остаётся доступной для записи.
Используйте это как отправную точку для Compose profile stateless API; проверяйте каждую настройку применительно к сервису, а не копируйте её как универсальную policy:
services:
api:
image: registry.example.com/orders-api@sha256:<approved-digest>
expose:
- "8080"
user: "10001:10001"
read_only: true
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
mem_limit: 512m
cpus: "1.0"
pids_limit: 256
tmpfs:
- /tmp
expose оставляет port 8080 доступным для других services в Compose network, не публикуя его напрямую на host. Если это соответствует вашей архитектуре, разместите TLS на reverse proxy или load balancer. Если сам API должен быть доступен из интернета, явно определите эту границу и защитите её там.
Defaults Docker — это отправная точка, а не production policy; exploitability зависит от workload, host, network и attacker.
Применяйте profile через Compose review, deployment automation или Kubernetes admission:
- Используйте выделенного user. Укажите
USERв Dockerfile и убедитесь, что приложение работает без root. Rootless Docker или другой rootless runtime добавляет полезную границу там, где это позволяет совместимость. - Сначала удалите capabilities.
--cap-drop ALLудаляет default capability set контейнера; возвращайте только те capabilities, необходимость которых workload явно подтверждает. - Сделайте root filesystem доступной только для чтения.
--read-onlyблокирует обычную запись в filesystem образа. Вместо этого предоставьте процессу узко ограниченную temporary filesystem или volume. - Ограничьте resources. Задайте
--memory,--cpusи--pids-limit. Эти limits ограничивают один важный вид resource exhaustion, но не предотвращают каждый возможный путь denial-of-service. - Ограничьте network exposure. Публикуйте необходимые ports и подключайте только необходимые networks.
Rootless operation и least privilege могут нарушить работу software, который привязывается к privileged ports. Документируйте исключения с compensating control и датой окончания действия.
Уберите secrets и Docker socket из зоны поражения
Более поздний image layer может скрыть secret из final filesystem, оставив его в предыдущем layer в image history. Не храните DATABASE_PASSWORD в Dockerfile и source repository.
Для orders-api deployment в Docker Compose с использованием mounted secret может выглядеть так:
services:
api:
image: registry.example.com/orders-api@sha256:<approved-digest>
secrets:
- database_password
secrets:
database_password:
external: true
Приложение должно читать secret file, а не ожидать DATABASE_PASSWORD:
from pathlib import Path
database_password = Path(
"/run/secrets/database_password"
).read_text().strip()
Environment variables допустимы только тогда, когда runtime защищает их от logs, crash reports и недоверенных соседних containers; в противном случае используйте mounted secret или Vault/AWS Secrets Manager. Выполняйте rotation credentials, если есть подозрение на exposure.
Docker socket требует жёсткого запрета в обычных application services:
volumes:
- /var/run/docker.sock:/var/run/docker.sock
Mount socket передаёт управление daemon: скомпрометированный container может расширить инцидент до host. Удалённый доступ к Docker API требует TLS, ограничения network и authentication — никогда не открывайте unauthenticated daemon.
CIS обнаруживает drift, но не доказывает безопасность
CIS Docker Benchmark предоставляет воспроизводимый baseline для конфигурации Docker host, daemon и container. CIS полезен именно потому, что он скучный; опасно считать его score доказательством безопасности.
Docker Bench for Security проверяет многие из этих областей. Внимательно изучите команду перед запуском — она монтирует чувствительные host paths и Docker socket, поэтому запускайте её только в одобренной административной среде:
docker run -it --net host --pid host --cap-add audit_control \
-v /var/lib:/var/lib \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /usr/lib/systemd/system:/var/lib/systemd/system \
-v /etc:/etc \
--label docker_bench_security \
docker/docker-bench-security
Адаптируйте mounts к вашей среде и security process. Не вставляйте эту команду в незнакомый host, будто это безвредная диагностика.
Рассматривайте failed check как gap в механизме контроля. Записывайте затронутый host или container, обоснование исключения, compensating control и дату окончания действия.
CIS охватывает конфигурацию host, daemon и container; dependency scanning, runtime detection и incident response требуют отдельных механизмов контроля. Запускайте audit по расписанию и после изменений host, чтобы он выявлял drift, а не выдавал церемониальный score.
Добавьте runtime detection, потому что сканирование не видит поведение
Scanner изучает artifact. Runtime detection изучает действия live workload. Как отмечает vcso.ai, «Сканирование, которое обнаруживает уязвимый package в container image во время build, не обнаруживает угрозу, которая проявляется только в runtime».
Даже clean build может быть использован после deployment, например через недавно обнаруженную flaw или неожиданный request path. Runtime tools наблюдают за syscalls, processes и network flows, а затем создают alert, когда поведение отклоняется от policy. Falco — пример open-source detection на уровне syscalls.
Начните с rules, связанных с известным поведением приложения. Следите за неожиданными shells. Отслеживайте записи в чувствительные paths и новые outbound connections. Контролируйте операции, чувствительные к capabilities. Настраивайте rules совместно с service owner. Detection, на которую никто не реагирует, — это telemetry, а не protection.
В Kubernetes admission controllers отклоняют images, users, capabilities, host mounts или resource settings, нарушающие policy, до запуска pods; runtime monitoring отслеживает происходящее после admission. Для standalone Docker или Compose обеспечьте эквивалентные checks в deployment automation или host policy.
Назначьте ответственного за response до включения alerts:
- Определите workload, image digest, host или node, process и network activity.
- Изолируйте или остановите workload согласно процедуре, учитывающей влияние на service.
- Выполните rotation credentials, которые могли быть доступны.
- Сохраните logs и относящиеся к делу evidence.
- Выполните rebuild из clean supported base и redeploy.
- Добавьте preventive deployment или runtime rule для этого failure.
Требуйте полезную telemetry, объяснимые alerts и назначенного response owner — ни один продукт не обнаруживает каждую атаку.
Создайте путь к golden image, которым разработчики будут пользоваться
Catalogue, который ждёт security approval на каждый patch, — это очередь, которую разработчики будут обходить.
Противоречие повторяется в разных surveys: люди ценят более безопасный путь, но этот путь часто занимает слишком много времени.
Предоставьте catalogue:
- небольшой набор language и service bases;
- назначенного owner и update SLA;
- pinned versions и digests;
- автоматические rebuilds при изменении base packages;
- scanning, signing и provenance;
- copyable usage examples;
- self-service request path для новых bases;
- exceptions с owner, причиной, compensating control и датой окончания действия.
Запрос на новый base должен запускать automated build, который выполняет tests, scans, signs и publishes. Security проверяет policy и exceptional cases. Ей не следует вручную проверять каждый routine patch.
Позвольте командам использовать approved images без ticket. При изменении base публикуйте новый digest, затронутые packages и migration window. Если команде нужна другая system library, сделайте request path видимым и ограниченным по времени.
Catalogue не устранит каждое использование public image. Он может сократить число неуправляемых exceptions, сделав supported option более простой для adoption, чем самодельную строку FROM.
Выбирайте инструменты по отсутствующему механизму контроля
Покупайте тот механизм контроля, которого вам не хватает. Выбирайте на основе gap, который он закрывает, а не качества его demo. Следующие пути maturity — это примеры из сравнения CiphersSecurity за 2026 год, а не независимые рейтинги производительности.
| Ситуация команды | Примеры для старта | Вопрос для проверки |
|---|---|---|
| Небольшая команда с established CI pipeline | Trivy plus Falco | Можете ли вы сканировать и подписывать releases, направлять runtime alerts и экспортировать evidence, не создавая новую operations queue? |
| Команда с активным использованием Kubernetes, которой требуется enforcement | Sysdig или Aqua | Принудительно применяет ли продукт policy на admission и runtime для вашего cluster и может ли workflow response определить команду-владельца? |
| Большая multi-cloud команда с фрагментированной ответственностью | Wiz, Prisma Cloud или CrowdStrike | Сопоставляет ли он assets с owners во всём вашем estate, показывает ли policy gaps с полезной глубиной и создаёт ли evidence для remediation? |
Это отправные точки, а не endorsements. Небольшая команда в первую очередь должна внедрить image scanning, signing, deployment policy и lightweight detector. Kubernetes platform рано нуждается в admission и runtime controls, потому что cluster совместно используют многие teams. Фрагментированному multi-cloud estate может быть полезен CNAPP после определения ownership и baseline controls.
Docker Scout и SentinelOne Singularity Cloud Security — другие примеры на рынке. Одна CNAPP console может красиво отображать gaps, оставляя их без изменений. Проверяйте каждого кандидата относительно вашего registry, deployment path, identity model, точки enforcement policy, alert routing и evidence export.
Превратите механизмы контроля в регулярный production-цикл
Используйте следующую последовательность внедрения:
- Проведите inventory estate. Найдите images, registries, Docker hosts, daemon endpoints, socket mounts, root containers, privileged settings и production limits.
- Устраните слабые места с высоким влиянием. Удалите baked secrets, ненужный root, privileged mode, избыточные capabilities и неapproved host mounts.
- Сделайте artifacts воспроизводимыми. Закрепите bases и используйте multi-stage builds. Сканируйте в CI, подписывайте images, затем выполняйте deployment по digest.
- Применяйте deployment policy. Требуйте supported users, dropped capabilities, read-only filesystems, resource limits, approved networks и trusted registries.
- Проводите audit hosts. Запускайте Docker Bench в соответствии с CIS Docker Benchmark по расписанию и отслеживайте exceptions.
- Обнаруживайте поведение в реальном времени. Добавьте мониторинг syscalls, processes и networks с назначенным response owner.
- Автоматизируйте maintenance. Выполняйте rebuild supported bases и повторно тестируйте applications. Повторно публикуйте signed images, уведомляйте consumers и закрывайте exceptions по истечении срока.
Этот порядок является сильным default, но не заменяет threat modeling ваших workloads. Перед изменением последовательности для high-risk service оцените exploitability, требования к privileges и internet exposure.
ActiveState сообщает, что 100% респондентов, вероятно, будут использовать AI или automation для приоритизации vulnerabilities, а 95% ожидают, что intelligent remediation станет стандартом к 2026 году. Используйте эту помощь, чтобы ранжировать findings, предлагать изменения dependencies или Dockerfile, открывать remediation pull requests и обобщать затронутые workloads.
Считайте результат AI предлагаемым изменением; service owner по-прежнему отвечает за test, approval, provenance и rollback. AI может подготовить полезный pull request. Он не может установить, что приложение по-прежнему работает или что получившийся artifact заслуживает доверия.
Для orders-api генерируйте эту release record из CI metadata и deployment configuration, а затем сравнивайте её при каждом release:
digest | user | capabilities | writable paths | reachable networks | detector | response owner
Если release не может предоставить ответы по этим семи полям, остановите deployment и исправьте evidence path, прежде чем добавлять ещё один security product.