Права в Linux отвечают на вопрос «кто может читать этот файл». AppArmor отвечает на другой: «что вообще позволено этой программе». Разница проявляется при взломе. Веб-шелл выполняется от пользователя веб-сервера и получает все его права — а это чтение доброй половины системы. Профиль AppArmor ограничивает процесс списком того, что ему нужно для работы, и попытка прочитать /etc/shadow или запустить /bin/bash заканчивается отказом, независимо от прав пользователя.
Что уже включено
sudo aa-status
Вывод отвечает на три вопроса: сколько профилей загружено, сколько из них в режиме enforce и complain и какие процессы работают без профиля вообще. На типичной Ubuntu профилей окажется несколько десятков, но почти все — для вспомогательных программ вроде man и tcpdump. Ключевые службы — nginx, Apache, PHP-FPM — в списке ограниченных обычно отсутствуют.
Три режима, которые надо различать:
- enforce — правила применяются, лишнее запрещено;
- complain — нарушения только записываются в журнал, ничего не блокируется. Режим для настройки;
- unconfined — профиля нет, программа работает без ограничений.
Самая полезная часть вывода aa-status — последняя: процессы, слушающие сеть и при этом не ограниченные ничем. Это и есть список того, с чего стоит начать.
Инструменты
sudo apt install apparmor-utils
Без этого пакета команд aa-complain, aa-enforce и aa-logprof в системе нет, хотя сам AppArmor работает.
Как включить профиль и не остановить службу
Порядок принципиален. Профиль, включённый сразу в enforce, с высокой вероятностью запретит службе что-нибудь нужное, и она перестанет работать — обычно не сразу, а на редкой операции вроде загрузки файла или отправки почты.
Правильная последовательность:
sudo aa-complain /etc/apparmor.d/usr.sbin.nginx
Неделя работы в этом режиме, включая все нештатные сценарии: выгрузку бэкапа, обновление, загрузку крупных файлов. Затем — разбор накопленного:
sudo aa-logprof
Команда проходит по записанным нарушениям и по каждому спрашивает, разрешить его или нет. Здесь нужна внимательность: разрешать следует то, что действительно относится к работе службы, а не всё подряд — иначе получится профиль, разрешающий всё, и смысл теряется.
И только потом:
sudo aa-enforce /etc/apparmor.d/usr.sbin.nginx
Где смотреть отказы
Все нарушения попадают в журнал ядра:
sudo journalctl -k | grep -i apparmor
sudo grep 'apparmor="DENIED"' /var/log/audit/audit.log
Второй файл существует, если установлен auditd, — и с ним записи заметно подробнее. В записи отказа видны имя профиля, запрошенная операция и путь, к которому обращались; этого достаточно, чтобы понять, чинить профиль или радоваться срабатыванию.
Отдельно стоит запомнить симптом: служба ведёт себя странно — не читает конфиг, не пишет в каталог, не открывает сокет, — а в её собственных логах ошибка выглядит как «отказано в доступе» при заведомо правильных правах. Это почти всегда AppArmor, и первое, что стоит сделать, — заглянуть в журнал ядра.
Мера практическая, а не теоретическая
Профиль для PHP-FPM или nginx окупается конкретным образом. Веб-шелл, попавший на сайт, при ограниченном процессе не может ни прочитать системные файлы, ни запустить оболочку, ни записать что-либо за пределами разрешённых каталогов. Взлом сайта остаётся взломом сайта, а не превращается в доступ ко всей машине — а именно этот переход и составляет основную часть ущерба.
Разумный порядок внедрения: сначала профиль для того, что смотрит в интернет (веб-сервер, PHP-FPM), потом для баз данных, дальше — по необходимости. Всё сразу включать не нужно, и универсального готового набора не существует: профиль зависит от того, где у вас лежат файлы.
Что проверять регулярно
Профили сбрасываются в неограниченный режим чаще, чем кажется: обновление пакета может заменить файл профиля, ручная отладка оставляет службу в complain, а новая служба приезжает без профиля вовсе. Полезны две цифры: сколько профилей в enforce и сколько сетевых процессов без ограничений. Изменение любой из них — событие, о котором стоит знать. Как это выглядит собранным на одну страницу — на демо ниже.