Классические права Unix (rwx, владелец, группа) - это дискреционный контроль доступа (DAC): владелец файла сам решает, кому дать доступ, и процесс, запущенный от root, может делать буквально всё. Мандатный контроль доступа (MAC) добавляет второй, неотключаемый владельцем слой: правила задаёт администратор через политику, и даже процесс root подчиняется ей. В этом уроке разберём два рабочих механизма MAC в Linux - SELinux (родной для семейства RHEL) и AppArmor (родной для Debian/Ubuntu/SUSE), научимся читать контексты, переключать режимы, чинить отказы и писать локальные исключения. Smack посмотрим обзорно как третий вариант.

Как это работает
SELinux реализует MAC через метки (labels), которые ядро через модуль LSM проверяет при каждом системном вызове доступа. У каждого процесса, файла, порта, сокета есть контекст безопасности из четырёх полей: пользователь SELinux, роль, тип и уровень MLS. Пример контекста файла: system_u:object_r:httpd_sys_content_t:s0. Ключевое поле для целевой (targeted) политики - это тип. Решение принимается по правилам вида allow: процессу с типом httpd_t разрешено читать файлы с типом httpd_sys_content_t. Нет правила - нет доступа, по умолчанию запрещено всё. Эта модель называется Type Enforcement.
Целевая политика, которая стоит по умолчанию в RHEL 10 и Fedora 41+, ограничивает не всё подряд, а только перечисленные сетевые и системные сервисы (демоны). Процессы, для которых нет специальной политики, работают в неограниченном домене unconfined_t и фактически живут по старым правилам DAC. Это разумный компромисс: защищаем то, что смотрит в сеть, не ломая остальное.
У SELinux три режима. Enforcing - правила реально применяются, нарушения блокируются и пишутся в аудит. Permissive - нарушения только логируются, но пропускаются; это режим отладки, а не безопасности. Disabled - модуль выключен (в RHEL 9+ полностью выключить через конфиг уже нельзя, только через параметр ядра selinux=0, и так делать не надо). Булевы переключатели (booleans) - это готовые тумблеры в политике, которые включают и выключают целые куски правил без перекомпиляции, например разрешить веб-серверу исходящие сетевые соединения.
AppArmor устроен принципиально иначе: он привязывает правила не к меткам, а к пути исполняемого файла. Профиль описывает, к каким путям, capability и сетевым операциям имеет доступ конкретная программа. Профиль работает в режиме enforce (нарушения блокируются) или complain (только логируются, аналог permissive). Подход по путям проще читать и писать, но он слабее там, где важны жёсткие, текстовые ссылки, монтирования и переименования. Smack (Simplified Mandatory Access Control Kernel) - третий LSM на метках, заметно проще SELinux; применяется в основном во встраиваемых системах и в Tizen, на серверах встречается редко.
Команды и примеры
Проверить статус и режим SELinux (RHEL/Fedora):
Код: Выделить всё
getenforce # Enforcing / Permissive / Disabled
sestatus # подробно: текущий и из конфига режим, тип политики
setenforce 0 # временно в permissive (до перезагрузки)
setenforce 1 # обратно в enforcing
Посмотреть контексты (флаг -Z есть у большинства утилит):
Код: Выделить всё
ls -Z /var/www/html/index.html
ps -eZ | grep httpd
id -Z # контекст текущего пользователя
Код: Выделить всё
# Назначить тип каталогу нестандартного веб-корня НАВСЕГДА (в базе fcontext)
semanage fcontext -a -t httpd_sys_content_t '/srv/web(/.*)?'
restorecon -Rv /srv/web # применить из базы к файлам
# Открыть нестандартный порт для веб-сервера
semanage port -a -t http_port_t -p tcp 8088
semanage port -l | grep http_port_t
Булевы переключатели:
Код: Выделить всё
getsebool -a | grep httpd
setsebool -P httpd_can_network_connect on # -P = постоянно
Код: Выделить всё
ausearch -m AVC -ts recent
# либо человеко-читаемые подсказки:
sealert -a /var/log/audit/audit.log
# сгенерировать локальный модуль-исключение:
ausearch -m AVC -ts recent | audit2allow -M my_httpd_fix
semodule -i my_httpd_fix.pp
Код: Выделить всё
aa-status # сколько профилей, в каком режиме
apt install apparmor-utils # утилиты aa-*
aa-complain /etc/apparmor.d/usr.sbin.nginx # профиль в complain
aa-enforce /etc/apparmor.d/usr.sbin.nginx # обратно в enforce
aa-logprof # интерактивно дополнить профиль по логам
Частые грабли
- Считать permissive безопасным режимом. Permissive ничего не блокирует - это только для отладки. Прод должен быть в enforcing.
- Чинить отказ через chcon и удивляться, что после ребута или autorelabel всё сломалось снова. Постоянное решение - semanage fcontext плюс restorecon.
- Слепо скармливать весь audit.log в audit2allow и устанавливать модуль. Так можно разрешить лишнее. Сначала прочитайте, что именно отказано, и нет ли готового boolean.
- Менять SELINUX=disabled в конфиге на работающей системе. После выключения метки протухают, и обратное включение требует полной перемаркировки (touch /.autorelabel плюс перезагрузка).
- Забыть открыть нестандартный порт через semanage port - сервис не стартует, а в логе AVC на name_bind.
- В AppArmor ждать защиты от жёстких ссылок: правила по путям обходятся через hardlink на тот же inode под другим именем, если профиль это не учитывает.
- Отсутствие setroubleshoot-server - тогда sealert не работает и подсказок в журнале нет, остаётся только ausearch.
- На стенде с RHEL 10 или Fedora убедитесь, что SELinux в enforcing (getenforce, sestatus).
- Установите httpd, создайте нестандартный веб-корень /srv/site, положите туда index.html и пропишите его в DocumentRoot.
- Перезапустите httpd, откройте страницу - получите 403. Найдите AVC через ausearch -m AVC -ts recent.
- Назначьте тип через semanage fcontext -a -t httpd_sys_content_t '/srv/site(/.*)?' и примените restorecon -Rv /srv/site. Проверьте доступ.
- Переведите httpd слушать порт 8088, через semanage port -a -t http_port_t -p tcp 8088 разрешите его, перезапустите.
- Включите подходящий boolean (например httpd_can_network_connect) и убедитесь через getsebool, что значение постоянное.
- Бонус на Ubuntu 24.04: aa-status, переведите профиль nginx в complain, вызовите нарушение, посмотрите лог, верните enforce через aa-enforce.
- Чем MAC отличается от DAC и почему root не всемогущ при включённом SELinux в enforcing?
- Из каких полей состоит контекст безопасности и какое из них решающее в целевой политике?
- В чём разница между chcon, semanage fcontext и restorecon - что переживает перезагрузку и почему?
- Какой режим SELinux пригоден для отладки и почему его нельзя оставлять на проде?
- Как из AVC-отказа получить рабочий локальный модуль политики и какие тут опасности?
- Чем модель AppArmor по путям принципиально отличается от модели SELinux по меткам и где у каждой слабые места?