ADG Оставить заявку
Блог Автоматизация 4 мин чтения

CentOS 8 и SELinux: обновляем Ansible-роли, где авторы с Galaxy этого не сделали

SELinux enforcing в CentOS 8 поломал три роли из Ansible Galaxy - не падением, а тихим отказом. Добавляем sefcontext и restorecon туда, где авторы не предусмотрели.

Контекст момента

CentOS 8 (сентябрь 2019) с SELinux enforcing по умолчанию выявил проблемы в community-ролях Ansible Galaxy, не поддерживающих SELinux-контексты

За два месяца работы с CentOS 8 в managed-инфраструктуре мы набрали достаточно граблей, чтобы написать отдельный пост только про SELinux и Ansible Galaxy. Потому что это не одна история - это паттерн.

Когда в октябре мы поднимали первые продакшн-серверы на восьмёрке, SELinux enforcing был ожидаем. У нас он включён по умолчанию и на CentOS 7 - вопрос не в том, включать или нет, а в том, что community-роли, которые мы брали с Galaxy, писались и тестировались преимущественно на CentOS 7, где большинство команд умалчивали SELinux-контексты. Восьмёрка это не прощает.

Как это проявляется

Не падением роли. В этом и проблема. Ansible отрабатывает без failed, сервис стартует, systemctl status показывает active (running). Но через несколько секунд - Permission denied в логах, сервис не обрабатывает запросы, или конкретная функция не работает. Первые пару раз мы теряли время, потому что смотрели не туда.

ausearch -m avc -ts recent - вот куда надо смотреть сразу после деплоя на CentOS 8, если что-то ведёт себя странно.

Три роли, которые пришлось чинить

Первая - роль для rsyslog с кастомным хранилищем логов. Роль из Galaxy создавала директорию под нестандартным путём и клала туда конфиг. На CentOS 7 rsyslog писал без вопросов. На восьмёрке - отказ писать в директорию, потому что у неё контекст default_t, а rsyslog ожидает var_log_t. Роль это не учитывала вообще.

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

- name: set selinux context for log dir
  sefcontext:
    target: '/srv/logs(/.*)?'
    setype: var_log_t
    state: present

- name: apply selinux context
  command: restorecon -Rv /srv/logs
  changed_when: false

Важно: sefcontext без последующего restorecon - это как написать правило в конфиг без перезагрузки сервиса. Политика запишется, но фактический xattr на файлах не изменится.

Вторая - роль для nginx с нестандартным DocumentRoot. Здесь ситуация немного хитрее. Роль создавала webroot в /srv/www/<project>/, но semanage fcontext -l показывал, что /srv/ не покрыт стандартными правилами nginx. Результат: nginx запускается, отдаёт 403 и пишет (13: Permission denied) в error.log. setenforce 0 моментально решает проблему и подтверждает диагноз.

Решение то же: sefcontext + restorecon, только тип httpd_sys_content_t. Добавили в нашу обёртку вокруг роли, трогать оригинальную не стали - проще поддерживать изменения отдельно.

Третья - роль для Postfix с нестандартными очередями. Это самый неприятный случай, потому что Postfix стартовал, письма принимал, но при определённых условиях падал при попытке записи во временную директорию. Не при каждом письме - только при конкретном сценарии с размером. audit.log молчал несколько минут, потом выдавал пачку avc: denied { write }. audit2allow предложил создать кастомный модуль политики, но мы пошли по другому пути - поправили путь очередей на стандартный /var/spool/postfix/, где SELinux-контексты расставлены из коробки.

Что поменяли в процессе

Теперь у нас в базовом плейбуке есть шаг проверки после деплоя: запускаем ausearch -m avc -ts recent и смотрим вывод. Не автоматическая проверка - просто напоминание оператору смотреть в audit.log через пять минут после применения роли на CentOS 8. Топорно, но работает.

Для ролей, которые работают с путями вне стандартных - добавили в наш внутренний чеклист ревью ролей: «а есть ли тут sefcontext?». Если роль создаёт директории или файлы в нестандартных местах и в ней нет ни одного упоминания SELinux - это красный флаг для CentOS 8.

Модуль community.general.sefcontext требует libsemanage-python3 или python3-libsemanage на целевом хосте. На CentOS 8 это нужно ставить явно - добавили в bootstrap-роль. На CentOS 7 там был libsemanage-python, на восьмёрке пакет переименован, и если bootstrap не обновлён - получишь ModuleNotFoundError от Ansible в самый неподходящий момент.

Что делать с ролями из Galaxy

Три варианта, и мы используем все три в зависимости от роли.

Первый - форк с минимальными изменениями. Берём роль, добавляем SELinux-задачи, называем нашей версией. Плюс - полный контроль. Минус - обновления Galaxy надо тянуть вручную.

Второй - обёртка. Вызываем оригинальную роль, а до/после добавляем наши задачи с SELinux. Проще поддерживать, но надо следить за порядком и тем, что оригинальная роль не сбросит контексты.

Третий - PR в оригинальный репозиторий. Для двух ролей мы уже отправили PR с SELinux-поддержкой. Когда примут - вопрос открытый, но хотя бы не в вакууме работаем.

Общая картина такая: многие роли в Galaxy написаны людьми, которые или тестировали на системах без SELinux, или с setenforce 0 как первой строчкой Vagrantfile. CentOS 8 это явно выявляет. Не баг в дистрибутиве - честная работа SELinux, как и должно быть. Просто ecosystem Galaxy к этому не всегда готов.

Контакт

Нужна такая же инженерная работа?

Опишите задачу и контекст. Ответим в течение рабочего дня, при необходимости подпишем NDA.