Создание своей политики SELinux

Обновлено и опубликовано Опубликовано:

Используемые термины: SELinux, Linux.

В некоторых системах на базе Linux используется расширенная система безопасности SELinux. Процесс ее настройки или отключения описан в инструкциях Как отключить SELinux и Настройка SELinux в CentOS.

Если у нас есть свое приложение, для упрощения процесса его развертывания мы можем создать собственную политику, благодаря которой процесс настройки SELinux станет проще. Рассмотрим действия по шагам.

Данная инструкция написана с использованием статьи на Хабре.

Описание процесса

Для компиляции готовой политики нам нужно создать 2 файла:

  1. .te (Type Enforcement) — содержит описание сущностей для политики.
  2. .fc (File Context) — файл для описания доступов к каталогам.

На основе созданных файлов мы получаем политику .pp, которую можно будет установить и включить при помощи команды semodule.

После включения политики необходимо проверить работоспособность приложения и вывод утилиты audit2allow, которая позволяет понять, каких прав не хватает нашему процессу.

Приступим.

Создание файла .te

Создадим каталог, в котором будем работать и перейдем в него:

mkdir -p /opt/selinux/mypolicy

cd /opt/selinux/mypolicy

Создаем файл со следующим содержимым:

vi myapp.te

policy_module(myapp, 1.0.0)

type myapp_t;
type myapp_exec_t;
type myapp_opt_t;
type myapp_conf_t;
type myapp_log_t;
type myapp_cache_t;
type myapp_tmp_t;
type myapp_port_t;

files_config_file(myapp_conf_t)
files_type(myapp_cache_t)
files_type(myapp_opt_t)
logging_log_file(myapp_log_t)
files_tmp_file(myapp_tmp_t)
corenet_port(myapp_port_t)

application_domain(myapp_t, myapp_exec_t)
init_daemon_domain(myapp_t, myapp_exec_t)
corecmd_exec_bin(myapp_t)
libs_use_ld_so(myapp_t)
kernel_read_system_state(myapp_t)
files_rw_generic_tmp_dir(myapp_t)
sysnet_read_config(myapp_t)
dev_read_rand(myapp_t)
fs_getattr_xattr_fs(myapp_t)
sysnet_dns_name_resolve(myapp_t)
logging_search_logs(myapp_t)
logging_log_filetrans(myapp_t, myapp_log_t, file)
files_poly_member_tmp(myapp_t, myapp_tmp_t)

* содержимое файла разбито на блоки. Рассмотрим их подробнее.

Описание типов:

  • myapp_t — это будет типом процесса для нашего приложения.
  • myapp_exec_t — применяется для исполняемых файлов.
  • myapp_conf_t — разрешения для конфигурационных файлов.
  • myapp_opt_t — применим для разрешения доступа к файлам и папкам в каталоге /opt.
  • myapp_log_t — для логирования.
  • myapp_cache_t — для кэширования.
  • myapp_tmp_t — для временных файлов.
  • myapp_port_t — для сетевого порта, который использует наше приложение.

Макросы, с помощью которых мы дадим стандартные разрешения нашим типам:

  • files_config_file — дает разрешения для использования конфигурационных файлов.
  • files_type — для различных файлов. В нашем примере, это кэш.
  • logging_log_file — разрешения для log-файлов.
  • files_tmp_file — для временных файлов.
  • corenet_port — разрешение для сетевых портов.

Макросы, которые дают конкретные разрешения нашему процессу:

  • application_domain — привязываем процесс myapp_t к типу myapp_exec_t. Последнему разрешается запуск исполняемых файлов.
  • init_daemon_domain — разрешаем запуск через systemd.
  • corecmd_exec_bin — разрешаем запуск бинарных файлов из каталогов /bin, /usr/bin.
  • libs_use_ld_so — разрешаем подключение библиотек.
  • kernel_read_system_state — чтение состояния системы, например, утилизации процессора и памяти.
  • files_rw_generic_tmp_dir — разрешаем писать в каталог для временных файлов (например, /tmp).
  • sysnet_read_config — разрешаем читать конфигурационные файлы сетевых настроек.
  • dev_read_rand — получение случайных чисел.
  • fs_getattr_xattr_fs — получение атрибутов файлов.
  • sysnet_dns_name_resolve — разрешаем разрешение имен в IP-адреса с помощью DNS.
  • logging_search_logs — доступ к каталогу с логами.
  • logging_log_filetrans — указываем, что логи, создаваемые нашим процессом myapp_t будут иметь тип myapp_log_t.
  • files_poly_member_tmp — указываем, что временные файлы, создаваемые нашим процессом myapp_t будут иметь тип myapp_tmp_t.

