AppArmor в Ubuntu Server: создание и отладка профилей для собственных сервисов | AdminWiki

AppArmor в Ubuntu Server: создание и отладка профилей для собственных сервисов

28 августа 2026 11 мин. чтения
Содержание статьи

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

Практическая последовательность выглядит так: проверить поддержку AppArmor в Ubuntu Server, создать узкий профиль в /etc/apparmor.d, загрузить его в режиме complain, выполнить штатные сценарии сервиса, изучить события DENIED, проверить предложения aa-logprof, затем включить режим enforce. Такой порядок снижает риск остановки службы из-за пропущенного доступа.

AppArmor не заменяет Unix-права, systemd hardening, firewall и обновление пакетов. Он добавляет отдельный слой контроля для уже запущенного процесса и его дочерних процессов. Ниже приведен рабочий сценарий для собственного systemd-сервиса в Ubuntu Server.

Как AppArmor ограничивает сервис и какой результат даст настройка

Что именно защищает профиль AppArmor

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

  • чтение, запись, добавление данных и выполнение файлов;
  • проход по каталогам и создание объектов в файловой системе;
  • доступ к Unix-сокетам и временным файлам;
  • сетевые операции;
  • использование отдельных Linux capabilities;
  • переход дочернего процесса в другой профиль.

Профиль не меняет владельца файла и не отменяет обычные права пользователя. Если сервис запущен от имени appuser, ему по-прежнему нужны корректные права Unix. AppArmor может дополнительно запретить действие, которое Unix-права разрешают.

Правила применяются к процессу, запущенному по указанному пути. Если systemd запускает shell-wrapper, интерпретатор или другой бинарник, профиль для ожидаемого файла может не сработать так, как предполагается. Дочерние процессы наследуют профиль при использовании подходящего правила перехода, например ix.

Complain и enforce: два режима перед внедрением

В режиме complain AppArmor регистрирует нарушения, но обычно не блокирует действие. Этот режим нужен для сбора фактического поведения сервиса: обращений к конфигурации, каталогам данных, сокетам, DNS и дочерним программам.

В режиме enforce запрещенные действия блокируются и попадают в журнал. Сервис может перестать запускаться, принять запрос или записать данные, если профиль не содержит необходимого правила.

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

Для общей настройки hardening полезен отдельный материал о защите Linux-сервера: практическое руководство по hardening и аудиту в 2026 году.

Проверка поддержки AppArmor в Ubuntu Server

Проверка пакетов, службы и состояния ядра

Сначала определите версию системы и состояние основных компонентов:

cat /etc/os-release
uname -r

systemctl status apparmor --no-pager
aa-status
command -v apparmor_parser
apt policy apparmor apparmor-utils apparmor-profiles

В Ubuntu обычно нужны пакеты apparmor и apparmor-utils. Первый содержит службу и компоненты AppArmor, второй добавляет команды aa-status, aa-complain, aa-enforce и aa-logprof.

Нормальный результат для службы содержит состояние active (exited) или другое штатное активное состояние, а команда aa-status показывает загруженные профили. Отсутствие apparmor_parser указывает на неполную установку пакетов. Если служба есть, но ядро не сообщает о загруженных профилях, проверьте загрузку модуля и сообщения ядра.

sudo apt update
sudo apt install apparmor apparmor-utils

sudo systemctl enable --now apparmor
sudo systemctl status apparmor --no-pager
sudo aa-status

Версии Ubuntu могут отличаться по составу пакетов и формату вывода. Ориентируйтесь на фактическое наличие команд и состояние ядра, а не только на присутствие каталога /etc/apparmor.d.

Как понять список загруженных профилей

sudo aa-status
sudo apparmor_status

Вывод обычно разделяет профили в режимах enforce и complain. Профиль в каталоге конфигурации считается загруженным только после успешной обработки парсером. Наличие файла, например /etc/apparmor.d/usr.local.bin.myservice, само по себе не ограничивает процесс.

Для поиска профиля используйте:

sudo aa-status | grep myservice
sudo dmesg | grep -i apparmor

Если профиль не отображается, проверьте синтаксис, имя файла и результат загрузки. Для диагностики загрузки службы пригоден журнал:

sudo journalctl -u apparmor -b --no-pager

Создание минимального профиля для собственного сервиса

Сбор фактических путей и зависимостей процесса

До написания правил соберите данные о сервисе:

  • путь из ExecStart;
  • пользователь и группа из unit-файла;
  • рабочий каталог;
  • конфигурационные файлы;
  • каталоги состояния, кэша и журналов;
  • пути к Unix-сокетам и PID-файлам;
  • исходящие соединения и DNS-зависимости;
  • дочерние процессы и внешние утилиты.
systemctl cat myservice.service
systemctl show myservice.service -p ExecStart -p User -p Group -p WorkingDirectory
ps -ef | grep '[m]yservice'
readlink -f /path/to/myservice

Разделите зависимости на обязательные и необязательные. Например, сервису может требоваться чтение /etc/myservice/config.yml, запись в /var/lib/myservice/ и добавление строк в /var/log/myservice/service.log. Доступ к домашнему каталогу администратора в такой схеме не нужен.

strace помогает в тестовой среде, когда журналы не показывают полный путь обращения. Используйте его для подтверждения поведения, а не как автоматический генератор готовой политики.

Базовый синтаксис профиля AppArmor

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

sudo nano /etc/apparmor.d/usr.local.bin.myservice

Минимальный профиль может выглядеть так:

#include <tunables/global>

/usr/local/bin/myservice {
  #include <abstractions/base>

  /usr/local/bin/myservice rix,
  /etc/myservice/config.yml r,
  /var/lib/myservice/ r,
  /var/lib/myservice/** rwk,
  /var/log/myservice/ r,
  /var/log/myservice/** rw,
  /run/myservice/ rw,
  /run/myservice/** rw,

  network inet stream,
  network inet6 stream,
}

Имя после открывающей фигурной скобки должно соответствовать исполняемому файлу. Правила заканчиваются запятой. Include-файлы Ubuntu содержат общие разрешения для типовых системных действий и сокращают дублирование.

  • r разрешает чтение;
  • w разрешает запись;
  • a разрешает добавление в конец файла;
  • k разрешает блокировку файла;
  • x разрешает запуск;
  • ix запускает дочерний файл с наследованием текущего профиля;
  • px запускает файл с переходом в отдельный профиль;
  • ux запускает файл без ограничений AppArmor.

Правило ux расширяет доверенную область и требует отдельного обоснования. Для дочерней программы безопаснее создать отдельный профиль или использовать ix, если наследуемых ограничений достаточно.

Проверка и загрузка профиля

Сначала проверьте синтаксис без изменения активной политики:

sudo apparmor_parser -Q /etc/apparmor.d/usr.local.bin.myservice

Ключ -Q запускает проверку без загрузки профиля. После исправления ошибок загрузите профиль:

sudo apparmor_parser -r /etc/apparmor.d/usr.local.bin.myservice
sudo aa-status | grep myservice

Ключ -r заменяет уже загруженную версию. Перед каждым изменением сохраняйте копию:

sudo cp -a /etc/apparmor.d/usr.local.bin.myservice /etc/apparmor.d/usr.local.bin.myservice.bak

Для нового профиля включите complain:

sudo aa-complain /etc/apparmor.d/usr.local.bin.myservice

Настройка правил для файлов и каталогов

Разрешения read, write, append и execute

Выбирайте право под конкретную операцию. Конфигурации обычно получают r:

/etc/myservice/config.yml r,

Каталогу данных требуется проход по самому каталогу и доступ к объектам внутри:

/var/lib/myservice/ r,
/var/lib/myservice/** rwk,

Для журнала, который приложение только дополняет, лучше использовать a:

/var/log/myservice/service.log a,

Если приложение создает временные файлы, укажите каталог и нужные права. Для запуска дочернего процесса используйте узкий путь:

/usr/bin/helper ix,

Правило каталога и правило его содержимого решают разные задачи. Доступ к /var/lib/myservice/** не должен автоматически превращаться в доступ ко всей файловой системе.

Шаблоны путей и переменные include

Шаблон /** охватывает произвольное количество вложенных объектов. Такая запись удобна для диагностики, но опасна как постоянное правило:

/var/lib/myservice/** rwk,

Используйте шаблон только внутри выделенного каталога. Для одного файла задавайте точный путь. Общие фрагменты подключайте через include:

#include <abstractions/base>
#include <abstractions/nameservice>

abstractions/nameservice может потребоваться процессу, который разрешает имена через системный DNS. Фактический набор зависимостей проверяйте по журналу и поведению сервиса.

Права на каталоги, временные файлы и сокеты

Сервису нужен доступ к каждому родительскому каталогу на пути. Для /var/lib/myservice/data.db недостаточно разрешения на файл, если процесс не может пройти через /var, /var/lib или /var/lib/myservice.

Учитывайте каталоги, которые создает systemd через RuntimeDirectory= и StateDirectory=. При PrivateTmp=true сервис видит отдельное временное пространство, поэтому разрешение на обычный /tmp может не решать проблему.

Unix-сокет задавайте отдельным правилом, если приложение использует его как файл или endpoint:

/run/myservice/myservice.sock rw,

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

Правила для сети и Linux capabilities

Сетевой доступ приложения

Для сетевых действий в профиле используют правила network. Пример для TCP-соединений IPv4 и IPv6:

network inet stream,
network inet6 stream,

Принимающий TCP-сервис и клиент, который подключается к базе данных, могут использовать разные сценарии, поэтому проверяйте их отдельно. Запустите сервис на локальном адресе, выполните входящий запрос, исходящее подключение и DNS-разрешение имени.

AppArmor контролирует операции процесса, но не фильтрует порты так, как UFW или nftables. Firewall и security groups облачного провайдера продолжают определять сетевую доступность. Сервер для тестов можно развернуть в облачной инфраструктуре с отдельными правилами доступа: серверы и VDS/VPS Timeweb Cloud.

Capabilities: когда они нужны и чем опасны

Capabilities разделяют полномочия, которые раньше связывали с root. Примеры:

  • cap_net_bind_service, привязка к портам ниже 1024;
  • cap_net_admin, отдельные сетевые операции;
  • cap_setuid и cap_setgid, смена идентификатора и группы.

Сначала проверьте, не решается ли задача настройкой systemd:

systemctl show myservice.service -p User -p AmbientCapabilities -p CapabilityBoundingSet
getcap /usr/local/bin/myservice

Добавляйте в профиль только capability, которая подтверждена конкретным отказом и назначением приложения. Полный набор capabilities превращает профиль в слабое ограничение.

Перевод профиля из complain в enforce через aa-logprof

Сбор отказов в journalctl и audit.log

Выполните штатные операции сервиса в режиме complain, затем найдите события AppArmor:

sudo journalctl -k -b --no-pager | grep -i apparmor
sudo journalctl -b --no-pager | grep -E 'apparmor|DENIED'
sudo grep -i 'apparmor.*denied' /var/log/audit/audit.log

В записи DENIED анализируйте профиль, процесс, операцию, путь и capability. Например, отказ в операции open над /var/lib/myservice/cache.db означает, что нужно проверить назначение файла и добавить минимальное право, если оно действительно требуется.

Фильтруйте журнал по времени старта, запросу или ротации логов. Это помогает связать событие с действием приложения и не принимать случайный диагностический шум за обязательную зависимость.

Работа с aa-logprof

sudo aa-logprof

Утилита анализирует события AppArmor и предлагает правила. Для каждого запроса выбирайте разрешение только при подтвержденной необходимости. Вариант deny оставляйте, если действие не относится к штатной работе сервиса или выглядит подозрительно.

После принятия правил проверьте измененный файл:

sudo apparmor_parser -Q /etc/apparmor.d/usr.local.bin.myservice
sudo apparmor_parser -r /etc/apparmor.d/usr.local.bin.myservice

aa-logprof не знает бизнес-логику приложения. Автоматическое принятие всех предложений может дать сервису доступ к секретам, домашним каталогам и системным файлам.

Критерии готовности enforce-режима

  • сервис запускается после остановки и после перезагрузки;
  • проходят основные API-запросы или CLI-команды;
  • читаются конфигурация и сертификаты;
  • создаются и обновляются данные;
  • работают DNS, исходящие соединения и Unix-сокеты;
  • запускаются необходимые фоновые процессы;
  • проходит ротация журналов;
  • временные диагностические разрешения удалены.

Переключите профиль только после повторной проверки:

sudo aa-enforce /etc/apparmor.d/usr.local.bin.myservice
sudo aa-status | grep myservice
sudo systemctl restart myservice.service
sudo systemctl status myservice.service --no-pager

Интеграция AppArmor с systemd

Проверка соответствия профиля и ExecStart

Сверьте профиль с фактическим unit-файлом:

systemctl cat myservice.service
systemctl show myservice.service -p ExecStart
readlink -f /usr/local/bin/myservice
pid=$(systemctl show -p MainPID --value myservice.service)
readlink -f /proc/$pid/exe

Wrapper на shell, Python-интерпретатор или симлинк меняет картину запуска. Если unit вызывает /bin/sh -c, нужно отдельно проверить переходы и дочерние программы. Для независимых компонентов создавайте отдельные профили, когда им требуются разные права.

Перезапуск и диагностика unit-файла

Если изменился только профиль, достаточно проверить его и перезапустить службу. После изменения unit-файла добавьте daemon-reload:

sudo apparmor_parser -Q /etc/apparmor.d/usr.local.bin.myservice
sudo systemctl daemon-reload
sudo systemctl restart myservice.service
sudo systemctl status myservice.service --no-pager
sudo journalctl -u myservice.service -b --no-pager

Ошибка запуска может исходить из AppArmor, systemd sandboxing, Unix-прав, отсутствующего каталога или самого приложения. Сопоставляйте время сбоя в журнале unit с событием DENIED в журнале ядра.

Постоянная загрузка профиля после перезагрузки

Профили из /etc/apparmor.d загружаются службой AppArmor. После reboot проверьте фактическое состояние:

sudo systemctl is-enabled apparmor
sudo systemctl is-active apparmor
sudo aa-status | grep myservice
sudo systemctl is-active myservice.service

Проверьте, что профиль находится в правильном каталоге, имеет корректный синтаксис и сохраняет режим enforce. Тест после reboot выполняйте на отдельном сервере, прежде чем менять production-систему.

Диагностика проблем и безопасное внедрение в production

Типовые причины отказов AppArmor

  • профиль указывает старый или неверный путь к бинарнику;
  • процесс не может пройти по родительскому каталогу;
  • приложение обращается к цели симлинка, которая не учтена;
  • файл создается динамически и отсутствует в исходном списке;
  • ротация журналов использует переименование и повторное открытие;
  • сервис создает Unix-сокет в /run;
  • не разрешено DNS-имя или исходящее соединение;
  • дочернему процессу нужен отдельный профиль;
  • не хватает конкретной capability.

Алгоритм проверки простой: найти DENIED, определить операцию и путь, подтвердить необходимость действия, проверить Unix-права и параметры systemd, затем изменить одно правило. После этого снова загрузите профиль и воспроизведите тот же сценарий.

Проверка профиля после обновления приложения

Обновление может изменить бинарник, конфигурацию, каталог кэша, формат логов или набор дочерних процессов. После обновления повторите cold start, основные запросы, запись данных, фоновые задания и ротацию логов.

Новые события DENIED анализируйте вручную. Слепое добавление всех предложений aa-logprof постепенно расширяет политику и снижает пользу изоляции.

Чек-лист внедрения и отката

  1. Сохраните резервную копию профиля и unit-файла.
  2. Проверьте синтаксис через apparmor_parser -Q.
  3. Загрузите профиль в complain на тестовой системе.
  4. Выполните штатные и аварийные сценарии сервиса.
  5. Разберите события DENIED и вручную проверьте предложения aa-logprof.
  6. Повторите тесты после перезагрузки.
  7. В согласованное окно включите enforce.
  8. Наблюдайте журналы ядра и журнал unit в течение периода, соответствующего нагрузке сервиса.

При критическом сбое временно верните профиль в complain:

sudo aa-complain /etc/apparmor.d/usr.local.bin.myservice
sudo systemctl restart myservice.service

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

Для комплексной проверки конфигураций и журналов пригодится руководство по аудиту безопасности серверов.

Итоговая шпаргалка по командам AppArmor в Ubuntu Server

КомандаНазначение
aa-statusПоказать загруженные профили и их режимы.
systemctl status apparmorПроверить состояние службы AppArmor.
apparmor_parser -Q FILEПроверить синтаксис профиля без загрузки.
apparmor_parser -r FILEЗагрузить новую или обновленную версию профиля.
aa-complain FILEПеревести профиль в режим регистрации нарушений.
aa-enforce FILEВключить фактическую блокировку запрещенных действий.
aa-logprofРазобрать события и получить предложения правил.
journalctl -k -b | grep -i apparmorНайти события AppArmor в журнале ядра.
journalctl -u myservice.service -bПроверить запуск и работу systemd-сервиса.
systemctl restart myservice.serviceПовторно запустить сервис после изменения политики.

Рабочая политика AppArmor начинается с точного списка зависимостей и заканчивается проверкой в enforce после reboot. Узкие пути, отдельные capabilities, анализ каждого DENIED и резервная копия профиля дают контролируемое ограничение без лишнего доступа.

Поделиться:
Сохранить гайд? В закладки браузера