Блог

Защита от побега из контейнера: Практическое руководство по изоляции Docker для многопользовательского хостинга

Узнайте, как защитить контейнеры Docker от уязвимостей побега и сбоев изоляции в многопользовательских средах с помощью конкретных шагов и примеров.

Краткое содержание

Контейнеры Docker используют общий хост-ядро, что делает изоляцию критически важной — особенно в многопользовательском хостинге, где один побег из контейнера может скомпрометировать всех арендаторов. Многие разработчики полагают, что контейнеры — это идеально изолированные виртуальные машины, но реальность иная. В этой статье объясняются функции ядра Linux, лежащие в основе изоляции Docker (пространства имен, cgroups), и векторы атак, которые им угрожают. Вы узнаете практические шаги по усилению вашей настройки Docker: ограничение привилегий, использование безопасной среды выполнения, сканирование образов и сегментация сети. Следуя примеру поставщика многопользовательского хостинга WordPress из реального мира, вы увидите, как применять эти меры защиты. Мы также рассмотрим оговорки, такие как компромиссы в производительности и использование seccomp/AppArmor. Цель — предоставить вам надежную стратегию изоляции, которая предотвращает побеги из контейнеров и обеспечивает безопасность ваших арендаторов.

Введение

Если вы управляете многопользовательской хостинговой платформой — будь то общий хостинг WordPress, SaaS-приложение или служба сред разработки — побег из контейнера является сценарием кошмара. Уязвимость в ядре или неправильная конфигурация могут позволить одному арендатору вырваться из своего контейнера и получить доступ к данным других арендаторов или к самому хосту. Изоляция Docker полагается на функции ядра Linux, такие как пространства имен и cgroups, но стандартные конфигурации часто недостаточны для надежной безопасности. Эта статья проведет вас через векторы атак и предоставит действенные шаги для защиты ваших контейнеров Docker, проиллюстрированные примером многопользовательского хостинга WordPress из реального мира. Для более широкого обзора оркестрации в производственной среде см. наше руководство по Оркестрация готовых к производству контейнерных приложений.

Понимание изоляции Docker

Контейнеры Docker используют пространства имен Linux для обеспечения изоляции на уровне процессов: пространства имен PID изолируют деревья процессов, сетевые пространства имен разделяют сетевые интерфейсы, пространства имен монтирования изолируют точки монтирования файловой системы, а пространства имен пользователей позволяют сопоставлять корень контейнера с непривилегированным пользователем хоста. Группы управления (cgroups) ограничивают использование ресурсов, таких как ЦП, память и ввод-вывод диска. Эти функции вместе создают «песочницу» вокруг каждого контейнера. Однако, в отличие от виртуальной машины, которая запускает отдельное ядро, контейнеры используют общее хост-ядро. Это означает, что уязвимость в ядре (например, CVE-2022-0492) может быть использована для побега из изоляции пространства имен контейнера. Кроме того, неправильные конфигурации, такие как запуск контейнеров от имени root внутри контейнера, предоставление контейнеру всех возможностей или не отбрасывание ненужных возможностей Linux, могут расширить поверхность атаки.

Векторы атак

Общие векторы атак включают:

  • Эксплойты ядра: Использование ошибки в хост-ядре для получения доступа к хосту.
  • Привилегированные контейнеры: Запуск с --privileged предоставляет все возможности и обходит большинство мер изоляции.
  • Злоупотребление возможностями: Даже без полного привилегированного режима контейнер с опасными возможностями, такими как CAP_SYS_ADMIN или CAP_NET_ADMIN, может монтировать файловые системы или манипулировать сетевыми настройками.
  • Небезопасные практики работы с образами: Использование базовых образов с известными уязвимостями или включение ненужных инструментов, таких как компиляторы или интерпретаторы командной строки.
  • Общие пространства имен монтирования: Монтирование каталогов хоста в контейнеры может привести к побегу, если они не доступны только для чтения.

Практические шаги по обеспечению безопасности

1. Запуск контейнеров от имени непривилегированного пользователя

