- PVSM.RU - https://www.pvsm.ru -

Настройка окружения SELinux на примере LAMP-сервера

Это третья статья из цикла

Настройка окружения SELinux на примере LAMP-сервера - 1
И сегодня она попала в поток «Администрирование». Сегодня мы не будем писать модули [1] или настраивать RBAC [2], а пойдем по пути наименьшего сопротивления и просто захарденим обычный LAMP-сервер при помощи готовой политики, включив необходимые настройки.
Если кто забыл, за аббривиатурой LAMP скрывается Linux, Apache, Mysql, PHP, т.е. это большая часть всех VDS [3], которые покупают люди для хранения своих личных блогов. Надеюсь, что этот поможет всем им стать немного безопаснее :)

Предположения

Итак, предполагаем, что:
Настройка окружения SELinux на примере LAMP-сервера - 2

  1. Дистрибутив — CentOS 7 x64, пользователь — root
  2. SELinux включен, загружена политика targeted
  3. Режим SELinux — enforcing

Подготовка

Если LAMP у вас уже установлен и настроен — можете пропустить
Установим стандартный комплект софта для LAMP:
[root@lamp ~]# yum install -y httpd mariadb-server php-fpm php-mysql
Минимально настроим софт:

/etc/php-fpm.d/www.conf

[www]
listen = 127.0.0.1:9009
user = apache
group = apache
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35
pm.max_requests = 500
pm.status_path = /status
request_terminate_timeout = 10s
request_slowlog_timeout = 1s
slowlog = /var/log/php-fpm/www-slow.log
security.limit_extensions = .php
php_admin_value[error_log] = /var/log/php-fpm/www-error.log
php_admin_flag[log_errors] = on
php_admin_value[memory_limit] = 128M
php_value[session.save_handler] = files
php_value[session.save_path] = /var/lib/php/session

/etc/httpd/conf.d/userdir.conf

<IfModule mod_userdir.c>
UserDir enabled
UserDir www
</IfModule>
<Directory "/home/*/www">
AllowOverride FileInfo AuthConfig Limit Indexes
Options MultiViews Indexes
Require method GET POST OPTIONS
DirectoryIndex index.html index.htm index.php
<FilesMatch ".php$">
<If "-f %{REQUEST_FILENAME}">
SetHandler "proxy:fcgi://127.0.0.1:9009"
</If>
</FilesMatch>
</Directory>

Запустим все необходимые сервисы:
[root@lamp ~]# systemctl enable httpd mariadb php-fpm
[root@lamp ~]# systemctl start httpd mariadb php-fpm
Добавим какого-нибудь пользователя, например phpbb:
[root@lamp ~]# useradd -Z user_u -m -g apache phpbb
[root@lamp ~]# chmod 750 /home/phpbb

И создадим простой тестовый файл с phpinfo():
[phpbb@lamp ~]$ mkdir www
[phpbb@lamp ~]$ echo "<?php phpinfo(); ?>" > www/info.php
Перейдем по ссылке…
Настройка окружения SELinux на примере LAMP-сервера - 3
… и получим именно то, что получают все :)

Разбираемся с ошибками

В отличие от других мануалов, где следующим шагом идет «отключите SELinux», мы сейчас узнаем, почему так получилось и что можно сделать.
Для начала — установим консольные утилиты для управления политиками SELinux:
[root@lamp ~]# yum install -y policycoreutils-python policycoreutils-newrole policycoreutils-restorecond setools-console
А потом — включим нужные нам модули ( командой semodule ):
[root@lamp ~]# semodule -e apache
[root@lamp ~]# semodule -e mysql
Давайте посмотрим, с какими именно проблемами столкнулся apache при открытии этой страницы?

audit2allow -lb -t httpd_t

#============= httpd_t ==============
#!!! This avc can be allowed using one of the these booleans:
# httpd_enable_homedirs, httpd_read_user_content, httpd_unified
allow httpd_t httpd_user_content_t:file getattr;

Все верно: папка www ( а так-же папки web и public_html ) внутри домашней директории пользователя автоматически получает тип httpd_user_content_t, что и указано в правилах:

sesearch -T -s user_t -c dir -d


type_transition user_t user_home_dir_t: dir httpd_user_content_t «public_html»;
type_transition user_t user_home_dir_t: dir httpd_user_content_t «www»;
type_transition user_t user_home_dir_t: dir httpd_user_content_t «web»;

Лечение указано в выводе audit2allow, установка переменных выполняется командой setsebool ( или semanage boolean ).
[root@lamp httpd]# setsebool -P httpd_read_user_content=1
Обновляем страницу и получаем:
Настройка окружения SELinux на примере LAMP-сервера - 4
Смотрим логи:

/var/log/httpd/error_log

[Tue Feb 28 21:15:04.555595 2017] [proxy:error] [pid 21586] (13)Permission denied: AH00957: FCGI: attempt to connect to 127.0.0.1:9009 (*) failed
[Tue Feb 28 21:15:04.555892 2017] [proxy_fcgi:error] [pid 21586] [client 192.168.56.101:57974] AH01079: failed to make connection to backend: 127.0.0.1

Все ясно: httpd не может коннектиться куда попало, httpd может ходить только куда нужно. Это логично: если веб-сервер вдруг соединяется по ssh, то явно происходит что-то странное.
Давайте посмотрим, куда веб-серверу ходить можно?

sesearch -A -s httpd_t -c tcp_socket -p name_connect -d -C

DT allow httpd_t port_type: tcp_socket name_connect; [ httpd_can_network_connect ]
DT allow httpd_t mythtv_port_t: tcp_socket name_connect; [ httpd_can_connect_mythtv ]
DT allow httpd_t zabbix_port_t: tcp_socket name_connect; [ httpd_can_connect_zabbix ]
DT allow httpd_t smtp_port_t: tcp_socket name_connect; [ httpd_can_sendmail ]
DT allow httpd_t mssql_port_t: tcp_socket name_connect; [ httpd_can_network_connect_db ]
DT allow httpd_t postgresql_port_t: tcp_socket name_connect; [ httpd_can_network_connect_db ]
ET allow httpd_t ocsp_port_t: tcp_socket name_connect; [ kerberos_enabled ]
DT allow httpd_t oracle_port_t: tcp_socket name_connect; [ httpd_can_network_connect_db ]
DT allow httpd_t gopher_port_t: tcp_socket name_connect; [ httpd_can_network_relay ]
DT allow httpd_t osapi_compute_port_t: tcp_socket name_connect; [ httpd_use_openstack ]
DT allow httpd_t mongod_port_t: tcp_socket name_connect; [ httpd_can_network_connect_db ]
DT allow httpd_t memcache_port_t: tcp_socket name_connect; [ httpd_can_network_relay ]
DT allow httpd_t memcache_port_t: tcp_socket name_connect; [ httpd_can_network_memcache ]
DT allow httpd_t http_cache_port_t: tcp_socket name_connect; [ httpd_can_network_relay ]
DT allow httpd_t cobbler_port_t: tcp_socket name_connect; [ httpd_can_network_connect_cobbler ]
DT allow httpd_t ftp_port_t: tcp_socket name_connect; [ httpd_can_connect_ftp ]
DT allow httpd_t ftp_port_t: tcp_socket name_connect; [ httpd_can_network_relay ]
DT allow httpd_t gds_db_port_t: tcp_socket name_connect; [ httpd_can_network_connect_db ]
DT allow httpd_t pop_port_t: tcp_socket name_connect; [ httpd_can_sendmail ]
DT allow httpd_t http_port_t: tcp_socket name_connect; [ httpd_can_network_relay ]
ET allow httpd_t http_port_t: tcp_socket name_connect; [ httpd_graceful_shutdown ]
ET allow httpd_t kerberos_port_t: tcp_socket name_connect; [ kerberos_enabled ]
DT allow httpd_t ldap_port_t: tcp_socket name_connect; [ httpd_can_connect_ldap ]
DT allow httpd_t ephemeral_port_type: tcp_socket name_connect; [ httpd_use_openstack ]
DT allow httpd_t ephemeral_port_type: tcp_socket name_connect; [ httpd_can_connect_ftp ]
DT allow httpd_t ephemeral_port_type: tcp_socket name_connect; [ httpd_can_network_relay ]
DT allow httpd_t squid_port_t: tcp_socket name_connect; [ httpd_can_network_relay ]
DT allow httpd_t mysqld_port_t: tcp_socket name_connect; [ httpd_can_network_connect_db ]

