Источник: ROSA Wiki · Лицензия: Creative Commons Attribution · Оригинал: https://wiki.rosa.ru/index.php/SELinux.html
Это независимое зеркало и не является официальным сайтом ROSA.
Jump to content

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; применимо к РОСА благодаря общей политике.