SELinux в enforcing на CentOS 5: как мы перестали его отключать и начали разбираться с политиками
После миграции на CentOS 5 Apache не стартовал на трёх серверах - SELinux блокировал нестандартный document root. Вышли через audit2allow за 20 минут.
SELinux в enforcing-режиме включён по умолчанию в RHEL 5 / CentOS 5 в 2007 году
Когда в августе переезжали на CentOS 5, мы уже знали, что SELinux там включён в enforcing по умолчанию. Знали теоретически. На практике выяснилось, что Apache не поднялся ни на одном из трёх серверов, которые ушли в production первой волной. Не упал с ошибкой в конфиге, не вернул 500 - просто не стартовал. Systemd тогда ещё не было, sysvinit-скрипт молча возвращал failure, и без понимания что к чему первые несколько минут уходили на проверку обычных подозреваемых: конфиг Apache, права на файлы, порты.
Потом кто-то догадался посмотреть audit.log.
Картина в логах
/var/log/audit/audit.log был полон AVC-отказов вида:
type=AVC msg=audit(...): avc: denied { read } for pid=... comm="httpd"
name="..." dev=... ino=... scontext=user_u:system_r:httpd_t:s0
tcontext=user_u:object_r:user_home_t:s0 tclass=file
Корень проблемы простой: document root у нескольких клиентов лежал не в /var/www/html, а в /srv/web/<клиент>/public или похожих нестандартных путях - исторически так сложилось. SELinux об этих путях ничего не знал и применял к ним тип user_home_t или вовсе default_t, а httpd с контекстом httpd_t читать такое не может.
Первый инстинкт был предсказуемый: setenforce 0 и разобраться потом. Мы его подавили. Раз уже взялись за CentOS 5, надо разбираться по-настоящему.
audit2allow и локальный модуль политики
В RHEL 5 / CentOS 5 Red Hat поставил в комплект утилиту audit2allow, которая читает AVC-отказы и генерирует правила политики. Схема оказалась прямолинейной:
- Собрать отказы.
grep httpd /var/log/audit/audit.log | audit2allow -m local > local.te- получаем текстовое описание политики. - Посмотреть что там написано. Это важно - не нужно подписывать политику не читая. В нашем случае правила были разумные: разрешить httpd читать файлы с конкретными контекстами.
- Скомпилировать и загрузить.
checkmodule -M -m -o local.mod local.te && semodule_package -o local.pp -m local.mod && semodule -i local.pp.
Первый прогон на одном сервере занял около двадцати минут, включая чтение правил и понимание синтаксиса. На двух оставшихся - уже быстрее, потому что проблема была идентичной.
Apache поднялся. Сайты отдавали контент. Enforcing остался включён.
Почему не restorecon
Более правильный путь для Apache и нестандартного document root - присвоить файлам правильный контекст через chcon -R -t httpd_sys_content_t /srv/web/ или через semanage fcontext с последующим restorecon. Это работает при условии, что путь фиксирован и не меняется при переустановке.
Мы разобрались с этим уже после - прочитали документацию, проверили на стенде. В итоге на двух серверах применили semanage fcontext и restorecon, убрав локальный модуль. Модуль через audit2allow - хорошее средство быстро разблокировать ситуацию, но не всегда самое чистое итоговое решение.
Практическое правило, которое из этого выходит: audit2allow для диагностики и первого fix, semanage + restorecon для постоянного решения, если речь о контексте файлов.
Что SELinux реально даёт в enforcing
На CentOS 4 мы держали SELinux в permissive или отключали совсем - слишком много ручной работы было с политиками, инструменты были сырее. В CentOS 5 порог вошёл заметно ниже.
Конкретный пример из той же недели: один из серверов попытался через PHP-скрипт записать файл в /etc - не злонамеренно, баг в коде клиентского приложения. SELinux заблокировал запись, AVC-запись появилась в audit.log. Без enforcing это прошло бы тихо, и мы узнали бы только если бы файл в /etc что-то сломал.
Это не то чтобы ежедневно случается - но именно для таких случаев enforcing и нужен.
Что теперь в процессе
Правило для новых серверов на CentOS 5 стало простым: SELinux в enforcing с первого дня. Если сервис не стартует - сразу смотрим audit.log, не трогаем setenforce.
Для переезжающих с CentOS 4 старых установок алгоритм такой: переключить в permissive, дать поработать неделю, собрать все AVC-отказы, разобрать пачкой через audit2allow или restorecon, переключить в enforcing, проверить что всё живо. Это дольше, но правильнее чем чинить в production под нагрузкой.
Ещё не до конца разобрались с тем, как обращаться с политиками при обновлениях пакетов - бывает что обновление демона меняет поведение и старый модуль политики начинает либо пропускать лишнее, либо блокировать нужное. Пока отслеживаем руками. Инструментов автоматического аудита политик в rpm-пакетах у нас нет.
Всё это - часть работы в рамках сопровождения серверной инфраструктуры: не откладывать неудобное в «разберёмся потом», а разбираться когда проблема ещё свежая и понятная.