Базовая безопасность контейнеров

Рейтинг: 62.3% · 11 голосов
Практический курс по Docker: образы, контейнеры, тома, сети, Compose и продакшен. Уроки по главам с обсуждением.
Ответить
Аватара пользователя
Marina_DevOps
Сообщения: 25
Зарегистрирован: 11 май 2026, 05:31

Базовая безопасность контейнеров

Сообщение Marina_DevOps »

АкадемияDocker с нуляГлава 11 из 17
Оглавление курса (17)
  1. Что такое Docker и какие задачи он решает
  2. Установка Docker и запуск первого контейнера
  3. Образы: слои, теги и реестр Docker Hub
  4. Пишем свой Dockerfile
  5. Тома и хранение данных: volumes и bind mounts
  6. Сети в Docker: связываем контейнеры между собой
  7. Переменные окружения и конфигурация контейнеров
  8. Docker Compose: поднимаем многоконтейнерное приложение
  9. Оптимизация образов: multi-stage сборка, размер и кэш слоёв
  10. Логи, отладка и мониторинг контейнеров
  11. Базовая безопасность контейнеров (вы здесь)
  12. Подготовка к продакшену: что важно учесть
  13. Dockerfile глубже: ENTRYPOINT и CMD, HEALTHCHECK, .dockerignore, запуск не от root
  14. Реестры образов: приватные registry, push и pull, теги и digest, imagePullSecrets
  15. BuildKit и buildx: multi-arch сборки, секреты сборки, экспорт кэша
  16. Docker в CI/CD: автосборка, сканирование образов (Trivy, Docker Scout), публикация
  17. Итоговый проект и куда расти: от Dockerfile до прода, обзор оркестрации (Kubernetes, Podman, OCI)
Контейнер по умолчанию не песочница. Процесс внутри часто работает от root, имеет лишние права ядра и тянет с собой пол-дистрибутива с дырявыми пакетами. В этой главе закроем самые частые проблемы: пользователь, права, секреты и уязвимости в образах.

Не работаем от root:

Если в Dockerfile нет инструкции USER, процесс запускается от root. Внутри контейнера это root с урезанным набором прав, но при побеге из контейнера (такие уязвимости находят регулярно) атакующий получает root на хосте. Плюс банальное: примонтировали каталог хоста через bind mount (глава 5), и контейнер пишет туда файлы от root, которые потом не удалить без sudo.

Лечится парой строк в Dockerfile:

Код: Выделить всё

FROM node:22-alpine
RUN addgroup -S app && adduser -S app -G app
WORKDIR /app
COPY --chown=app:app package*.json ./
RUN npm ci --omit=dev
COPY --chown=app:app . .
USER app
CMD ["node", "server.js"]
После USER все следующие инструкции и сам процесс работают от app. Если образ чужой и пересобрать его нельзя, поможет флаг при запуске: docker run --user 1000:1000.

Урезаем права при запуске:

Docker выдает контейнеру набор capabilities, кусочков root-привилегий. Большинству приложений не нужен ни один. Заодно можно запретить запись в файловую систему контейнера и эскалацию привилегий через setuid-бинарники:

Код: Выделить всё

docker run -d --name api \
  --cap-drop ALL \
  --read-only \
  --tmpfs /tmp \
  --security-opt no-new-privileges \
  -p 127.0.0.1:8080:8080 \
  myapp:1.4.2
--read-only делает корневую ФС контейнера доступной только для чтения, а --tmpfs /tmp дает приложению место для временных файлов. Обратите внимание на 127.0.0.1 в -p: публикуйте порты на localhost, если наружу их должен отдавать только nginx или другой прокси. Docker сам прописывает правила в iptables, и опубликованный на 0.0.0.0 порт виден из интернета в обход ufw. На VPS за 300 рублей это классический способ засветить базу данных.

В Compose (глава 8) то же самое описывается декларативно:

Код: Выделить всё

services:
  api:
    image: myapp:1.4.2
    user: "1000:1000"
    read_only: true
    tmpfs:
      - /tmp
    cap_drop:
      - ALL
    security_opt:
      - no-new-privileges:true
Секреты не запекаем в образ:

Все, что попало в слой образа, остается там навсегда: docker history и любой, кто скачает образ, увидят ваши ENV с паролями и скопированный .env. Передавайте секреты при запуске (глава 7), а если секрет нужен на этапе сборки, используйте механизм секретов BuildKit:

Код: Выделить всё

RUN --mount=type=secret,id=npmrc,target=/root/.npmrc npm ci
и собирайте командой docker build --secret id=npmrc,src=$HOME/.npmrc . Файл будет доступен только на время этой инструкции и в слои не попадет.

Сканируем образы:

Базовый образ полугодовой давности это десятки известных CVE. Сканер trivy ставится одним бинарником и показывает уязвимости по слоям: trivy image myapp:1.4.2. У Docker есть встроенный docker scout cves. Гоняйте сканер в CI и пересобирайте образы на свежей базе хотя бы раз в месяц. И фиксируйте теги (глава 3): latest сегодня и latest через месяц это разные образы.

Типичные грабли:

Монтирование /var/run/docker.sock внутрь контейнера. Доступ к сокету Docker равен root на хосте, что бы ни стояло в USER. Если контейнеру нужно управлять Docker, это осознанное решение для доверенного кода, а не удобный хак.

--read-only ломает приложения, которые пишут в свои каталоги: nginx хочет /var/cache/nginx, php-fpm пишет сессии на диск. Не откатывайте флаг целиком, добавьте tmpfs на конкретный путь.

После --user 1000:1000 контейнер не сможет писать в volume, который раньше наполнялся от root. Поправьте владельца один раз: docker run --rm -v mydata:/data alpine chown -R 1000:1000 /data.

Итог: не root, минимум прав, секреты вне образа, регулярное сканирование. Этого хватает, чтобы закрыть большинство реальных инцидентов с контейнерами у небольших команд. В последней главе соберем все вместе и поговорим о подготовке к продакшену: политики рестарта, лимиты ресурсов, healthcheck.
👍6 ❤️ 🔥 😄 🤔1
✔ Лучший ответ сформирован автоматически — k8ssmith
Marina_DevOps писал(а):опубликованный на 0.0.0.0 порт виден из интернета в обход ufw вот это боль. в прошлом году так засветил postgres на vps, узнал только когда в логах пошли подключения с левых ip и база начала тормозить. с тех пор все порты только на 127.0.0.1, наружу один nginx
Перейти к ответу →
Аватара пользователя
k8ssmith
Сообщения: 2
Зарегистрирован: 02 июн 2026, 09:30

Re: Базовая безопасность контейнеров

Сообщение k8ssmith »

✔ Лучший ответ — сформирован автоматически
Marina_DevOps писал(а):опубликованный на 0.0.0.0 порт виден из интернета в обход ufw
вот это боль. в прошлом году так засветил postgres на vps, узнал только когда в логах пошли подключения с левых ip и база начала тормозить. с тех пор все порты только на 127.0.0.1, наружу один nginx
👍 ❤️ 🔥1 😄 🤔
Аватара пользователя
qwertyn
Сообщения: 4
Зарегистрирован: 28 май 2026, 00:38

Re: Базовая безопасность контейнеров

Сообщение qwertyn »

вопрос по user в compose. официальный образ postgres стартует от root и сам понижает привилегии до postgres внутри. если ему прописать user 1000:1000, он не сломается на правах к /var/lib/postgresql/data? или для таких образов это правило не применяем?
👍 ❤️ 🔥2 😄 🤔
Аватара пользователя
tiddly
Сообщения: 3
Зарегистрирован: 28 май 2026, 06:35

Re: Базовая безопасность контейнеров

Сообщение tiddly »

попробовал --read-only на своем flask-приложении, упало на записи логов в /app/logs. перевел логи в stdout, как в главе 10 советовали, и все взлетело. в итоге read_only еще и заставил сделать по-человечески
👍1 ❤️1 🔥 😄 🤔
Аватара пользователя
maker_borya
Сообщения: 1
Зарегистрирован: 21 май 2026, 23:16

Re: Базовая безопасность контейнеров

Сообщение maker_borya »

спасибо за наводку на trivy. прогнал по рабочему образу на python:3.9-slim, который никто два года не трогал, 60+ critical. пересобрал на 3.12-slim, осталось два. полчаса работы, а в отчете для безопасников красота
👍 ❤️2 🔥 😄 🤔1
Ответить
← Предыдущая глава
Логи, отладка и мониторинг контейнеров
Следующая глава →
Подготовка к продакшену: что важно учесть

Все главы курса «Docker с нуля»

Поделиться темой: ✈ Telegram VK

Вернуться в «Docker с нуля»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость