Перейти к основному содержимому
Вернуться в категорию

Безопасность Docker: Усиление защиты контейнерной среды

Лучшие практики безопасности Docker: пользователь без root, файловая система только для чтения, профили seccomp, сканирование образов, безопасность Docker socket, сетевая изоляция и управление секретами.

Время чтения: 17 dk Контейнеры и оркестрация
dockerбезопасностьконтейнерseccompapparmorсканирование образовсекретыусиление
Автор
REXE Teknoloji Network & Security Team
Редактор
REXE Teknoloji Technical Editorial
Первая публикация
Последнее обновление

Безопасность Docker: Усиление защиты контейнерной среды

Docker-контейнеры в конфигурации по умолчанию могут содержать множество уязвимостей. Контейнеры, работающие от root, чрезмерно привилегированные контейнеры и небезопасные образы представляют серьёзные риски. В этом руководстве мы рассмотрим безопасность Docker послойно.

1. Запуск от имени пользователя без root

Самая фундаментальная мера безопасности: запуск контейнеров от имени пользователя без root.

Определение пользователя в Dockerfile

hljs dockerfile
# Плохая практика — запуск от root
FROM node:20
WORKDIR /app
COPY . .
RUN npm install
CMD ["node", "server.js"]

# Хорошая практика — пользователь без root
FROM node:20

# Создать пользователя и группу
RUN groupadd -r appgroup && useradd -r -g appgroup appuser

WORKDIR /app
COPY --chown=appuser:appgroup . .
RUN npm ci --only=production

# Переключиться на пользователя без root
USER appuser

CMD ["node", "server.js"]

Указание пользователя во время выполнения

hljs bash
# Запустить с конкретным пользователем
docker run -d --user 1000:1000 myapp:latest

# Запустить с текущим пользователем
docker run -d --user $(id -u):$(id -g) myapp:latest

2. Файловая система только для чтения

hljs bash
# Запустить с корневой файловой системой только для чтения
docker run -d \
  --name myapp \
  --read-only \
  --tmpfs /tmp \
  --tmpfs /var/run \
  myapp:latest
hljs yaml
# docker-compose.yml
services:
  app:
    image: myapp:latest
    read_only: true
    tmpfs:
      - /tmp
      - /var/run
    volumes:
      - app-logs:/app/logs

3. Управление capabilities

hljs bash
# Удалить все capabilities, добавить только необходимые
docker run -d \
  --name myapp \
  --cap-drop ALL \
  --cap-add NET_BIND_SERVICE \
  myapp:latest

# НИКОГДА не использовать привилегированный режим
# docker run --privileged myapp  # ПЛОХАЯ ПРАКТИКА
hljs yaml
services:
  app:
    image: myapp:latest
    cap_drop:
      - ALL
    cap_add:
      - NET_BIND_SERVICE
      - CHOWN

4. Профили Seccomp

hljs bash
# Запустить с профилем seccomp по умолчанию (рекомендуется)
docker run -d --security-opt seccomp=default myapp:latest

# Пользовательский профиль seccomp
docker run -d \
  --security-opt seccomp=/path/to/seccomp-profile.json \
  myapp:latest

5. Безопасность Docker-образов

Безопасные практики Dockerfile

hljs dockerfile
# Минимальный образ с многоэтапной сборкой
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build

# Production-образ — минимальный
FROM node:20-alpine

# Применить обновления безопасности
RUN apk update && apk upgrade && apk add --no-cache dumb-init

# Пользователь без root
RUN addgroup -S appgroup && adduser -S appuser -G appgroup

WORKDIR /app
COPY --from=builder --chown=appuser:appgroup /app/dist ./dist
COPY --from=builder --chown=appuser:appgroup /app/node_modules ./node_modules

USER appuser

HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD wget -qO- http://localhost:3000/health || exit 1

ENTRYPOINT ["dumb-init", "--"]
CMD ["node", "dist/server.js"]

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

