SELinux
SELinux в РОСА
В РОСА 13 поддерживается режим targeted: защищаются сетевые службы (веб-серверы, СУБД, контейнерные среды выполнения и другие серверные приложения), а локальные действия администратора не ограничиваются. Такой же режим используется в Red Hat Enterprise Linux и Fedora; политика для РОСА собирается из того же дерева fedora-selinux/selinux-policy, поэтому имена доменов и типов (httpd_t, mysqld_db_t и т. п.), утилиты и формат журналов совпадают с RHEL: инструкции и модули сторонних пакетов, написанные для Red Hat, применимы и в РОСА.
Полноценная работа в режиме MLS на данный момент не поддерживается.
Статья построена как лабораторная работа: в каждом разделе ставится задача, приводятся команды и результат, который вы должны получить. Все примеры проверены на чистой установке РОСА Сервер 13 и применимы к РОСА Хром, РОСА Фреш и МОС версии 13 и новее.
По умолчанию SELinux выключен.
Все команды выполняются от имени root. Блоки с командами наберите в терминале; блок после слова «Результат:» — это то, что вы должны увидеть на экране.
Подготовка системы
Установите политику targeted:
dnf install selinux-policy-targeted
Вместе с ней будут установлены selinux-policy и утилиты. После установки в /etc/selinux/config появляется конфигурация с выключенным по умолчанию SELinux. Проверьте её:
cat /etc/selinux/config | grep -E "^SELINUX|^SELINUXTYPE"
Результат:
SELINUX=disabled SELINUXTYPE=targeted
Служба аудита
Задача: включить запись отказов SELinux в журнал аудита.
Без пакета audit отказы выводятся только в журнал ядра с ограничением частоты, и ausearch не находит их. Установите и включите:
dnf install audit systemctl enable --now auditd
Проверьте, что служба запущена:
systemctl is-active auditd
Результат:
active
Первый запуск: permissive и переразметка
Задача: включить SELinux в разрешающем режиме (permissive) — отказы вычисляются и записываются в журнал, но не блокируются. Это штатный способ перевода сервера на SELinux: сначала в permissive изучают журнал, затем переводят в enforcing.
Измените режим в конфигурации, запросите переразметку файловой системы при следующей загрузке и перезагрузитесь:
sed -i "s/^SELINUX=.*/SELINUX=permissive/" /etc/selinux/config touch /.autorelabel reboot
Переразметка (relabel) необходима: файлы, установленные до включения SELinux, не имеют меток. При загрузке система обходит все файлы и проставляет метки согласно политике; на больших файловых системах это занимает несколько минут.
После загрузки проверьте состояние:
getenforce
Результат:
Permissive
Развёрнутое состояние системы:
sestatus | head -5
Результат:
SELinux status: enabled SELinuxfs mount: /sys/fs/selinux SELinux root directory: /etc/selinux Loaded policy name: targeted Current mode: permissive
Метка файла, установленного до включения SELinux, теперь корректна:
ls -Z /usr/sbin/sshd
Результат:
system_u:object_r:sshd_exec_t:s0 /usr/sbin/sshd
Файл /.autorelabel после переразметки удаляется автоматически.
Изучение журнала аудита
Задача: научиться находить и читать отказы SELinux.
Команды для повседневной работы:
ausearch -m avc -ts recent # отказы за последние 10 минут ausearch -m avc -ts boot # отказы с загрузки ausearch -m avc -ts today # отказы за сутки
Каждый отказ — строка denied с указанием операции, процесса и меток:
avc: denied { write } for comm="httpd" name="x" scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:var_lib_t:s0 tclass=file
Здесь scontext — метка процесса (домен httpd_t), tcontext — метка объекта, tclass — класс объекта, в фигурных скобках — запрещённая операция.
Две утилиты объясняют отказ словами и предлагают вариант правила:
audit2why -a # объяснение каждого отказа audit2allow -a # черновик allow-правила по журналу
Примечание. Вывод audit2allow — отправная точка для анализа, а не готовое решение: часто правильнее изменить метку файла или включить переключатель (boolean), а не добавлять разрешение.
Часто отказ вызван не отсутствием правила, а неправильной меткой файла. Проверьте, какая метка должна быть, и исправьте её:
matchpathcon /var/www/html # какая метка должна быть restorecon -Rv /var/www/html # переразметить по правилам политики
Полная переразметка диска из работающей системы:
fixfiles -F onboot
Перевод в enforcing
Задача: включить блокирующий режим после того как сервер поработает в permissive без отказов.
sed -i "s/^SELINUX=.*/SELINUX=enforcing/" /etc/selinux/config reboot
getenforce
Результат:
Enforcing
Временное переключение без перезагрузки (до следующей загрузки):
setenforce 0 # permissive setenforce 1 # enforcing
Дальнейшие разделы можно выполнять уже в enforcing: примеры подобраны так, чтобы отказов не было.
Примеры
Примеры независимы друг от друга: выбирайте те, что соответствуют вашим задачам. Признак правильной работы во всех примерах один и тот же: служба отвечает, процесс выполняется в собственном домене SELinux (ps -eZ), а ausearch -m avc -ts recent не находит отказов.
Веб-сервер Apache HTTPD
Задача: запустить Apache HTTPD под SELinux и убедиться, что он работает в собственном домене.
dnf install apache systemctl enable --now httpd
systemctl is-active httpd
Результат:
active
Проверьте, что веб-сервер работает.
curl -fsS -o /dev/null -w "%{http_code}\n" http://127.0.0.1/
Результат:
200
Убедитесь, что процесс выполняется в собственном домене:
ps -eZ | grep httpd | head -1
Результат:
system_u:system_r:httpd_t:s0 httpd
Проверьте, что журнал аудита пуст:
ausearch -m avc -ts recent | grep -c denied
Результат:
0
Процесс выполняется в домене httpd_t — служба изолирована: её файлы (httpd_config_t, httpd_log_t), порты и права отделены от остальных служб. Журнал аудита пуст (последний результат: 0).
Angie
Задача: убедиться, что веб-сервер angie (форк nginx) изолируется так же, как nginx.
dnf install angie systemctl start angie
Примечание. Apache, nginx и angie слушают порт 80 по умолчанию — на одном узле обычно работает что-то одно. Если Apache уже запущен, остановите его (systemctl stop httpd) перед запуском angie.
systemctl is-active angie
Результат:
active
Проверьте, что веб-сервер работает.
curl -fsS -o /dev/null -w "%{http_code}\n" http://127.0.0.1/
Результат:
200
Убедитесь, что процесс выполняется в собственном домене:
ps -eZ | grep angie
Результат:
system_u:system_r:httpd_t:s0 angie
Проверьте метку файла идентификатора процесса:
ls -Z /run/angie.pid
Результат:
system_u:object_r:httpd_var_run_t:s0 /run/angie.pid
Angie размечается теми же типами httpd_*, что и nginx, и работает в домене httpd_t. Файл идентификатора процесса получает штатный тип httpd_var_run_t.
PostgreSQL 18
Задача: развернуть СУБД PostgreSQL 18 и проверить запрос.
dnf install postgresql18-server systemctl enable --now postgresql18
Первый запуск создаёт кластер баз данных автоматически (сценарий postgresql_initdb.sh из юнита). Проверка:
systemctl is-active postgresql18
Результат:
active
Убедитесь, что процесс выполняется в собственном домене:
ps -eZ | grep postgres | head -1
Результат:
system_u:system_r:postgresql_t:s0 postgres
Выполните тестовый запрос:
sudo -u postgres psql -c "select version();"
Результат:
PostgreSQL 18.6 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 14.3.0 20250505 (ROSA), 64-bit
СУБД работает в домене postgresql_t; данные в /var/lib/postgresql18/data размечены типом postgresql_db_t. Бинарные файлы находятся в /usr/libexec/postgresql18/ (в /usr/bin — ссылки alternatives), и политика учитывает эту схему размещения.
Zabbix-агент
Задача: установить агент мониторинга и получить от него данные.
dnf install zabbix7.0-agent systemctl start zabbix-agent
ps -eZ | grep zabbix
Результат:
system_u:system_r:zabbix_agent_t:s0 zabbix_agentd
Получите версию агента встроенной утилитой:
zabbix_get -s 127.0.0.1 -k agent.version
Результат:
7.0.25
Агент работает в собственном домене zabbix_agent_t.
MariaDB и MySQL (пакет mysql-selinux)
Задача: изолировать СУБД MariaDB (или MySQL) отдельным модулем политики.
Политика MariaDB/MySQL выделяется из базовой в отдельный пакет mysql-selinux (так же поступили в Fedora и апстриме). Установите его до первого запуска СУБД, чтобы бинарные файлы сразу получили правильные метки:
dnf install mysql-selinux dnf install mariadb-server systemctl start mariadb
ls -Z /usr/sbin/mariadbd
Результат:
system_u:object_r:mysqld_exec_t:s0 /usr/sbin/mariadbd
Убедитесь, что процесс выполняется в собственном домене:
ps -eZ | grep mariadbd
Результат:
system_u:system_r:mysqld_t:s0 mariadbd
Выполните тестовый запрос:
mysql -e "select version();"
Результат:
10.5.23-MariaDB
Тот же пакет mysql-selinux работает и с MySQL: пути /usr/sbin/mysqld, /var/lib/mysql и остальные размечены одинаково.
Примечания.
- MariaDB и MySQL конфликтуют по файлам — одновременно может быть установлена только одна СУБД.
- Помимо mariadb-server, в репозитории доступны пакеты Oracle MySQL Community:
mysql-community9.4,mysql-community8.4. - Если СУБД была установлена и запускалась до установки
mysql-selinux, переразметьте её файлы:restorecon -R /usr/sbin/mariadbd /var/lib/mysql.
Контейнеры: Docker и Podman
Задача: запустить контейнерную среду выполнения под SELinux.
Для Docker и Podman установите пакет container-selinux — это отдельный модуль политики с доменами container_runtime_t (среда выполнения) и container_t (контейнер):
dnf install docker container-selinux systemctl enable --now docker
ps -eZ | grep dockerd
Результат:
system_u:system_r:container_runtime_t:s0 dockerd
Запустите первый контейнер:
docker run --rm alpine echo "привет из контейнера"
Результат:
привет из контейнера
Образы и тома контейнеров получают тип container_file_t:
docker run -d --name web -p 8080:80 httpd docker exec web ls -Z /usr/local/apache2/bin/httpd
Результат:
system_u:object_r:container_file_t:s0 /usr/local/apache2/bin/httpd
Для автоматической переразметки каталога под монтирование используйте суффикс :Z:
docker run --rm -v /srv/data:/data:Z alpine cat /data/file
Podman работает в тех же доменах:
dnf install podman podman run --rm alpine echo "привет из podman"
Примечание. Docker и Podman используют разные стеки запуска (runc/crun) и могут конфликтовать по файлам; обычно на узле выбирают одну среду. Kubernetes требует containerd в качестве среды выполнения — при установке кластера пакет docker может быть удалён как конфликтующий.
Kubernetes
Задача: поднять одноузловой кластер Kubernetes с containerd под enforcing targeted.
Установите компоненты (модуль политики уже установлен вместе с container-selinux):
dnf install kubelet kubeadm kubectl containerd
Подготовьте containerd и загрузите модуль ядра для работы сети (без него CNI flannel завершается с ошибкой):
containerd config default > /etc/containerd/config.toml sed -i "s|SystemdCgroup = false|SystemdCgroup = true|" /etc/containerd/config.toml modprobe br_netfilter echo br_netfilter > /etc/modules-load.d/br_netfilter.conf systemctl enable --now containerd kubelet
Инициализация кластера:
kubeadm init --pod-network-cidr=10.244.0.0/16
Установите сеть pod'ов и разрешите планирование pod'ов на управляющем узле:
export KUBECONFIG=/etc/kubernetes/admin.conf kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml kubectl taint node $(hostname) node-role.kubernetes.io/control-plane:NoSchedule-
Проверка:
kubectl get nodes
Результат:
NAME STATUS ROLES AGE VERSION rosa Ready control-plane 44s v1.36.4
Запустите тестовый pod и прочитайте его журнал:
kubectl run test --image=alpine --restart=Never --command -- sh -c "echo ок" kubectl logs test
Результат:
pod/test created ок
Убедитесь, что kubelet выполняется в собственном домене:
ps -eZ | grep kubelet
Результат:
system_u:system_r:kubelet_t:s0-s0:c0.c1023 kubelet
Компоненты плоскости управления (etcd, apiserver) работают в контейнерах в домене spc_t — так ведёт себя Kubernetes без явных меток SELinux в манифестах (метки MCS задаёт, например, OpenShift).
Диагностика и повседневные операции
Сводка команд:
getenforce— текущий режим;sestatus -v— состояние и метки текущих процессов;ls -Z,ps -eZ,id -Z— метки файлов, процессов, пользователя;matchpathcon путь— какой меткой путь должен быть помечен;restorecon -Rv путь— переразметить по правилам;fixfiles -F onboot— полная переразметка при следующей загрузке;semanage fcontext -l— таблица правил разметки;semanage boolean -l— переключатели политики;setsebool -P имя on— включить переключатель постоянно;semodule -l— список загруженных модулей;semanage permissive -a домен— перевести домен в permissive без изменения остальной политики (удобно для отладки одной службы).
Пример: служба пишет в нестандартный каталог. Вместо allow-правила смените метку каталога — правило переживёт переразметку:
semanage fcontext -a -t httpd_sys_content_t "/srv/www(/.*)?" restorecon -R /srv/www
Смотрите также
- Using SELinux (RHEL 9) — руководство RHEL 9; применимо к РОСА благодаря общей политике.