1. Архитектура контейнеризации и анализ векторов атак на инфраструктуру
Архитектура контейнеризации и анализ векторов атак на инфраструктуру
Представьте, что вы строите многоквартирный дом, где вместо капитальных кирпичных стен между соседями установлены лишь тонкие гипсокартонные перегородки, а водопровод и вентиляция — общие и никак не изолированы. В мире информационных систем долгое время господствовала виртуализация (VM), предоставлявшая каждому «жильцу» полноценную изолированную крепость с собственным фундаментом (ядром ОС). Контейнеризация изменила правила игры, предложив коммунальный комфорт: общие ресурсы, общее ядро, но иллюзию полной приватности. Для специалиста по безопасности это означает, что любая трещина в «гипсокартоне» пространства имен или малейшая ошибка в настройке общих коммуникаций может привести к тому, что злоумышленник из одной квартиры мгновенно окажется в спальне у соседа или, что еще хуже, захватит управление всем зданием.
Контейнер как процесс: архитектурный сдвиг
Главное заблуждение, с которым приходится сталкиваться при аудите безопасности, — восприятие контейнера как «легковесной виртуальной машины». С точки зрения безопасности это опасная когнитивная ловушка. Виртуальная машина изолирована на уровне гипервизора, который эмулирует аппаратное обеспечение. Контейнер же — это всего лишь обычный процесс в операционной системе Linux, который «обманут» механизмами ядра так, что он считает себя изолированным.
Если мы выполним команду ps aux на хостовой машине, мы увидим процессы контейнеров точно так же, как процессы веб-браузера или текстового редактора. Разница лишь в том, что эти процессы запущены внутри специфических ограничителей. Архитектура Docker и Podman строится на трех столпах ядра Linux:
Понимание этой «процессной» природы критично. Если в VM злоумышленнику для захвата хоста нужно преодолеть барьер гипервизора (что случается крайне редко и требует сложнейших эксплойтов), то в контейнере он уже находится внутри ядра хоста. Его отделяет от свободы лишь программная конфигурация этих самых пространств имен и прав доступа.
Модель угроз: от Docker Daemon до рантайма
При анализе векторов атак на контейнерную инфраструктуру мы должны сегментировать среду на четыре ключевые зоны поражения. Каждая зона требует своего подхода к защите и мониторингу.
Зона 1: Цепочка поставок (Supply Chain)
Атака начинается задолго до запуска контейнера. Образ — это статический слепок файловой системы. Если разработчик использует в качестве базового образаnode:latest из публичного репозитория, он неявно доверяет сотням мейнтейнеров пакетов.
Векторы атаки здесь включают:
* Poisoning (Отравление образов): внедрение бэкдоров в популярные образы на Docker Hub.
* Typosquatting: создание образа с именем, похожим на популярное (например, alpinne вместо alpine), содержащего майнер криптовалюты.
* Секреты в слоях: оставленные в Dockerfile ключи SSH или API-токены. Даже если вы удалите файл в следующем слое, он останется в истории образа и может быть извлечен.Зона 2: Инфраструктура управления (The Orchestrator & Daemon)
Здесь кроется фундаментальное различие между Docker и Podman. Docker по умолчанию использует клиент-серверную архитектуру с центральным демоном (dockerd), работающим от имени root.
* Атака через сокет: если злоумышленник получает доступ к /var/run/docker.sock, он фактически получает права root на хосте. Команда docker run -v /:/host alpine позволяет смонтировать корень хостовой системы внутрь контейнера и изменить, например, /etc/shadow.
* API без аутентификации: Docker API, выставленный на сетевой порт без TLS, — это открытая дверь для массового заражения червями-шифровальщиками.Зона 3: Среда исполнения (Container Runtime)
Это момент, когда образ превращается в процесс. Основной риск здесь — Container Escape (побег из контейнера). * Злоупотребление Capabilities: выдача контейнеру избыточных привилегий (например,CAP_SYS_ADMIN) позволяет ему манипулировать монтированием файловых систем или загружать модули ядра.
* Уязвимости ядра: поскольку ядро общее, любая уязвимость в syscall (системном вызове), которую ядро не успело закрыть патчем, может быть использована для повышения привилегий до уровня хоста.Зона 4: Сетевое взаимодействие
Контейнеры часто общаются друг с другом через виртуальные мосты (bridge). По умолчанию в Docker все контейнеры в одной сети могут «видеть» друг друга. Без микросегментации взлом одного микросервиса (например, фронтенда) открывает прямой путь к базе данных через внутреннюю сеть, минуя внешние фаерволы.Глубокое погружение в Container Escape: пример с privileged-режимом
Одним из самых опасных флагов в Docker является --privileged. Профессорская этика требует разобрать этот случай детально, так как он наглядно демонстрирует хрупкость контейнерной изоляции. Когда вы запускаете контейнер с этим флагом, Docker отключает почти все механизмы защиты: не применяются профили AppArmor/Seccomp, передаются все Linux Capabilities, и, что самое важное, контейнеру открывается доступ ко всем устройствам хоста в /dev.
Рассмотрим механику атаки через release_agent. В старых версиях ядер и cgroups v1 это был классический способ побега:
--privileged.rdma или memory с хоста.release_agent записывается путь к скрипту внутри контейнера.Этот пример учит нас правилу: изоляция в контейнерах — это набор замков на одной двери. Если вы открыли один (дали CAP_SYS_ADMIN), остальные (Namespaces) могут не удержать грабителя.
Сравнение моделей безопасности: Docker vs Podman
Как специалисты по ИБ, мы должны оценивать не только удобство, но и архитектурную устойчивость. Здесь Podman предлагает радикально иной подход, основанный на принципе минимизации привилегий.
| Характеристика | Docker (традиционный) | Podman (Rootless) |
| :--- | :--- | :--- |
| Архитектура | Клиент-сервер (Daemon-based) | Fork/Exec (Daemonless) |
| Права процесса | Обычно root (демон всегда root) | Обычный пользователь (непривилегированный) |
| Точка отказа | Docker Daemon (взлом демона = взлом хоста) | Отсутствует центральный демон |
| Изоляция пользователей | Требует сложной настройки User Namespaces | User Namespaces включены по умолчанию |
| Аудит | Сложно отследить, кто запустил процесс (все от root) | Интеграция с auditd (виден реальный UID пользователя) |
В Docker, когда вы вводите команду, клиент общается с демоном через сокет. Демон порождает дочерний процесс. В системных логах владельцем процесса будет числиться root. В Podman процесс контейнера является прямым потомком процесса пользователя, запустившего его. Если пользователь ivan запускает контейнер, то и в htop на хосте мы увидим, что процесс принадлежит ivan. Это значительно упрощает расследование инцидентов и ограничивает радиус поражения: даже если злоумышленник «сбежит» из rootless-контейнера, он окажется на хосте с правами обычного пользователя ivan, а не суперпользователя.
Векторы атак через общие ресурсы ядра
Поскольку ядро — это общая библиотека функций для всех контейнеров, атаки на него являются наиболее разрушительными. Проблема в том, что поверхность атаки ядра огромна — более 300 системных вызовов.
Эксплуатация системных вызовов
Контейнер может попытаться вызвать функцию ядра, которая не была должным образом протестирована на предмет безопасности в контексте пространств имен. Классический пример — уязвимость Dirty COW (). Она позволяла непривилегированному пользователю (в том числе внутри контейнера) получить доступ на запись к read-only участкам памяти. Поскольку ядро общее, контейнер мог изменить системные файлы самого хоста, находящиеся в памяти.Атаки на файловую систему (Procfs и Sysfs)
Виртуальные файловые системы/proc и /sys — это окна в душу ядра. Если они смонтированы в контейнер неправильно (или в режиме read-write), контейнер может изменить параметры работы железа хоста или прервать работу других контейнеров. Например, доступ к /proc/sysrq-trigger позволяет удаленно перезагрузить хост или вызвать kernel panic простым echo.Методология анализа по CIS Benchmark и OWASP
Для проведения качественного аудита мы не можем полагаться на интуицию. Нам нужны стандарты.
Практический аспект: Аудит цепочки Build
При аудите Dockerfile мы ищем нарушения "гигиены": * Использованиеsudo внутри контейнера.
* Отсутствие инструкции USER. По умолчанию контейнер запускается от root. Хорошая практика — создать системного пользователя с минимальными правами:* Установка лишних пакетов (курл, гит, компиляторы). В идеале в образе должен быть только бинарный файл приложения и его зависимости. Образы на базе Alpine хороши своей компактностью, но и они могут быть избыточны. Для Go-приложений стандартом де-факто является использование scratch — абсолютно пустого образа.
Сетевая безопасность: иллюзия изоляции
Многие полагают, что если контейнер не пробросил порты наружу (-p), он недоступен. Это не так. Внутри Docker-хоста существует внутренняя сеть. Злоумышленник, захвативший один контейнер, может использовать его как плацдарм для сканирования внутренней сети (nmap по диапазону 172.17.0.0/16).
Проблема усугубляется использованием host networking (--network host). В этом режиме контейнер вообще не получает своего сетевого пространства имен и использует сетевой стек хоста. Это дает ему возможность прослушивать трафик других интерфейсов хоста, менять таблицу маршрутизации и обходить локальные фаерволы, которые часто доверяют трафику с localhost.
Управление секретами: где мы ошибаемся
Одной из самых частых находок при аудите является передача паролей и API-ключей через переменные окружения (ENV в Dockerfile или -e в рантайме).
Почему это плохо?
docker inspect.Правильный путь — использование механизмов Docker Secrets (в режиме Swarm) или монтирование секретов в tmpfs (память), чтобы они никогда не касались диска и не оставались в истории слоев образа.
Резюмируя архитектурные риски
Безопасность контейнеров — это не продукт, который можно купить, а процесс настройки ограничений. Мы должны исходить из принципа Zero Trust внутри хоста. Контейнер должен:
* Работать от не-root пользователя.
* Иметь файловую систему только для чтения (--read-only).
* Иметь жестко ограниченные ресурсы (cgroups), чтобы предотвратить DoS-атаки на соседей.
* Общаться только с теми сервисами, которые ему необходимы для работы (сетевая сегментация).
В следующих главах мы детально разберем, как именно настраивать эти механизмы «под капотом» ядра, переходя от теории векторов атак к практике глубокой защиты. Помните: в мире контейнеров ваша главная защита — это не стены, а правильно настроенные фильтры системных вызовов и строгая дисциплина при сборке образов.