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

Thank you for reading this post, don't forget to subscribe!

Если у нас есть свое при­ло­же­ние, для упро­ще­ния про­цес­са его раз­вер­ты­ва­ния мы можем создать соб­ствен­ную поли­ти­ку, бла­го­да­ря кото­рой про­цесс настрой­ки 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

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

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

  • 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

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

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

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

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

yum install policycoreutils-devel

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

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

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

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

Мы уви­дим в нашем ката­ло­ге /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

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

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

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

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

vi myapp.te

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

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

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