По умолчанию Docker запускает контейнеры от имени root внутри контейнера. Если злоумышленник получит root-доступ внутри контейнера, у него будет больше рычагов. Создайте пользователя в вашем Dockerfile и используйте директиву USER. Также избегайте использования флага --user в Docker Compose для сопоставления с произвольным пользователем хоста, если это возможно.

2. Отбросить все возможности и добавить только необходимые

Возможности Linux разбивают привилегии суперпользователя на более мелкие единицы. В Docker Compose используйте cap_drop: ALL, а затем cap_add только необходимые (например, NET_BIND_SERVICE). Избегайте опасных возможностей, таких как SYS_ADMIN, NET_ADMIN, SYS_PTRACE.

3. Использовать корневую файловую систему только для чтения

Установите read_only: true в определении вашего контейнера. Это предотвратит запись злоумышленниками в файловую систему контейнера. Если вашему приложению необходимо записывать временные файлы, смонтируйте том tmpfs в этом месте.

4. Включить переназначение пространств имен пользователей

Переназначение пространств имен пользователей сопоставляет пользователя root контейнера с непривилегированным пользователем хоста. Это добавляет уровень изоляции, поскольку даже если root контейнера совершит побег, он будет иметь привилегии переназначенного пользователя. Включите его в /etc/docker/daemon.json с помощью "userns-remap": "default". Имейте в виду, что это может усложнить права доступа к томам. Для получения более подробной информации см. Мастерство изоляции Docker для безопасного и эффективного веб-хостинга.

5. Применять профили Seccomp и AppArmor/AppArmor

Seccomp ограничивает системные вызовы, которые может выполнять контейнер. Docker предоставляет профиль seccomp по умолчанию, который блокирует опасные системные вызовы. Вы также можете создавать пользовательские профили. Аналогично, AppArmor (или SELinux) обеспечивает обязательный контроль доступа. Используйте AppArmor для ограничения вашего контейнера минимальным набором разрешенных операций. Профиль безопасности можно установить через security_opt в Docker Compose.

6. Использовать минимальные базовые образы и сканировать на наличие уязвимостей

Выбирайте небольшие образы, такие как Alpine или Distroless, которые имеют меньшую поверхность атаки. Регулярно сканируйте образы с помощью таких инструментов, как Docker Scout, Trivy или Clair. Интегрируйте сканирование в ваш конвейер CI/CD, чтобы предотвратить развертывание уязвимых образов.

7. Сегментация сети с помощью пользовательских мостовых сетей

Создавайте отдельные мостовые сети для каждого арендатора или уровня приложений. Это ограничивает трафик между ними (east-west). В Docker Compose определяйте сети и изолируйте службы. Используйте internal: true, если службе не нужен доступ в Интернет. Правила брандмауэра на хосте дополнительно ограничивают трафик между контейнерами.

8. Ограничение ресурсов с помощью Cgroups

Установите лимиты ЦП и памяти в Docker Compose, используя deploy.resources.limits. Это предотвращает запуск атаки исчерпания ресурсов скомпрометированным контейнером. Кроме того, установите kernel_memory и memory_reservation для более точного контроля.

Пример из реального мира: Многопользовательский хостинг WordPress с Docker Compose

Рассмотрим сценарий, когда вы размещаете несколько сайтов WordPress для разных клиентов, каждый в своем контейнере Docker. Небезопасная настройка может выглядеть так:

version: '3'
services:
  wordpress:
    image: wordpress:latest
    ports:
      - "8080:80"
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: exampleuser
      WORDPRESS_DB_PASSWORD: examplepass
      WORDPRESS_DB_NAME: exampledb
    volumes:
      - ./wp-content:/var/www/html/wp-content
  db:
    image: mysql:5.7
    environment:
      MYSQL_DATABASE: exampledb
      MYSQL_USER: exampleuser
      MYSQL_PASSWORD: examplepass
      MYSQL_ROOT_PASSWORD: somewordpress
    volumes:
      - db_data:/var/lib/mysql
volumes:
  db_data:

Эта настройка уязвима: контейнер WordPress запускается от имени root внутри, имеет все возможности (поскольку ни одна не отброшена), монтирует каталог хоста с доступом на запись и имеет неограниченный сетевой доступ.

Теперь давайте усилим ее:

version: '3'
services:
  wordpress:
    image: wordpress:latest
    user: www-data
    cap_drop:
      - ALL
    cap_add:
      - NET_BIND_SERVICE
    read_only: true
    tmpfs:
      - /var/www/html/wp-content/plugins
    security_opt:
      - seccomp=seccomp-profile.json
      - apparmor=wordpress-profile
    networks:
      - frontend
    ports:
      - "8080:80"
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: exampleuser
      WORDPRESS_DB_PASSWORD: examplepass
      WORDPRESS_DB_NAME: exampledb
    volumes:
      - wp-uploads:/var/www/html/wp-content/uploads
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 256M
  db:
    image: mysql:5.7
    user: mysql
    cap_drop:
      - ALL
    cap_add:
      - NET_BIND_SERVICE
    networks:
      - backend
    environment:
      MYSQL_DATABASE: exampledb
      MYSQL_USER: exampleuser
      MYSQL_PASSWORD: examplepass
      MYSQL_ROOT_PASSWORD: somewordpress
    volumes:
      - db_data:/var/lib/mysql
    deploy:
      resources:
        limits:
          cpus: '0.25'
          memory: 128M
networks:
  frontend:
    driver: bridge
    internal: false
  backend:
    driver: bridge
    internal: true
volumes:
  wp-uploads:
  db_data:

Ключевые улучшения:

  • Оба контейнера работают от имени непривилегированных пользователей (www-data и mysql).
  • Все возможности отброшены, добавлена только NET_BIND_SERVICE.
  • Файловая система WordPress доступна только для чтения, за исключением монтирования tmpfs и тома uploads.
  • Применяются профили Seccomp и AppArmor (вам потребуется предоставить пользовательские профили).
  • Раздельные сети изолируют веб от базы данных, при этом сеть базы данных является внутренней.
  • Лимиты ресурсов предотвращают исчерпание ресурсов.

Дополнительную информацию об усилении безопасности Docker для WordPress см. в статье Docker для WordPress: почему изолированные контейнеры меняют все.

Оговорки

  • Переназначение пространств имен пользователей: Хотя это и мощно, это нарушает монтирование томов, поскольку переназначенный UID хоста не совпадает с UID контейнера. Вам может потребоваться предварительно создать каталоги с правильными правами доступа или использовать тома Docker с поддержкой переназначения.
  • Профили Seccomp/AppArmor: Пользовательские профили требуют понимания шаблонов системных вызовов и доступа к файлам вашего приложения. Чрезмерно ограничительные профили могут нарушить функциональность. Тщательно тестируйте.
  • Производительность: Дополнительные уровни безопасности, такие как seccomp и AppArmor, имеют минимальные накладные расходы, но лимиты ресурсов и файловые системы только для чтения могут повлиять на приложения с интенсивной записью.
  • Сложность оркестрации: В многопользовательской среде управление файлами Docker Compose для каждого арендатора может стать громоздким. Рассмотрите возможность использования инструмента оркестрации более высокого уровня, такого как Kubernetes, но это вносит свои собственные соображения безопасности.

Заключение

Побег из контейнера — это реальная угроза в многопользовательском хостинге Docker, но ее можно предотвратить. Понимая механизмы изоляции и применяя многоуровневую защиту — отбрасывая возможности, запуская от имени непривилегированного пользователя, включая пространства имен пользователей, seccomp, AppArmor, сегментацию сети и регулярное сканирование образов — вы можете значительно снизить риск. Помните, что настройки Docker по умолчанию не готовы к производству для многопользовательских рабочих нагрузок. Внедрите эти шаги сегодня, чтобы защитить своих арендаторов и свою инфраструктуру. Для полного обзора лучших практик безопасности Docker обратитесь к Защита ваших веб-приложений с помощью Docker: практическое руководство по изоляции и лучшим практикам.

Sources (5)