Стандартная изоляция Docker обеспечивает лишь базовый уровень безопасности. Рассказываем, как использовать встроенный в ядро Linux механизм AppArmor для защиты контейнеров, хостовой системы и VPS.
Введение
Стандартная изоляция Docker-контейнеров, основанная на пространствах имён (namespaces) и группах управления (cgroups), обеспечивает лишь базовый уровень безопасности. Она не предотвращает попытки процессов внутри контейнера получить несанкционированный доступ к ресурсам хостовой системы: файлам, сетевым интерфейсам или системным вызовам. Злоумышленник, эксплуатируя уязвимость в приложении или неправильно настроенном образе, может инициировать атаку на хост-машину, например, чтение чувствительных файлов (таких как /etc/shadow), несанкционированный доступ к Docker-сокету или попытку выполнения привилегированных операций.
AppArmor (Application Armor) решает эти проблемы, контролируя доступ на уровне приложений. Его механизм безопасности, интегрированный непосредственно в ядро Linux, позволяет создавать профили с детальными правилами для каждого процесса. Для Docker это означает возможность точечно ограничивать действия контейнера: запрещать запись в определенные директории, ограничивать сетевые соединения, блокировать опасные системные вызовы или доступ к устройствам.
Рассказываем, как создавать, настраивать и применять кастомные профили AppArmor для Docker-контейнеров, все инструкции приведены для Ubuntu 24.04.
Принципы работы AppArmor
AppArmor работает на основе профилей — наборов правил, которые определяют разрешённые и запрещённые операции для конкретного приложения или процесса. Каждый профиль действует по принципу «всё, что явно не разрешено — запрещено». Правила профиля контролируют доступ к нескольким ключевым ресурсам:
- доступ к файловой системе — указываются конкретные пути с указанием прав доступа (чтение, запись, выполнение, создание ссылок);
- сетевые операции — регулируются по протоколам (tcp, udp, raw) и типам операций (bind, listen, accept);
- системные вызовы и возможности — ограничивают использование опасных привилегий.
Процесс работы AppArmor состоит из нескольких этапов. При запуске приложения загружается соответствующий профиль; ядро перехватывает системные вызовы процесса и сверяет их с правилами профиля; при нарушении правил действие блокируется, а запись о нарушении попадает в системные логи.
Основные команды для работы с AppArm.
- Проверка статуса службы:
sudo systemctl status apparmor
И статуса профилей:
sudo aa-status
- Принудительная перезагрузка конкретного профиля после внесения изменений:
sudo apparmor_parser -r /etc/apparmor.d/имя_профиля
- Просмотр логов нарушений:
sudo journalctl -k -f -g apparmor
Стандартный профиль Docker в AppArmor
AppArmor предустановлен в Ubuntu 24.04 и активен по умолчанию. При запуске контейнера Docker автоматически генерирует профиль docker-default в tmpfs и загружает его в ядро. Стандартный профиль применяется для всех запущенных контейнеров, если его не переопределить при запуске параметром --security-opt apparmor=имя_профиля:
docker run --security-opt apparmor=my-app app
Ключевые правила стандартного профиля Docker:
- блокировка записи в критичные системные директории: deny /etc/** wl,
- ограничение доступа к ядерным структурам: deny /proc/sysrq-trigger rwklx,
- контроль монтирования файловых систем: deny mount,
- ограничение сетевых возможностей: network bridge.
Регулярно просматривайте логи, чтобы проверять эффективность работы профиля:
sudo tail -f /var/log/syslog | grep apparmor
Для большинства сценариев стандартного профиля достаточно, но для критически важных приложений рекомендуется создавать кастомные профили с более детальными правилами доступа.
Создание кастомного профиля для контейнера
Для создания специализированных профилей AppArmor, обеспечивающих точечный контроль доступа для конкретного контейнера, используется утилита aa-genprof. Этот инструмент анализирует деятельность процесса и генерирует базовый профиль на основе его поведения. Однако aa-genprof предназначена для профилирования процессов, запущенных напрямую на хосте. Она не может корректно отследить действия процесса, изолированного внутри контейнера (с его собственной файловой системой, пространством имён и т. д.). Её использование для контейнеров даст неполный и скорее всего бесполезный профиль. Новый профиль для контейнеров можно создать на основе шаблона docker-default, его нужно разместить в /etc/apparmor.d или вложенном каталоге.
Пример кастомного профиля:
#include <tunables/global>
# Профиль для контейнера my-app
# flags: attach_disconnected, mediate_deleted — рекомендуемые опции
profile my-app flags=(attach_disconnected,mediate_deleted) {
#
# Базовые правила и абстракции
#
# abstractions/base — минимальный набор разрешений для системных вызовов
# abstractions/nameservice — доступ к DNS и базовым сетевым функциям
#
# Эти include-файлы идут в стандартной поставке AppArmor (Ubuntu/Debian).
#
# См. каталог /etc/apparmor.d/abstractions/
#
# Их можно подрезать, если нужно ещё жестче ограничить контейнер
#
# -----------------------------------------------------------
# Базовые include'ы
# -----------------------------------------------------------
# Подключение общих правил
# -----------------------------------------------------------
#include <abstractions/base>
#include <abstractions/nameservice>
#
# Ограничение возможностей ядра (capabilities)
#
# sys_admin — самая опасная возможность, фактически root
# sys_module — загрузка/выгрузка модулей ядра
# sys_ptrace — отладка/трассировка чужих процессов
#
deny capability sys_admin,
deny capability sys_module,
deny capability sys_ptrace,
#
# Запрет доступа к критическим файлам и системным структурам
#
deny /etc/shadow rw,
deny /etc/sudoers rw,
deny /proc/*/mem r,
deny /sys/kernel/security/** rw,
deny mount,
#
# Сетевые правила
#
# inet stream — разрешаем TCP (IPv4)
# inet dgram — разрешаем UDP (IPv4)
# raw — запрет на низкоуровневый доступ к пакетам
# inet6 — полный запрет IPv6 (можно убрать, если нужен)
#
network inet stream,
network inet dgram,
deny network raw,
deny network inet6,
#
# Работа с временными каталогами
#
# Разрешаем запись в /tmp и /var/tmp
# Но запрещаем запуск исполняемых файлов из /tmp — частый вектор атак
#
/tmp/** rw,
deny /tmp/** x,
/var/tmp/** rw,
/run/** rw,
#
# Доступ к базовым устройствам
#
/dev/null rw,
/dev/zero r,
/dev/urandom r,
#
# Доступ к бинарям
#
# mr = m(emap) + r(read) — достаточно для исполнения
# ix можно использовать для жёсткой изоляции исполнения только под этим профилем
#
/usr/bin/** mr,
/bin/** mr,
#
# Межпроцессные взаимодействия
#
# ptrace — блокируем трассировку процессов
# signal — блокируем отправку сигналов другим процессам
#
deny ptrace,
deny signal,
}
После создания профиля загрузите его в ядро:
sudo apparmor_parser -r /etc/apparmor.d/my-app
Переведите профиль в режим обучения (complain) и начните отладку:
sudo aa-complain /etc/apparmor.d/my-app
Запустите контейнер с новым профилем и отработайте все его типичные сценарии.
docker run --security-opt apparmor=my-app --rm -it your-application
Проанализируйте логи и добавьте недостающие правила с помощью aa-logprof:
sudo aa-logprof
Эта утилита проанализирует логи AppArmor и предложит добавить правила для разрешённых, но незадекларированных действий.
Переведите профиль в режим ограничений:
sudo aa-enforce /etc/apparmor.d/my-app
Валидация работы профиля через проверку логов:
sudo journalctl -k -f | grep apparmor
Обязательно обновляйте профили при изменении функционала контейнеров.
Продвинутая настройка AppArmor
Для создания высокоспециализированных профилей безопасности используйте расширенные возможности синтаксиса AppArmor.
Ограничение системных вызовов
Профиль может ограничивать использование конкретных возможностей ядра Linux:
deny capability sys_module, # запрет загрузки модулей ядра
deny capability sys_ptrace, # блокировка отладки других процессов
deny capability sys_time, # запрет изменения системного времени
deny capability sys_nice, # запрет изменения приоритета процессов
deny capability sys_rawio, # запрет низкоуровневого доступа к устройствам
Детальный контроль сетевого доступа
Сетевые правила позволяют фильтровать трафик по протоколам и типам операций:
network inet stream, # разрешить только IPv4 TCP
network inet dgram, # разрешить IPv4 UDP
deny network inet6, # полный запрет IPv6
deny network netlink, # блокировка Netlink сокетов
deny network packet, # запрет raw packet access
Расширенное управление файловыми системами
Настройка доступа к файлам и директориям:
# Блокировка доступа к устройствам
deny /dev/sd* rw, # запрет доступа к блочным устройствам
deny /dev/ttyS* rw, # блокировка последовательных портов
deny /dev/mem rw, # запрет прямого доступа к памяти
# Контроль временных файлов
/tmp/** rw, # разрешить запись в /tmp
/var/tmp/** rw, # разрешить запись в /var/tmp
deny /tmp/**x, # запрет выполнения из /tmp
# Системные файлы
deny /etc/passwd w, # запрет записи в passwd
deny /etc/ssh/** rw, # блокировка доступа к SSH-ключам
Управление процессами и сигналами
Контроль взаимодействия между процессами:
deny signal, # запрет отправки сигналов другим процессам
deny ptrace, # блокировка трассировки процессов
Использование условных правил
Динамические правила на основе атрибутов процесса:
# Разрешение записи только для определенных владельцев
owner /var/log/nginx/* rw,
owner /var/cache/nginx/** rw,
# Ограничение на основе пути исполняемого файла
/usr/bin/nginx {
/var/lib/nginx/** rw,
network inet stream,
}
Аудит и мониторинг
Включение детального логирования для анализа:
audit /etc/** r, # логирование всех чтений из /etc
audit deny /root/** r, # логирование попыток доступа к /root
Пример комбинации правил
Профиль для веб-сервера nginx:
#include <tunables/global>
profile nginx-container {
#include <abstractions/base>
#include <abstractions/nameservice>
deny capability sys_module,
deny capability dac_override,
network inet stream,
network inet dgram,
deny network inet6,
/usr/sbin/nginx mr,
/var/log/nginx/** rw,
/var/cache/nginx/** rw,
/run/nginx.pid rw,
deny /etc/shadow r,
deny /root/** r,
}
Для применения изменений в профиле используйте команду:
sudo apparmor_parser -r /etc/apparmor.d/containers/nginx-container
Проверка работы правил:
sudo journalctl -k -f -g apparmor | grep -E "(DENIED|ALLOWED)"
Эти продвинутые техники позволяют создавать высокоточные профили безопасности, адаптированные под конкретные требования приложений и значительно повышающие уровень защиты контейнерных сред.
Интеграция AppArmor с Docker
Применение профиля через аргументы запуска контейнера
Чтобы использовать кастомный профиль AppArmor, при запуске контейнера укажите его имя в параметре --security-opt:
docker run -d --name nginx-container \
--security-opt "apparmor=my-app" \
-p 80:80 \
nginx:latest
Применённый профиль проверяйте командой inspect:
docker inspect nginx-container --format '{{ .HostConfig.SecurityOpt }}'
Использование профилей в Docker Compose
Для применения профилей AppArmor в docker-compose добавьте соответствующие параметры в определение сервиса:
version: '3.8'
services:
web:
image: nginx:latest
security_opt:
- apparmor=my-app
ports:
- "80:80"
Управление профилями через скрипты
Создайте скрипт обслуживания, чтобы автоматизировать обновление профилей:
#!/bin/bash
# /usr/local/bin/reload-apparmor-profiles.sh
PROFILES_DIR="/etc/apparmor.d/containers/"
for profile in "$PROFILES_DIR"*; do
if [ -f "$profile" ]; then
sudo apparmor_parser -r "$profile"
echo "Reloaded profile: $(basename "$profile")"
fi
done
Сделайте скрипт исполняемым и добавьте в crontab для регулярного обновления:
sudo chmod +x /usr/local/bin/reload-apparmor-profiles.sh
sudo crontab -l | { cat; echo "0 3 * * * /usr/local/bin/reload-apparmor-profiles.sh"; } | sudo crontab -
Заключение
AppArmor остаётся одним из самых надёжных инструментов повышения безопасности контейнеров в Linux. Его главное преимущество — детальная изоляция процессов, которая дополняет стандартные механизмы Docker и позволяет закрыть критические уязвимости на уровне ядра. Создание и настройка кастомных профилей требует времени, но в итоге вы получаете гибкий и управляемый инструмент, который защищает хостовую систему от атак, снижает риск компрометации и даёт полный контроль над поведением контейнеров.
Для продакшн-среды оптимальным решением будет комбинация: использование стандартного профиля docker-default для обычных сервисов и кастомных профилей для критичных приложений. Регулярный аудит логов, обновление правил и автоматизация загрузки профилей через скрипты помогут поддерживать защиту на актуальном уровне.
В условиях, когда контейнерные окружения становятся мишенью для атак так же часто, как и классические серверы, интеграция AppArmor в вашу Docker-инфраструктуру — это не дополнительная опция, а обязательный элемент стратегии безопасности.
Читайте в блоге:
- Настройка заданий cron и systemd-таймеров для автоматизации рутинных задач на Ubuntu 24.04
- Основы работы с nftables на Ubuntu 24.04
- Как генерировать надёжные пароли на Ubuntu 24.04