Безопасность серверов

AppArmor на сервере: профили, enforce и диагностика отказов

Как проверить AppArmor в Ubuntu и Debian, создать профиль для серверного приложения, перевести его из complain в enforce и разобрать denied-события.

12 минут
абстрактная иллюстрация профилей защиты серверных приложений
Для безопасной настройки AppArmor сначала определите исполняемый файл сервиса и проверьте готовый профиль от пакета или поставщика. Новый либо доработанный профиль загрузите в режиме complain, соберите события о реальной работе приложения, оставьте только необходимые разрешения и затем переведите именно этот профиль в enforce. Отказы разбирают по профилю, процессу, операции и ресурсу; отключение AppArmor целиком не является штатным исправлением.

Что AppArmor проверяет помимо прав Linux

AppArmor — реализация мандатного контроля доступа через каркас Linux Security Modules. Он работает вместе с обычным дискреционным контролем доступа, а не вместо него: процесс должен пройти обе проверки. Поэтому корректные владельцы файла, ACL и режим chmod не гарантируют доступ, если профиль AppArmor его не разрешает.

Профиль AppArmor обычно привязан к пути исполняемого файла и задаёт, что процесс вправе читать, записывать, отображать в память и выполнять, какие capabilities использовать и какие сетевые операции совершать. Детализация сетевых ограничений зависит от версии AppArmor, ABI политики и типа сокета: базовые правила могут различать только семейство, тип и протокол, а не конкретный удалённый адрес или порт. Это путевой контроль доступа: при изменении пути бинарного файла, запуске через другую программу-обёртку или появлении дочерней программы профиль может перестать соответствовать фактическому поведению.

