Безопасность Docker-контейнеров: лучшие практики для продакшена
Практика4 минРедакция Innovialabs
Коротко
Безопасный контейнер работает не от root, собран из минимального проверенного образа, не хранит секретов в слоях, лишён лишних capabilities, ограничен по ресурсам, а к Docker-сокету нет доступа извне.
Что важнее всего
Контейнер — не виртуальная машина: он делит ядро с хостом. Взломанный контейнер с лишними правами легко превращается во взломанный сервер. Базовые правила для продакшена:
- Запускайте процессы не от root.
- Собирайте из минимальных базовых образов и фиксируйте их версии.
- Сканируйте образы на CVE в CI до деплоя.
- Никогда не зашивайте секреты в слои образа.
- Урезайте capabilities, используйте read-only файловую систему и лимиты ресурсов.
- Защищайте Docker-сокет и registry.
1. Запуск не от root
По умолчанию процесс в контейнере работает от root. Если злоумышленник выйдет за пределы приложения, root внутри контейнера сильно упростит следующий шаг.
FROM node:20-alpine
WORKDIR /app
COPY --chown=node:node . .
RUN npm ci --omit=dev
USER node
CMD ["node", "server.js"]
- Создайте отдельного пользователя или используйте того, что есть в базовом образе.
- Слушайте порты выше 1024, чтобы root не требовался.
- Рассмотрите rootless Docker или user namespace remapping на хосте.
2. Минимальные базовые образы
Каждый лишний пакет — это лишняя поверхность атаки и лишние CVE.
| Вариант | Когда подходит |
|---|---|
alpine / -slim | Обычные сервисы, малый размер |
| Distroless | Скомпилированные приложения и рантаймы, без shell |
scratch | Статические бинарники (Go, Rust) |
- Используйте multi-stage сборку: компиляторы и dev-зависимости остаются на этапе сборки.
- Фиксируйте базовый образ по тегу, а для критичных сервисов — по digest (
image@sha256:...). - Регулярно пересобирайте образы, чтобы патчи безопасности базового образа доходили до продакшена.
3. Сканирование образов на CVE
- Добавьте в CI сканер: Trivy, Grype или Docker Scout.
- Останавливайте сборку при критических уязвимостях, для которых есть исправление.
- Сканируйте не только при сборке, но и уже работающие образы: новые CVE появляются каждый день.
- Ведите короткий задокументированный список исключений для неприменимых находок.
trivy image --severity HIGH,CRITICAL --exit-code 1 myapp:1.4.0
4. Секреты не должны попадать в слои
Всё, что записано в слой, остаётся в истории образа, даже если следующий RUN rm удалил файл. ENV API_KEY=... и COPY .env видны любому, кто может скачать образ.
- Добавьте
.env, ключи и учётные данные в.dockerignore. - Для секретов на этапе сборки используйте BuildKit secret mounts:
RUN --mount=type=secret,id=npmrc,target=/root/.npmrc npm ci
- Секреты для работы передавайте через оркестратор: Docker/Swarm secrets, Kubernetes Secrets или менеджер секретов вроде Vault или облачного KMS.
- Если секрет хоть раз попал в опубликованный образ — смените его: удалить тег недостаточно.
5. Ограничение capabilities и ресурсов
docker run -d \
--user 1000:1000 \
--read-only --tmpfs /tmp \
--cap-drop ALL --cap-add NET_BIND_SERVICE \
--security-opt no-new-privileges \
--memory 512m --cpus 1 --pids-limit 200 \
myapp:1.4.0
--cap-drop ALL, затем возвращайте только нужное.- Никогда не используйте
--privilegedв продакшене. - Корневая ФС
--read-only, запись — только в явно заданные тома или tmpfs. - Лимиты памяти, CPU и PID не дадут одному контейнеру положить весь хост.
- Оставляйте включёнными профили seccomp и AppArmor/SELinux по умолчанию.
- Не публикуйте порты баз данных и внутренних сервисов на
0.0.0.0— используйте внутренние сети.
6. Защита Docker-сокета и registry
Доступ к /var/run/docker.sock равен root на хосте. Кто может к нему обращаться, тот может запустить привилегированный контейнер и смонтировать файловую систему хоста.
- Не монтируйте сокет в контейнеры приложений. Если инструменту он действительно нужен, используйте ограничивающий socket proxy.
- Никогда не открывайте Docker API по TCP без TLS с клиентской аутентификацией.
- Ограничьте членство в группе
dockerна хосте.
Для registry:
- Используйте приватный registry с аутентификацией и доступами по проектам.
- CI получает токен на push, серверы — токен только на pull.
- Подписывайте образы (например, cosign) и проверяйте подписи перед деплоем.
- Включите автоматическое сканирование в registry, если оно доступно.
Частые ошибки
- Тег
latestв продакшене: непонятно, что на самом деле запущено. - Секреты в
ENVили скопированные.env-файлы. - Сокет, смонтированный «только для мониторинга».
- Нет лимитов ресурсов, и одна утечка памяти роняет все сервисы на хосте.