ISPmanager и selinux
Материал из ISPWiki
Содержание |
Используемое программное обеспечение
- Centos 5.3
- ISPmanager-Pro 4.3.32. - .34
Вступление
После некоторой пляски удалось их подружить, обеспечив тем самым неплохую изоляцию клиентского хостинга от сервера. Если за счет дыры в скриптах пользовательских сайтов злоумышленник сможет запихать на сервер эксплойт, и даже повысить привилегии до рута - все равно он останется в контексте вебсервера и будет сильно ограничен в своих действиях.
Основная идея, которая легла в основу метода: надо поднять два httpd, один для ispmgr, другой для клиентов хостинга. В качестве побочного эффекта - очень полезная фича: возможные ошибки в конфиге клиентского апача не пытаются уронить ispmanager. Клиентский апач работает в стандартном контексте selinux, а для апача ispmgr написан модуль, который запускает его в unconfined_c, тем самым фактически отключая для него selinux.
Создание модуля selinux для ispmgr
Эти действия можно (и желательно) делать не на той машине, где будет развернут хостинг. Для сборки модуля требуется та же версия дистрибутива, что будет стоять на хостинге. Если действия будут выполняться на той же машине, что и хостинг, то предварительно потребуется включить selinux и восстановить атрибуты (см следующее сообщение).
yum install selinux-policy-devel.noarch policycoreutils mkdir ~/policy cd ~/policy
Cоздаем в этом каталоге следующие файлы: ispmgr.fc ispmgr.if ispmgr.te
ispmgr.fc
/usr/sbin/httpd_ispmgr -- gen_context(system_u:object_r:ispmgr_exec_t,s0) /usr/sbin/httpd_ispmgr.worker -- gen_context(system_u:object_r:ispmgr_exec_t,s0)
ispmgr.if
######################################## ## <summary> ## Execute a domain transition to run ispmgr. ## </summary>
interface(`ispmgr_domtrans',`
gen_require(`
type ispmgr_t, ispmgr_exec_t;
')
domain_auto_trans($1,ispmgr_exec_t,unconfined_t)
allow $1 ispmgr_t:fd use;
allow ispmgr_t $1:fd use;
allow $1 ispmgr_t:fifo_file rw_file_perms;
allow $1 ispmgr_t:process sigchld;
')
ispmgr.te
policy_module(ispmgr,1.0.5) type ispmgr_t; type ispmgr_exec_t;
require {
type initrc_t;
type unconfined_t;
}
domain_type(ispmgr_t) domain_entry_file(ispmgr_t, ispmgr_exec_t)
ispmgr_domtrans(initrc_t)
Компиляция
Выполняем команду make
make -f /usr/share/selinux/devel/Makefile Compiling targeted ispmgr module /usr/bin/checkmodule: loading policy configuration from tmp/ispmgr.tmp /usr/bin/checkmodule: policy configuration loaded /usr/bin/checkmodule: writing binary representation (version 6) to tmp/ispmgr.mod Creating targeted ispmgr.pp policy package rm tmp/ispmgr.mod.fc tmp/ispmgr.mod
Загрузка модуля
Если все прошло успешно, должен появиться файл ispmgr.pp Если что-то пошло не так, перед повторным запуском make удаляем подкаталог tmp и файл ispmgr.pp
Пробуем загрузить собранный модуль и убеждаемся, что он появился в списке загруженных
semodule -i ispmgr.pp semodule -l
Если мы собирали модуль там же, где развернут хостинг, то удаляем пакет selinux-policy-devel.noarch
Активация selinux и установка модуля
Дальнейшие действия выполняются на машинах с развернутым ispmgr
Включаем selinux в режим permissive и восстанавливаем атрибуты файлов, т.к. инсталляция ispmgr при выключенном selinux их не устанавливала
В /etc/selinux/config прописываем SELINUX=permissive
touch /.autorelabel shutdown -rf now
Перезагрузка займет значительное время, которое зависит от количества файлов на диске.
yum install policycoreutils
Если мы собирали модуль не на той машине, где будет развернут хостинг, копируем модуль ispmgr.pp, загружаем его и убеждаемся в наличии модуля:
semodule -i ispmgr.pp semodule -l
Создание клона httpd
cp -ax /usr/sbin/httpd /usr/sbin/httpd_ispmgr cp -ax /usr/sbin/httpd.worker /usr/sbin/httpd_ispmgr.worker
Устанавливаем контекст и убеждаемся, что это именно ispmgr_exec_t
restorecon -F /usr/sbin/httpd_ispmgr /usr/sbin/httpd_ispmgr.worker ls -lZ /usr/sbin/httpd_ispmgr /usr/sbin/httpd_ispmgr.worker
Если контекст будет иным, разбираемся, что с нашим ispmgr.pp
Разбираемся с логами:
mkdir /var/log/httpd_ispmgr chmod 700 /var/log/httpd_ispmgr cd /etc/httpd ln -s ../../var/log/httpd_ispmgr logs_ispmgr
Далее клонируем конфиги, каталоги и стартап-скрипты. Я буду приводить отличия от оригинала. cp -ax /usr/sbin/apachectl /usr/sbin/apachectl_ispmgr
diff -u /usr/sbin/apachectl /usr/sbin/apachectl_ispmgr
--- /usr/sbin/apachectl 2009-07-14 14:03:18.000000000 +0400 +++ /usr/sbin/apachectl_ispmgr 2009-10-19 07:34:44.000000000 +0400 @@ -41,7 +41,7 @@ # -------------------- -------------------- # # the path to your httpd binary, including options if necessary -HTTPD='/usr/sbin/httpd' +HTTPD='/usr/sbin/httpd_ispmgr' # # # a command that outputs a formatted text version of the HTML at the @@ -58,8 +58,8 @@ STATUSURL="http://localhost:80/server-status" # Source /etc/sysconfig/httpd for $HTTPD setting, etc. -if [ -r /etc/sysconfig/httpd ]; then - . /etc/sysconfig/httpd +if [ -r /etc/sysconfig/httpd_ispmgr ]; then + . /etc/sysconfig/httpd_ispmgr fi #
При желании в обоих приведенных выше файлах стоит подправить строку STATUSURL="http://localhost:80/server-status" в соответствии с реалиями каждого из серверов.
cp -ax /etc/rc.d/init.d/httpd /etc/rc.d/init.d/httpd_ispmgr
diff -u /etc/rc.d/init.d/httpd /etc/rc.d/init.d/httpd_ispmgr
--- /etc/rc.d/init.d/httpd 2009-07-14 14:08:09.000000000 +0400
+++ /etc/rc.d/init.d/httpd_ispmgr 2009-10-19 07:18:30.000000000 +0400
@@ -5,16 +5,16 @@
# chkconfig: - 85 15
# description: Apache is a World Wide Web server. It is used to serve \
# HTML files and CGI.
-# processname: httpd
-# config: /etc/httpd/conf/httpd.conf
-# config: /etc/sysconfig/httpd
-# pidfile: /var/run/httpd.pid
+# processname: httpd_ispmgr
+# config: /etc/httpd/conf/httpd_ispmgr.conf
+# config: /etc/sysconfig/httpd_ispmgr
+# pidfile: /var/run/httpd_ispmgr.pid
# Source function library.
. /etc/rc.d/init.d/functions
-if [ -f /etc/sysconfig/httpd ]; then
- . /etc/sysconfig/httpd
+if [ -f /etc/sysconfig/httpd_ispmgr ]; then
+ . /etc/sysconfig/httpd_ispmgr
fi
# Start httpd in the C locale by default.
@@ -30,15 +30,15 @@
# Path to the apachectl script, server binary, and short-form for messages.
apachectl=/usr/sbin/apachectl
-httpd=${HTTPD-/usr/sbin/httpd}
-prog=httpd
-pidfile=${PIDFILE-/var/run/httpd.pid}
-lockfile=${LOCKFILE-/var/lock/subsys/httpd}
+httpd=${HTTPD-/usr/sbin/httpd_ispmgr}
+prog=httpd_ispmgr
+pidfile=${PIDFILE-/var/run/httpd_ispmgr.pid}
+lockfile=${LOCKFILE-/var/lock/subsys/httpd_ispmgr}
RETVAL=0
# check for 1.3 configuration
check13 () {
- CONFFILE=/etc/httpd/conf/httpd.conf
+ CONFFILE=/etc/httpd/conf/httpd_ispmgr.conf
GONE="(ServerType|BindAddress|Port|AddModule|ClearModuleList|"
GONE="${GONE}AgentLog|RefererLog|RefererIgnore|FancyIndexing|"
GONE="${GONE}AccessConfig|ResourceConfig)"
cp -ax /etc/sysconfig/httpd /etc/sysconfig/httpd_ispmgr
diff -u /etc/sysconfig/httpd /etc/sysconfig/httpd_ispmgr
--- /etc/sysconfig/httpd 2009-07-14 14:08:09.000000000 +0400 +++ /etc/sysconfig/httpd_ispmgr 2009-10-19 07:39:15.000000000 +0400 @@ -6,13 +6,13 @@ # available, but does not work with some modules (such as PHP). # The service must be stopped before changing this variable. # -#HTTPD=/usr/sbin/httpd.worker +#HTTPD=/usr/sbin/httpd_ispmgr.worker # # To pass additional options (for instance, -D definitions) to the # httpd binary at startup, set OPTIONS here. # -#OPTIONS= +OPTIONS="-f conf/httpd_ispmgr.conf" # # By default, the httpd process is started in the C locale; to
cp -ax /etc/httpd/conf.d/ssl.conf /etc/httpd/conf.d/ssl.conf_ispmgr mv /etc/httpd/conf.d/ssl.conf /etc/httpd/conf.d/ssl.conf_others
diff -u /etc/httpd/conf.d/ssl.conf_others /etc/httpd/conf.d/ssl.conf_ispmgr
--- /etc/httpd/conf.d/ssl.conf_others 2009-12-10 06:00:30.000000000 +0300
+++ /etc/httpd/conf.d/ssl.conf_ispmgr 2009-11-28 02:39:26.000000000 +0300
@@ -15,10 +15,7 @@
# When we also provide SSL we have to listen to the
# the HTTPS port in addition.
#
-Listen 192.168.8.69:443
-Listen 123.456.78.202:443
-Listen 123.456.78.203:443
-Listen 123.456.78.204:443
+Listen 123.456.78.198:443
##
## SSL Global Context
@@ -89,8 +86,8 @@
# Use separate log files for the SSL virtual host; note that LogLevel
# is not inherited from httpd.conf.
-ErrorLog logs/ssl_error_log
-TransferLog logs/ssl_access_log
+ErrorLog logs_ispmgr/ssl_error_log
+TransferLog logs_ispmgr/ssl_access_log
LogLevel warn
# SSL Engine Switch:
@@ -225,7 +222,7 @@
# Per-Server Logging:
# The home of a custom SSL log file. Use this when you want a
# compact non-error SSL logfile on a virtual host basis.
-CustomLog logs/ssl_request_log \
+CustomLog logs_ispmgr/ssl_request_log \
"%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"
</VirtualHost>
Директиву Listen нужно править в обоих файлах в соответствии с вашими реалиями. Я вынес ispmgr на тот ip, на котором висит лицензия, а остальные отдал под пользовательский апач.
cp -ax /etc/httpd/conf/httpd.conf /etc/httpd/conf/httpd_ispmgr.conf
diff -U 1 /etc/httpd/conf/httpd.conf /etc/httpd/conf/httpd_ispmgr.conf
--- /etc/httpd/conf/httpd.conf 2009-12-10 05:59:52.000000000 +0300
+++ /etc/httpd/conf/httpd_ispmgr.conf 2009-11-28 02:39:05.000000000 +0300
@@ -27,5 +27,5 @@
# server will use that explicit path. If the filenames do *not* begin
-# with "/", the value of ServerRoot is prepended -- so "logs/foo.log"
+# with "/", the value of ServerRoot is prepended -- so "logs_ispmgr/foo.log"
# with ServerRoot set to "/etc/httpd" will be interpreted by the
-# server as "/etc/httpd/logs/foo.log".
+# server as "/etc/httpd/logs_ispmgr/foo.log".
#
@@ -62,3 +62,3 @@
#
-PidFile run/httpd.pid
+PidFile run/httpd_ispmgr.pid
@@ -133,6 +133,3 @@
#Listen 12.34.56.78:80
-Listen 192.168.8.69:80
-Listen 123.456.78.202:80
-Listen 123.456.78.203:80
-Listen 123.456.78.204:80
+Listen 123.456.78.198:80
@@ -213,3 +210,3 @@
Include conf.d/*.conf
-Include conf.d/*.conf_others
+Include conf.d/*.conf_ispmgr
@@ -475,3 +472,3 @@
#
-ErrorLog logs/error_log
+ErrorLog logs_ispmgr/error_log
@@ -504,3 +501,3 @@
#
-#CustomLog logs/access_log common
+#CustomLog logs_ispmgr/access_log common
@@ -510,4 +507,4 @@
#
-#CustomLog logs/referer_log referer
-#CustomLog logs/agent_log agent
+#CustomLog logs_ispmgr/referer_log referer
+#CustomLog logs_ispmgr/agent_log agent
@@ -517,3 +514,3 @@
#
-CustomLog logs/access_log combined
+CustomLog logs_ispmgr/access_log combined
@@ -854,6 +851,2 @@
</Directory>
-<Directory /var/www/u1/data/www/r.isptest.mns.ru>
- php_admin_value open_basedir "/var/www/u1/data:."
- Options +ExecCGI
-</Directory>
@@ -996,47 +989,6 @@
# ServerName dummy-host.example.com
-# ErrorLog logs/dummy-host.example.com-error_log
-# CustomLog logs/dummy-host.example.com-access_log common
+# ErrorLog logs_ispmgr/dummy-host.example.com-error_log
+# CustomLog logs_ispmgr/dummy-host.example.com-access_log common
#</VirtualHost>
Опять-таки редактируем Listen в обоих файлах в соответствии с реалиями вашего хостинга. Вносим остальные нужные нам настройки (SSL-сертификаты ISPmanager и прочее) Перезапускаем пользовательский апач, чтобы освободить *.80 и *.443
service httpd restart
Включаем вебсервер панели в rcX.d и запускаем его:
chkconfig httpd_ispmgr --add chkconfig httpd_ispmgr on service httpd_ispmgr start
Если вы ничего не напутали, и самое главное, если я ничего не забыл, то должны запуститься оба апача, пользовательский в домене httpd_t и панельный в unconfined_t. Проверим это:
ps -Chttpd_ispmgr -Chttpd -Z
root:system_r:httpd_t 23592 ? 00:00:00 httpd root:system_r:httpd_t 23593 ? 00:00:00 httpd root:system_r:httpd_t 23594 ? 00:00:00 httpd root:system_r:httpd_t 23595 ? 00:00:00 httpd root:system_r:httpd_t 23596 ? 00:00:00 httpd root:system_r:httpd_t 23597 ? 00:00:00 httpd root:system_r:httpd_t 23598 ? 00:00:00 httpd root:system_r:httpd_t 23599 ? 00:00:00 httpd root:system_r:httpd_t 2455 ? 00:00:01 httpd root:system_r:httpd_t 30644 ? 00:00:00 httpd system_u:system_r:unconfined_t 2235 ? 00:00:01 httpd_ispmgr system_u:system_r:unconfined_t 23602 ? 00:00:00 httpd_ispmgr system_u:system_r:unconfined_t 23603 ? 00:00:00 httpd_ispmgr system_u:system_r:unconfined_t 23604 ? 00:00:00 httpd_ispmgr system_u:system_r:unconfined_t 23605 ? 00:00:00 httpd_ispmgr system_u:system_r:unconfined_t 23606 ? 00:00:00 httpd_ispmgr system_u:system_r:unconfined_t 23607 ? 00:00:00 httpd_ispmgr system_u:system_r:unconfined_t 23608 ? 00:00:00 httpd_ispmgr system_u:system_r:unconfined_t 23617 ? 00:00:00 httpd_ispmgr
Послесловие
Уфф. Основная работа сделана!
Включаем selinux в режим Enforced и перегружаемся. Не используем setenforce! Перезагрузка нужна, т.к. процессы получают контекст в момент создания, и перезапускать их все вручную неудобно.
Редактируем /etc/selinux/config SELINUX=enforcing и перезагружаемся.
Если все ожило нормально, остается только поправить по месту правила selinux для стандартных сервисов, вписать нестандартные директории в файловый контекст, установить selinux booleans и т п. Если вы не знаете, как этим пользоваться, то обратитесь к соответствующим разделам руководств. Я приведу список команд и один файл, который вам надо будет создать. Погуглите или почитайте руководства.
Свой файловый контекст вписываем сюда:
/etc/selinux/targeted/contexts/files/file_contexts.local
Примеры, как это сделать, можно взять тут:
/etc/selinux/targeted/contexts/files/file_contexts
Список полезных команд:
getsebool setsebool getenforce setenforce audit2allow audit2who checkmodule semodule_package semodule
Алгоритм дальнейшей работы, в общих чертах, таков:
- переходим в permissive
- перезапускаем проблемный сервис
- даем ему сделать то, что он хочет
- смотрим, что он накидал в audit log
- пропускаем его через audit2allow и получаем шаблон модуля
- творчески анализируем полученный шаблон и думаем, надо ли пускать сервис куда не надо, редактируем шаблон и file_contexts.local
- собираем и грузим модуль
- устанавливаем правильный контекст у того, что мы вписали в file_contexts.local
- переходим в enforced
- перезапускаем проблемный сервис и проверяем его работу
WBR, Vadim Shkolin, vadim аt vsh.spb.su