hljs bash
# Сканирование с Trivy (рекомендуется)
docker run --rm \
  -v /var/run/docker.sock:/var/run/docker.sock \
  aquasec/trivy:latest image myapp:latest

# Только критические и высокие уязвимости
docker run --rm \
  -v /var/run/docker.sock:/var/run/docker.sock \
  aquasec/trivy:latest image \
  --severity CRITICAL,HIGH \
  myapp:latest

6. Безопасность Docker Socket

hljs bash
# Монтировать Docker socket только для чтения (для мониторинга)
docker run -d \
  --name monitoring \
  -v /var/run/docker.sock:/var/run/docker.sock:ro \
  monitoring-app:latest

# НИКОГДА не монтировать Docker socket в production-контейнерах!

7. Управление секретами

hljs bash
# Использовать Docker secrets (режим Swarm)
echo "StrongPass123!" | docker secret create db_password -

docker service create \
  --name myapp \
  --secret db_password \
  myapp:latest
# Секрет доступен по пути /run/secrets/db_password

8. Сетевая безопасность

hljs bash
# Открывать только необходимые порты
docker run -d \
  --name myapp \
  -p 127.0.0.1:8080:8080 \
  myapp:latest

9. Лимиты ресурсов

hljs bash
# Лимиты CPU и памяти
docker run -d \
  --name myapp \
  --memory 512m \
  --memory-swap 512m \
  --cpus 1.0 \
  --pids-limit 100 \
  myapp:latest

10. Безопасность Docker Daemon

hljs json
// /etc/docker/daemon.json
{
  "icc": false,
  "no-new-privileges": true,
  "userns-remap": "default",
  "live-restore": true,
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}

Заключение

Безопасность Docker требует многоуровневого подхода. Начните с пользователя без root, файловой системы только для чтения, минимальных capabilities и сканирования образов. Никогда не передавайте секреты как переменные окружения, не монтируйте Docker socket без необходимости и защищайтесь от DoS-атак с помощью лимитов ресурсов. С этими мерами безопасности на серверах REXE вы можете обеспечить безопасность контейнерной инфраструктуры.

Часто задаваемые вопросы

Почему запуск контейнера от root опасен?

Пользователь root внутри контейнера может получить права root на хосте при наличии уязвимости container escape. Кроме того, контейнер, работающий от root, может случайно изменить критические системные файлы. Определите пользователя без root в Dockerfile с помощью директивы USER и запускайте с параметром --user.

Как сканировать Docker-образы на уязвимости?

Trivy — наиболее популярный инструмент с открытым исходным кодом: docker run --rm -v /var/run/docker.sock:/var/run/docker.sock aquasec/trivy:latest image IMAGE_NAME. Интегрируйте его в CI/CD-пайплайн для автоматического сканирования при каждой сборке. Docker Scout — официальный инструмент Docker, используется с docker scout cves IMAGE_NAME.

Когда следует использовать флаг --privileged?

Почти никогда. --privileged даёт контейнеру почти полный доступ к хосту и устраняет всю изоляцию безопасности. Если действительно необходимо (например, Docker-in-Docker), используйте только в среде разработки. В production используйте --cap-add для добавления только необходимых capabilities.

Как безопасно управлять секретами в Docker Compose?

Три метода: 1) .env-файл (простой, но должен быть добавлен в .gitignore), 2) Docker secrets (требует режима Swarm, доступны в /run/secrets/), 3) Внешние инструменты управления секретами, такие как HashiCorp Vault. Никогда не встраивайте секреты в Dockerfile или образы.

Что делает опция no-new-privileges?

no-new-privileges предотвращает получение процессами внутри контейнера новых привилегий через setuid/setgid-бинарные файлы. Это важный уровень защиты от атак privilege escalation. Можно включить по умолчанию для всех контейнеров, добавив в /etc/docker/daemon.json.

Связанные статьи

Сетевой трафикВходящий GbpsИсходящий Gbps