В квадратных скобках указаны переменные, которые отвечают за работу этого правила.
Итого: нужно добавить порт 9009 в один из типов, к которым разрешен коннект, а затем установить переменную httpd_can_network_relay в 1.
Новый порт добавляется при помощи команды semanage port:
[root@lamp httpd]# semanage port -a -t http_cache_port_t -p tcp 9009
[root@lamp httpd]# setsebool -P httpd_can_network_relay=1
Обновляем страницу и видим:
Настройка окружения SELinux на примере LAMP-сервера - 5

Что-то посложнее

Давайте теперь усложним задачу и поставим phpbb на этот хост.

установка phpBB 3.2.0

[phpbb@lamp ~]$ curl www.phpbb.com/files/release/phpBB-3.2.0.zip [4] -O
[phpbb@lamp ~]$ unzip phpBB-3.2.0.zip
[phpbb@lamp ~]$ mv phpBB3/* www/
[phpbb@lamp ~]$ restorecon -R www/

Попробуем создать для себя базу:
[phpbb@lamp www]$ mysql -uroot
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (13)
Поищем, как разрешить пользователю соединяться с базой?

sesearch -R -A -s user_t -t mysql -C -d

DT allow user_t mysqld_var_run_t: dir { getattr search open }; [ selinuxuser_mysql_connect_enabled ]
DT allow user_t mysqld_db_t: dir { getattr search open }; [ selinuxuser_mysql_connect_enabled ]
DT allow user_t mysqld_t: unix_stream_socket connectto; [ selinuxuser_mysql_connect_enabled ]
DT allow user_t mysqld_t: unix_stream_socket connectto; [ selinuxuser_mysql_connect_enabled ]
DT allow user_t mysqld_var_run_t: sock_file { write getattr append open }; [ selinuxuser_mysql_connect_enabled ]
DT allow user_t mysqld_var_run_t: sock_file { write getattr append open }; [ selinuxuser_mysql_connect_enabled ]

Отлично, включаем selinuxuser_mysql_connect_enabled и продолжаем:
[root@lamp httpd]# setsebool -P selinuxuser_mysql_connect_enabled=1

Создаем базу и пробуем зайти в инсталляшку phpbb:
Настройка окружения SELinux на примере LAMP-сервера - 6
Почему так? Потому что httpd не может изменять пользовательские данные. Давайте узнаем, какие же он изменять может?

sesearch -A -s httpd_t -p write -t user -C -R -d

ET allow httpd_t httpd_user_rw_content_t: file { ioctl read write create getattr setattr lock append unlink link rename open }; [ httpd_builtin_scripting ]
ET allow httpd_t httpd_user_ra_content_t: dir { ioctl write getattr lock add_name search open }; [ httpd_builtin_scripting ]
ET allow httpd_t httpd_user_ra_content_t: dir { ioctl write getattr lock add_name search open }; [ httpd_builtin_scripting ]
ET allow httpd_t httpd_user_rw_content_t: dir { ioctl read write getattr lock add_name remove_name search open }; [ httpd_builtin_scripting ]
ET allow httpd_t httpd_user_rw_content_t: dir { ioctl read write getattr lock add_name remove_name search open }; [ httpd_builtin_scripting ]
ET allow httpd_t httpd_user_rw_content_t: dir { ioctl read write create getattr setattr lock unlink link rename add_name remove_name reparent search rmdir open }; [ httpd_builtin_scripting ]
ET allow httpd_t httpd_user_rw_content_t: dir { ioctl read write getattr lock add_name remove_name search open }; [ httpd_builtin_scripting ]
DT allow httpd_t user_tty_device_t: chr_file { ioctl read write getattr lock append }; [ httpd_tty_comm ]
ET allow httpd_t httpd_user_rw_content_t: sock_file { read write getattr append open }; [ httpd_builtin_scripting ]
DT allow httpd_t user_devpts_t: chr_file { ioctl read write getattr lock append }; [ httpd_tty_comm ]
ET allow httpd_t httpd_user_rw_content_t: lnk_file { ioctl read write create getattr setattr lock append unlink link rename }; [ httpd_builtin_scripting ]

Устанавливаем php-xml, включаем httpd_builtin_scripting и назначаем контекст httpd_user_rw_content_t на указанные файлы и папки ( командой chcon ):
[root@lamp httpd]# setsebool -P httpd_builtin_scripting=1
[phpbb@lamp www]$ chmod 660 config.php
[phpbb@lamp www]$ chcon -t httpd_user_rw_content_t cache/ store/ files/ config.php images/avatars/upload/
Получаем:
Настройка окружения SELinux на примере LAMP-сервера - 7
Устанавливаем phpBB дальше, удаляем install и получаем работающий форум:
Настройка окружения SELinux на примере LAMP-сервера - 8
Меняем контекст конфига обратно:
[phpbb@lamp www]$ chcon -t httpd_user_content_t config.php
Наслаждаемся безопасным форумом :)

Вместо послесловия

Не написав ни одной строчки кода, используя только знания из man-файлов и стандартную политику SELinux по-умолчанию, можно за 30 минут настроить безопасное окружения для стандартных сервисов. И это не только про LAMP: стандартная политика содержит 403 готовых модуля. Этого хватит для решения большинства задач, которые когда-либо встанут перед администратором. Не выключайте SELinux, не заставляйте Дэна плакать [5].

Бонус #1

Для тех, кто все это таки прочел — готовый образ из статьи.
Ссылка: ufile.io/5eced [6] ( 846 Mb ) ( ссылка истечет 29.03.2017 )

Пароли

root:root
phpbb:phpbb
mysql root:root
mysql phpbb:i6p0AYF1B4Hg
phpbb: kreon:kreon1

Бонус #2

Небольшой cheatsheet.
Команды

  • semodule — управляет списком модулей
  • sestatus — текущий статус SELinux
  • setenforce 1/0 — включить/выключить enforcing
  • audit2allow — утилита для генерации правил ( и для подсказок )
  • sesearch — утилита для поиска правил в политике
  • seinfo — показывает информацию о типах, ролях, атрибутах итд
  • semanage — позволяет вносить изменения в политики
  • chcon — позволяет менять контекст на ФС
  • restorecon — востанавливает контекст по-умолчанию
  • setsebool — устанавливает переменную в on/off. С -P — пишет на диск
  • getsebool — получает переменную. -a — посмотреть все

Изменения политики

  • semanage port -a/-d -t httpd_port_t -p tcp 8044 — добавить/удалить номер порта к контексту
  • semanage fcontext -a/-d -t httpd_cache_t "/srv/http/cache(/.*)?" — добавить/удалить контекст для этой маски
  • semanage permissive -a/-d httpd_t — включить/выключить режим permissive для httpd_t

Аргументы к командам

  • id -Z — показывает контекст текущего пользователя
  • ls -Z — показывает контекст файлов
  • ps -Z — показывает контекст процессов
  • netstat -Z — показывает контекст соединений
  • usermod/useradd -Z связать пользователя с SELinux-пользователем
  • ausearch -m AVC — показывает нарушения политик

Автор: kreon

Источник [7]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/linux/246996

Ссылки в тексте:

[1] писать модули: https://habrahabr.ru/post/320100/

[2] настраивать RBAC: https://habrahabr.ru/post/322476/

[3] VDS: https://www.reg.ru/?rlink=reflink-717

[4] www.phpbb.com/files/release/phpBB-3.2.0.zip: https://www.phpbb.com/files/release/phpBB-3.2.0.zip

[5] не заставляйте Дэна плакать: https://stopdisablingselinux.com/

[6] ufile.io/5eced: https://ufile.io/5eced

[7] Источник: https://habrahabr.ru/post/322904/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best