Создание файла .fc

Создаем файл со следующим содержимым:

vi myapp.fc

/opt/myapp/myapp.sh        gen_context(system_u:object_r:myapp_exec_t)
/opt/myapp(/.*)?           gen_context(system_u:object_r:myapp_opt_t)
/etc/myapp/(.*)            gen_context(system_u:object_r:myapp_conf_t)
/opt/myapp/cache(/.*)?     gen_context(system_u:object_r:myapp_cache_t)
/opt/myapp/tmp(/.*)?       gen_context(system_u:object_r:myapp_tmp_t)
/var/log/myapp(/.*)?       gen_context(system_u:object_r:myapp_log_t)

* в данном примере мы каждому каталогу и его содержимому задаем политику установки контекста. Например, для каталога /opt/myapp/cache задается контекст myapp_cache_t, которому политиками в файле myapp.te мы разрешили писать кэш. И так далее.

Сборка политики

Для сборки политики нам нужен пакет:

yum install policycoreutils-devel

Саму сборку мы выполняем командой:

make -f /usr/share/selinux/devel/Makefile

Система найдет в текущем каталоге файлы .te и .fc и выполнит проверку со сборкой.

Мы должны увидеть что-то на подобие:

Compiling targeted myapp module
/usr/bin/checkmodule:  loading policy configuration from tmp/myapp.tmp
/usr/bin/checkmodule:  policy configuration loaded
/usr/bin/checkmodule:  writing binary representation (version 19) to tmp/myapp.mod
Creating targeted myapp.pp policy package
rm tmp/myapp.mod.fc tmp/myapp.mod

Мы увидим в нашем каталоге /opt/selinux/mypolicy файл с расширением .pp. Это и есть наша политика. Ее переносим на конечный компьютер, где хотим ее запустить и проверить.

Работа с политикой

Прежде чем закончить работу с политикой, нам нужно проверить установку и отладить ее работу. Рассмотрим процессы по-очереди.

Применение

На целевом компьютере, где должна работать наша политика вводим:

semodule -i myapp.pp

* предполагается, что мы находимся в каталоге, где лежит файл myapp.pp, иначе, прописываем к нему полный путь.

В системе появится наша политика. Посмотреть можно командой:

semodule -l | grep myapp

Мы должны увидеть что-то на подобие:

myapp    1.0.0

Применить политику можно командой:

semodule -e myapp

Для всех путей, характерных нашему приложению, мы должны сбросить политики SELinux — тогда применятся те. что указаны в политике, например:

restorecon -Rv /opt/myapp

* в данном примере мы указываем команду для сброса политик каталога /opt/myapp.
** нам нужно повторить данную команду для всех каталогов и файлов, которые использует наше приложение.

Так как в нашем примере приложение использует сетевой порт, мы должны его назначить с помощью утилиты semanage. Для этого на целевой компьютер ставим:

yum install policycoreutils-python

После можем использовать команду:

semanage port -a -t myapp_port_t -p tcp 8888

* где myapp_port_t — созданный нами тип для сетевого порта; tcp — используемый приложением сетевой протокол; 8888 — порт, который используется для прослушивания сетевых запросов.

Отладка

Не факт, что мы учли все запросы приложения. Чтобы ничего не упустить, на тестовом целевом компьютере мы включаем SELinux (если он был выключен), ждем некоторое время, тестируя приложение и после выполняем команду:

audit2allow -b -r -t myapp

Данная команда покажет все запросы, для которых у нашего процесса нет доступа. Мы увидим готовые команды, на подобие:

require {
    type unconfined_t;
    type myapp_t;
    class dir relabelto;
}

#============= unconfined_t ==============

allow unconfined_t myapp_t:dir relabelto;

... которые нам нужно отдельно использовать в политике.

Однако, решать, какие команды использовать, а какие нет нужно самостоятельно, так как не все данные запросы, действительно, нужны нашему приложению.

Например, если мы решим добавить команду в политику, то откроем наш файл .te:

vi myapp.te

Отредактируем версию, добавим require с типом и классом, а также команду, что предложила audit2allow:

policy_module(myapp, 1.0.1)

...

require {
    type unconfined_t;
    class dir relabelto;
}

...

allow unconfined_t myapp_t:dir relabelto;

* обратите внимание на require. Данная директива определяет не создание нового типа и классов, а использование тех, что есть в системе. Это важно, так как если попытаться определить тип, который уже есть в системе мы получим ошибку Re-declaration of type unconfined_t, Failed to create node.

Затем снова выполним сборку политики и повторную ее установку и применение.

# Linux # Безопасность # DevOps
Дмитрий Моск — частный мастер
Была ли полезна вам эта инструкция?

Да            Нет