Правила строят по принципу наименьших привилегий: не «разрешить /var/**», а разрешить конкретному сервису его каталог данных, конфигурацию, сокет и требуемые исполняемые файлы. AppArmor — один слой hardening; место MAC в общей базовой конфигурации разобрано в статье «Базовая защита сервера: как составить security baseline».

Проверьте AppArmor status и режим нужного профиля

В типичных Ubuntu и Debian пакет apparmor предоставляет загрузчик политики apparmor_parser и утилиту проверки состояния aa-status, а пакет apparmor-utils — aa-complain, aa-enforce, aa-disable, aa-genprof и aa-logprof. Состав пакетов, имя systemd-службы, расположение журналов и доступные ключи зависят от выпуска ОС и версии AppArmor userspace. Перед изменениями сверяйте синтаксис с руководством AppArmor и документацией своего дистрибутива; ниже приведён обычный сценарий для Ubuntu и Debian.

Показывает, включён ли AppArmor, сколько профилей загружено, какие из них находятся в enforce или complain, а также сведения о процессах под профилями.
sudo aa-status
Вывод:
Ожидаемый результат — сообщение о том, что AppArmor загружен, и списки профилей в enforce и complain. Если команда не найдена, проверьте пакет `apparmor` и документацию своего выпуска; если AppArmor не загружен, выясните состояние пакета, ядра, параметров загрузки и политики ОС.
Проверяет службу, которая обычно загружает профили из каталога политики при старте системы.
sudo systemctl status apparmor
Вывод:
На systemd-системе ожидается активная служба без ошибок разбора профилей. Отсутствие этого unit не всегда означает отсутствие AppArmor: ориентируйтесь прежде всего на `aa-status` и документацию конкретного выпуска.
Найдите в выводе точное имя профиля или путь attachment, относящийся к нужному приложению.
sudo aa-status | less
Вывод:
Если профиль есть в списке enforce — не создавайте второй профиль с тем же attachment. Сначала изучите существующий файл и способ его локального расширения.

Режим профиля, а не режим сервера

Режим complain и режим enforce AppArmor устанавливаются для отдельных профилей. Один сервис можно профилировать в complain, пока остальные профили сервера продолжают работать в enforce.

Поведение отдельных возможностей зависит от версии ядра, AppArmor userspace и политики дистрибутива.

СостояниеПоведение неразрешённой операцииПрактическое назначение
enforceОперация запрещается и обычно фиксируется в журнале как отказ.Штатная защита работающего сервиса.
complainОперация, не разрешённая обычными разрешающими правилами, обычно журналируется, но не блокируется; явные правила deny продолжают применяться.Сбор фактических потребностей приложения перед включением enforce.
unconfinedПроцесс не ограничен профилем AppArmor.Обычное состояние процесса, для которого профиль не прикреплён. Если ранее действовавший профиль снят ради диагностики, процесс временно теряет этот слой защиты.

Complain не означает «ничего не блокируется»

Явные правила deny продолжают применяться и в complain. Также отказ может исходить от обычных прав Linux, ACL, файловой системы, seccomp или другого механизма. Поэтому complain не гарантирует работоспособность приложения и не отменяет проверку после изменения.

Найдите исполняемый файл и существующую политику

Инвентаризация сервиса перед созданием профиля

Сквозной пример использует условное приложение reportd с бинарным файлом /opt/acme/bin/reportd. Это не готовый профиль для Nginx, СУБД или другого реального продукта.

  1. 1
    Зафиксируйте команду запуска службы
    Просмотрите unit и drop-in-файлы: systemctl cat reportd. Найдите ExecStart=, аргументы, пользователя, рабочий каталог, файлы конфигурации, каталоги данных, сокеты и дочерние команды. Если сервис запускается не через systemd, найдите его командную строку и механизм запуска.
  2. 2
    Подтвердите фактический бинарный файл запущенного процесса
    Получите PID через systemctl show -p MainPID --value reportd, затем выполните readlink -f /proc/<PID>/exe. Этот путь важнее предположений по имени службы: profile attachment обычно соответствует исполняемому файлу после разрешения символьных ссылок.
  3. 3
    Проверьте профиль от пакета или поставщика
    Ищите путь и имя приложения в /etc/apparmor.d: sudo grep -R --line-number --fixed-strings '/opt/acme/bin/reportd' /etc/apparmor.d. Для пакетного бинарного файла проверьте владельца через dpkg -S /путь/к/файлу. Найденный профиль сначала прочитайте вместе с его #include: пакет мог предусмотреть локальный файл для дополнений.
  4. 4
    Соберите ожидаемое поведение
    До генерации правил составьте короткий список: какие конфигурации сервис читает, куда пишет данные и временные файлы, какие Unix-сокеты или TCP/UDP-соединения открывает, какие helper-программы запускает, нужны ли capabilities. Отдельно отметьте действия, которых сервис делать не должен.
Ищет профиль или включаемый фрагмент, уже ссылающийся на бинарный файл из примера.
sudo grep -R --line-number --fixed-strings '/opt/acme/bin/reportd' /etc/apparmor.d
Вывод:
Нет вывода — возможный признак отсутствия готового профиля, но не доказательство: attachment может быть задан иначе или профиль может быть сгенерирован и загружен из другого места. Сопоставьте результат с `aa-status`.

В Ubuntu и Debian поставляемые профили обычно размещаются в /etc/apparmor.d, а отключённые профили отмечаются механизмом disable в этом дереве. Пакетное обновление может заменить основной файл профиля. Если поставляемый профиль поддерживает локальное включение, сохраняйте свои дополнения в предусмотренном локальном include-файле, часто в /etc/apparmor.d/local/…; это снижает риск перезаписи. Не создавайте второй независимый файл с тем же attachment: конфликтующие определения затрудняют сопровождение.

Создайте начальный профиль AppArmor

Есть два безопасных старта: создать минимальный профиль вручную на основе инвентаризации или использовать интерактивный aa-genprof для сбора событий. Утилита не понимает назначение приложения и не может сама отличить необходимый доступ от опасного, поэтому её предложения всегда проверяют.

Запускает штатный интерактивный сценарий подготовки профиля для указанной программы. В типичной установке утилита переводит профиль в complain на время сбора событий, предлагает воспроизвести работу приложения и затем разобрать журнал.
sudo aa-genprof /opt/acme/bin/reportd
Вывод:
После завершения проверьте созданный файл политики и фактический режим через `aa-status`: некоторые версии и сценарии завершения `aa-genprof` загружают готовый профиль в enforce. Если сбор и функциональная проверка ещё не закончены, до продолжения работы явно переведите этот профиль в complain и снова проверьте режим. Если `aa-genprof` отсутствует, найдите пакет `apparmor-utils` для своего выпуска либо создайте профиль вручную.
/etc/apparmor.d/opt.acme.bin.reportd
#include <tunables/global>

/opt/acme/bin/reportd flags=(complain) {
  #include <abstractions/base>

  /opt/acme/bin/reportd mr,
  /etc/reportd/config.yaml r,
  /var/lib/reportd/ r,
  /var/lib/reportd/** rw,
  /run/reportd/ r,
  /run/reportd/reportd.sock rw,

  capability net_bind_service,
  network inet stream,
}

Это учебный каркас, а не универсальная политика. Правило r разрешает чтение, w — запись, а m — исполняемое отображение файла в память, например через mmap с PROT_EXEC; завершающая запятая обязательна. /** охватывает дерево каталогов и допустим здесь только как осознанная граница каталога данных конкретного приложения. Правила capability и network добавляйте лишь после подтверждения необходимости. Абстракция AppArmor abstractions/base содержит общий базовый набор доступа к системным ресурсам, но не обязательно минимальный для конкретного сервиса. Перед включением abstractions прочитайте их содержимое и проверьте, какие разрешения они добавляют.

Проверяет синтаксис и заменяет в ядре профиль из указанного файла. Ключ `-r` означает replace загруженного профиля.
sudo apparmor_parser -r /etc/apparmor.d/opt.acme.bin.reportd
Вывод:
При успехе команда обычно не печатает сообщений. При ошибке не перезапускайте критичную службу: исправьте строку и номер, выданные parser, затем повторите загрузку. После успешной загрузки проверьте профиль через `aa-status`.

Как сохранить изменение после перезагрузки

Однократная загрузка через apparmor_parser меняет активную политику ядра, но не заменяет файл политики. Сохраните профиль в каталоге, который обрабатывает AppArmor при запуске ОС, и проверьте это после плановой перезагрузки или в тестовой среде. Правила размещения, локальных include и отключённых файлов различаются между выпусками и пакетами; для пакетного приложения предпочтительнее документированная схема поставщика.

Соберите события в complain и переведите профиль в enforce

Безопасный переход одного профиля в enforce

Работы выполняйте в окне изменений. Для удалённого сервера оставьте вторую административную сессию и проверенный путь аварийного доступа; особенно если профиль относится к SSH, сетевому агенту или критичному приложению.

  1. 1
    Переведите только нужный профиль в complain
    В типичной установке используйте sudo aa-complain /opt/acme/bin/reportd, затем подтвердите режим через sudo aa-status. Передавайте путь attachment либо имя профиля в форме, которую принимает ваша версия утилиты. Остальные профили эта команда не меняет.
  2. 2
    Воспроизведите штатные сценарии
    Перезапустите reportd, выполните его обычные запросы, фоновые задания, ротацию, работу с данными и штатное завершение. Не ограничивайтесь запуском процесса: многие зависимости проявляются только при обработке трафика, таймере или обновлении конфигурации.
  3. 3
    Разберите журнал и уточните правила
    Для каждого события установите профиль, comm, PID, операцию, запрошенный путь или иной ресурс. Разрешайте действие только если оно ожидаемо для назначения сервиса. После изменения файла перезагрузите его apparmor_parser -r и повторите сценарий.
  4. 4
    Включите enforce для одного профиля
    Выполните sudo aa-enforce /opt/acme/bin/reportd и снова проверьте aa-status. После этого перезапустите или штатно переподключите сервис, если это требуется для применения profile attachment при новом exec, и пройдите функциональную проверку.
  5. 5
    Проверьте сервис и откат
    Проверьте статус службы, её health-check и журнал AppArmor. Если новый enforce-отказ влияет на критичную функцию, временно верните только этот профиль в complain командой aa-complain, зафиксируйте событие и продолжите разбор. Не выключайте AppArmor для всего хоста.
Переключает профиль, связанный с указанным путем, в enforce в типичной конфигурации `apparmor-utils`.
sudo aa-enforce /opt/acme/bin/reportd
Вывод:
Ожидаемый результат — нужный профиль отображается в секции enforce вывода `aa-status`. Если путь не распознан, найдите точное имя профиля в `aa-status` и сверьте форму аргумента с `aa-enforce --help` и документацией установленной версии.

Где искать AppArmor denied и как читать событие

AppArmor формирует сообщения ядра, которые в зависимости от конфигурации могут попадать в systemd-journald, журнал ядра, /var/log/kern.log, /var/log/syslog или в подсистему аудита. При включённом auditd часть записей доступна в audit-журнале. Не предполагайте один источник: начните с journal, затем проверьте файловые и audit-журналы, принятые на конкретном сервере.

Ищет недавние отказы AppArmor среди сообщений ядра в systemd journal.
sudo journalctl -k --since '30 min ago' | grep 'apparmor="DENIED"'
Вывод:
Если записи найдены, сохраните полную строку, а не только путь. Если вывода нет, проверьте `/var/log/kern.log`, `/var/log/syslog` и при наличии auditd — `sudo ausearch -m AVC -ts recent`.
apparmor="DENIED" operation="open" profile="/opt/acme/bin/reportd" name="/etc/reportd/secret.key" pid=2418 comm="reportd" requested_mask="r" denied_mask="r"

Состав полей зависит от типа операции, ядра и настроек аудита.

ПолеЧто установить
profileКакой профиль ограничил процесс. Это ключ к нужному файлу политики.
comm, pidИмя процесса и его идентификатор; помогают связать событие с unit, дочерним процессом или конкретным запуском.
operationТип операции: например open, exec, file_mmap, capability или операция с сетью.
nameПуть к объекту там, где он применим. Для capability и части сетевых операций пути может не быть.
requested_mask и denied_maskКакой доступ запрашивался и какая часть была отклонена: чтение, запись, выполнение и другие права.
Открывает интерактивный разбор найденных событий AppArmor и предлагает варианты правил.
sudo aa-logprof
Вывод:
Используйте предложения как черновик. До подтверждения проверьте профиль, операцию, путь и назначение действия; не принимайте автоматически широкие шаблоны или разрешения на запуск программ.

Как исправлять denied без широких разрешений

  1. Сопоставьте profile, comm и PID с конкретной службой. Отказ от reportd-helper может относиться к дочернему процессу, а не к основному бинарному файлу.
  2. Определите запрошенную операцию и объект. Для файлового доступа проверьте реальный путь, символьные ссылки, владельца и обычные права Linux; для capability или сети — реальную функцию приложения.
  3. Решите, ожидаемо ли действие. Чтение конфигурации из предусмотренного каталога обычно может быть легитимным; попытка читать чужой закрытый ключ, выполнять shell или писать в неожиданный каталог — повод менять приложение либо считать действие нежелательным.
  4. Выберите самое узкое исправление: конкретное файловое правило, уже проверенную abstraction, отдельное правило выполнения или исправление конфигурации приложения, чтобы оно использовало собственный каталог.
  5. Перезагрузите изменённый профиль, воспроизведите сценарий и убедитесь, что разрешена только нужная операция. Зафиксируйте причину правила и зависимость, которая его требует.

Проблема

После включения enforce сервис не запускается или теряет функцию

Возможные причины

  • В профиле нет узкого правила для ожидаемого файла, каталога, выполнения helper-программы, capability или сетевой операции.
  • Сервис использует другой путь после обновления, символьной ссылки, смены рабочего каталога или запуска дочернего процесса.
  • Отказ связан не с AppArmor, а с DAC-правами, ACL или другой политикой.

Решение

Сначала извлеките полную запись denied и свяжите её с процессом. Если действие нужно, добавьте минимальное правило либо исправьте конфигурацию сервиса. Если функция критична и время разбора ограничено, временно переведите только этот профиль в complain, а затем повторите проверку и верните enforce.

Как избежать

Проверяйте профиль в complain на реальных сценариях: запуск, обработка запросов, запись данных, ротация, фоновые задания и штатное завершение.

Не лечите каждый denied строкой allow

Автоматическое принятие всех предложений aa-logprof, разрешения вида /** rw,, ux для произвольного запуска и массовые abstractions могут превратить профиль в формальность. Если приложению нужен доступ к неожиданному пути, сначала проверьте ошибку конфигурации, утечку пути из окружения или неучтённую зависимость.

Временное отключение одного профиля и возврат защиты

Для диагностики допустимо кратко отключить конкретный профиль, но это снимает с процесса слой MAC-защиты. В типичных apparmor-utils команда aa-disable одновременно выгружает профиль из ядра и создаёт отметку отключения, чтобы штатная загрузка профилей не включила его снова при следующем запуске службы AppArmor или перезагрузке. Простая выгрузка через apparmor_parser -R удаляет активный профиль, но сама по себе не обязана предотвращать его последующую загрузку из файла политики.

В типичной Ubuntu/Debian-конфигурации выгружает указанный профиль и через механизм `disable` предотвращает его штатную последующую загрузку.
sudo aa-disable /etc/apparmor.d/opt.acme.bin.reportd
Вывод:
Сразу проверьте результат через `aa-status`: профиль не должен оставаться среди загруженных. После выгрузки уже работающие процессы, которые были ограничены этим профилем, теряют его защиту. Когда профиль будет включён снова, одной загрузки политики недостаточно для повторного прикрепления к такому процессу: выполните контролируемый перезапуск приложения или другой новый exec. Расположение disable-маркера и принимаемую форму аргумента сверяйте с документацией установленной версии.
Обычный способ снова включить отключённый профиль и загрузить его в enforce в версиях, где `aa-enforce` управляет disable-маркером.
sudo aa-enforce /etc/apparmor.d/opt.acme.bin.reportd
Вывод:
Подтвердите возвращение профиля через `aa-status`, затем перезапустите приложение в контролируемом окне и повторите функциональную проверку. Перезапуск важен для надёжной проверки нового запуска под profile attachment; не полагайтесь только на статус загрузки политики.

Не отключайте AppArmor на всём сервере ради одного сбоя

Глобальное отключение снимает ограничения со всех защищённых сервисов и усложняет оценку последствий. Если временное отключение одного профиля действительно необходимо, ограничьте время, запишите причину, сохраните исходный профиль и заранее назначьте момент возврата в complain или enforce.

Выбор между AppArmor и SELinux, а не настройка конкретного профиля, рассмотрен в статье «SELinux или AppArmor: какую систему мандатного контроля доступа выбрать». Общую последовательность усиления Ubuntu и Debian смотрите в чек-листе hardening Linux; сбор и хранение событий вне одного хоста — отдельная задача из статьи «Централизованный сбор журналов безопасности».

Термины в статье

AppArmor — система мандатного контроля доступа Linux, ограничивающая программы профилями; профиль обычно выбирается по пути исполняемого файла, а файловые правила сопоставляются с путями.
Hardening — процесс усиления защищённости системы через отключение лишних функций, ограничение доступа и настройку безопасных параметров для снижения доступной поверхности атаки.
Linux Security Modules — каркас ядра Linux для подключения модулей контроля доступа, перехватывающих операции с объектами системы по заданным политикам.
Абстракция AppArmor — подключаемый набор повторно используемых правил профиля, описывающий типовой доступ приложения к файлам и системным ресурсам.
Дискреционный контроль доступа — модель авторизации, в которой владелец объекта назначает права пользователям и группам через разрешения или списки ACL.
Мандатный контроль доступа — модель разграничения доступа, в которой операции разрешаются обязательной системной политикой, не изменяемой владельцем ресурса.
Принцип наименьших привилегий — правило предоставления пользователю, службе или процессу только тех прав и на тот срок, которые необходимы для выполнения конкретной задачи.
Профиль AppArmor — набор правил мандатного контроля доступа, определяющий допустимые для конкретной программы операции с файлами, Linux capabilities и другими ресурсами.
Путевой контроль доступа — способ задания правил авторизации, при котором защищаемый ресурс выбирается по пути, например по пути URI или имени в файловой системе.
Режим AppArmor — состояние профиля контроля доступа в Linux: enforce блокирует нарушения, а complain регистрирует их, кроме действий, явно запрещённых правилами deny.
Режим complain — режим профиля AppArmor, в котором потенциальные нарушения регистрируются, но обычно не блокируются; исключение составляют явные правила deny.
Режим enforce AppArmor — режим принудительного применения профиля контроля доступа, в котором действия процесса, запрещённые профилем, блокируются и фиксируются в журнале.

Вопросы по теме

Все вопросы и ответы

Нужно ли сразу включать enforce для нового профиля AppArmor?

Нет, для нового профиля штатный безопасный порядок — сначала complain, затем enforce. В complain неразрешённые обычными правилами действия обычно записываются в журнал, но не блокируются. Это позволяет собрать фактические потребности приложения без немедленного нарушения его работы.

После включения complain перезапустите сервис и выполните не только запуск, но и обработку запросов, фоновые задания, запись данных, ротацию, обновление конфигурации и штатное завершение. Для каждого события проверьте профиль, процесс, операцию и ресурс. Добавляйте разрешение, только если действие действительно требуется сервису; широкие правила на всё дерево файлов или произвольный запуск программ делать не следует.

Изменённый файл профиля нужно загрузить, например через apparmor_parser -r, и повторить проверку. Затем включите enforce только для нужного профиля через aa-enforce, проверьте его режим в aa-status и протестируйте сервис. При критичном отказе временно верните именно этот профиль в complain, а не отключайте AppArmor на всём сервере.

Почему в complain mode AppArmor сервис всё равно получает отказ?

В режиме complain AppArmor обычно журналирует операции, которые не разрешены обычными разрешающими правилами, но не блокирует их. Однако это не означает, что процесс получает безусловный доступ.

Во-первых, явные правила deny сохраняют действие и в complain. Во-вторых, AppArmor работает вместе с обычным контролем доступа Linux: процессу могут отказать владельцы файла, chmod, ACL или ограничения файловой системы. Также причиной может быть seccomp либо другой механизм безопасности. Поэтому сообщение Permission denied само по себе не доказывает, что блокировка вызвана профилем AppArmor.

Для диагностики найдите полную запись события и проверьте поля profile, comm, pid, operation, name, requested_mask и denied_mask. Если AppArmor-события нет, проверьте права на реальный путь, символьные ссылки и конфигурацию сервиса. Если событие есть, определите, ожидаема ли операция: нужный доступ добавляют узким правилом, а подозрительное действие не разрешают автоматически.

Можно ли отключить только один профиль AppArmor для диагностики?

Да. В типичной Ubuntu/Debian-конфигурации команда aa-disable /etc/apparmor.d/opt.acme.bin.reportd выгружает указанный профиль из ядра и создаёт отметку отключения. Благодаря этому штатная загрузка профилей не должна включить его снова при перезапуске службы AppArmor или после перезагрузки.

Такое действие допустимо только как краткая диагностика. Пока профиль отключён, процесс не ограничен этим слоем мандатного контроля доступа. Сохраните исходный профиль, зафиксируйте время и причину отключения, а также назначьте проверку возврата защиты.

Простая выгрузка профиля через apparmor_parser -R отличается: она удаляет активный профиль, но сама по себе не обязана предотвратить его последующую загрузку из файла политики. После диагностики профиль обычно возвращают через aa-enforce /etc/apparmor.d/opt.acme.bin.reportd в версиях, где утилита управляет отметкой disable. Перед возвратом желательно устранить причину отказа и проверить сервис в complain либо enforce.

Почему chmod и ACL не устраняют AppArmor denied?

Потому что AppArmor не заменяет обычные права Linux, а работает вместе с ними. Процесс должен одновременно пройти проверку владельца, режима файла и ACL, а также получить разрешение в своём профиле AppArmor. Поэтому корректные chmod и ACL не помогут, если профиль не разрешает нужное чтение, запись, выполнение или другую операцию.

Почему профиль AppArmor не применяется к запущенному сервису?

AppArmor обычно связывает профиль с путём исполняемого файла. Поэтому имя unit, например reportd.service, не подтверждает, что нужный профиль применяется именно к фактически запущенному бинарному файлу.

Сначала просмотрите unit и drop-in-файлы командой systemctl cat reportd: проверьте ExecStart=, аргументы, обёртки и дочерние команды. Затем получите PID через systemctl show -p MainPID --value reportd и определите реальный исполняемый файл: readlink -f /proc/<PID>/exe. Этот путь важнее предположений по имени службы, поскольку attachment профиля обычно соответствует пути после разрешения символьных ссылок.

Далее найдите существующую политику в /etc/apparmor.d и проверьте точное имя либо attachment через aa-status. Если сервис после обновления запускается по другому пути, через wrapper или создаёт дочерний процесс, основному профилю может не соответствовать фактическое поведение. После изменения профиля загрузите его и при необходимости перезапустите или штатно переподключите сервис, чтобы новый exec получил нужный attachment.