Перейти к содержанию
Innovialabs

Безопасность Docker-контейнеров: non-root, сканирование Trivy и др.

Практика4 мин

Коротко

Запускайте контейнер от non-root пользователя на минимальном образе, делайте файловую систему read-only, сбрасывайте все capabilities, не монтируйте Docker-сокет и останавливайте CI, если Trivy нашёл исправимые HIGH и CRITICAL уязвимости.

Коротко

Контейнер сам по себе не является надёжной границей безопасности. Он использует ядро хоста, а типичный образ запускается от root со стандартным набором capabilities. Большая часть защиты сводится к пяти привычкам:

  • процесс работает от non-root пользователя;
  • образ собирается на минимальной базе;
  • корневая файловая система только для чтения;
  • ненужные Linux capabilities сброшены (обычно все);
  • Docker-сокет никогда не монтируется в контейнер приложения.

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

Non-root пользователь и минимальный образ

Если злоумышленник проэксплуатирует приложение, он получит права его процесса. Root внутри контейнера ближе к root на хосте, чем принято думать, особенно в сочетании с ошибкой конфигурации.

FROM node:22-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
USER node
EXPOSE 3000
CMD ["node", "server.js"]

Что здесь важно:

  • USER переключает на непривилегированную учётную запись. В официальных образах Node есть пользователь node; в других создайте его через useradd или укажите числовой UID.
  • Файлы приложения принадлежат root и доступны пользователю приложения только на чтение, поэтому процесс не может переписать собственный код.
  • Слушайте порт выше 1024, тогда дополнительные привилегии для его открытия не нужны.
  • Выбирайте slim, Alpine или distroless базы и multi-stage сборку: компиляторы, пакетные менеджеры и shell остаются на этапе сборки. Меньше пакетов — меньше CVE и меньше инструментов у атакующего.

Read-only файловая система и сброс capabilities

Большинству сервисов нужно писать только во временную папку и, возможно, в один том с данными. Всё остальное можно сделать read-only.

docker run -d \
  --read-only \
  --tmpfs /tmp \
  --cap-drop ALL \
  --security-opt no-new-privileges \
  myapp:1.4.2
  • --read-only не даёт подложить бинарник или изменить конфиги.
  • --tmpfs /tmp даёт приложению место для временных файлов в памяти.
  • --cap-drop ALL убирает возможности ядра вроде смены владельца файлов или raw-доступа к сети. Возвращайте только то, что можете обосновать.
  • no-new-privileges запрещает повышение прав через setuid-бинарники.

В Kubernetes то же самое задаётся в securityContext контейнера:

securityContext:
  runAsNonRoot: true
  runAsUser: 1000
  allowPrivilegeEscalation: false
  readOnlyRootFilesystem: true
  capabilities:
    drop: ["ALL"]

Никогда не монтируйте Docker-сокет

Монтирование /var/run/docker.sock даёт контейнеру полный контроль над Docker-демоном. А кто управляет демоном, тот может запустить привилегированный контейнер с файловой системой хоста — по сути это root на хосте. Относитесь к сокету как к паролю root.

Если инструменту действительно нужен Docker (CI-раннеры, сборщики логов), вынесите его на отдельный хост, используйте фильтрующий прокси с узким allowlist или переходите на сборку образов без демона. Та же логика касается --privileged и --pid=host: в контейнерах приложений их быть не должно.

Сканирование образов Trivy в CI

Trivy — open-source сканер, который сверяет системные пакеты и зависимости языков в образе с базами уязвимостей. Ещё он умеет проверять Dockerfile и манифесты Kubernetes на ошибки конфигурации.

# остановить пайплайн при исправимых HIGH/CRITICAL уязвимостях
trivy image --severity HIGH,CRITICAL --ignore-unfixed --exit-code 1 myapp:1.4.2

# проверить Dockerfile и манифесты на ошибки конфигурации
trivy config .

Как сделать сканирование полезным, а не шумным:

  • Порог по severity: блокируйте merge на HIGH и CRITICAL, остальное показывайте в отчёте.
  • --ignore-unfixed пропускает CVE без патча — с ними всё равно ничего не сделать сейчас.
  • Принятые риски храните в .trivyignore с комментарием и датой пересмотра для каждой записи.
  • Пересканируйте регулярно, а не только при сборке: новые CVE появляются и для образов, которые не менялись.
  • Фиксируйте версию или commit сторонних CI-actions: сканер тоже часть вашей цепочки поставки.

Частые ошибки

ОшибкаКак лучше
Теги latest в продакшенеФиксировать версии или digest
Секреты, зашитые в слои образаПередавать секреты при запуске или через build secrets
Один большой образ с инструментами сборкиMulti-stage сборка, slim runtime
Просканировали один раз и забылиПлановые пересканы задеплоенных образов
--privileged, «чтобы заработало»Найти и добавить одну нужную capability

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

Не всегда. Alpine маленький, но использует musl вместо glibc, что иногда ломает совместимость некоторых языков и нативных модулей. Slim-образы на Debian или distroless часто не хуже. Главное — меньше пакетов и регулярные обновления.

Поможем с этим

Если хотите не разбираться самим, а получить результат — этим мы занимаемся каждый день.

Обсудить проект

Читайте также

Есть идея или задача? Расскажите нам

Ответим в течение рабочего дня и предложим решение. Консультация бесплатная.