Я пытаюсь настроить несколько экземпляров php-fpm для запуска нескольких версий php через apache 2.2, работающих на centos 6.5.
В какой-то момент в будущем это окажется в среде общего хостинга, поэтому мне нужна максимально возможная безопасность.
Поэтому я стараюсь вообще не отключать selinux и стараюсь установить как можно более узкие политики.
Я относительно новичок в selinux (на наших существующих серверах он просто отключен). Я много читал по этой теме, но логика все еще ускользает от меня (как я уверен, этот вопрос показывает).
При вызове php-скрипта apache выдает такую ошибку:
[Sun May 18 10:46:17 2014] [error] [client 192.168.163.1] (13)Permission denied: FastCGI: failed to connect to server "/fcgi-bin-php5-fpm-i10000_test-1.testtest.org": connect() failed
[Sun May 18 10:46:17 2014] [error] [client 192.168.163.1] FastCGI: incomplete headers (0 bytes) received from server "/fcgi-bin-php5-fpm-i10000_test-1.testtest.org"
Каталог, содержащий сокеты php-fpm, выглядит так:
drwxr-xr-x. root root system_u:object_r:var_run_t:s0 .
drwxr-xr-x. root root system_u:object_r:var_run_t:s0 ..
srw-------. apache apache unconfined_u:object_r:var_run_t:s0 apache_default.sock
srw-------. apache apache unconfined_u:object_r:var_run_t:s0 i10000_test-1.testtest.org.sock
srw-------. apache apache unconfined_u:object_r:var_run_t:s0 i10000_test-2.testtest.org.sock
srw-------. apache apache unconfined_u:object_r:var_run_t:s0 i10000_test-3.testtest.org.sock
-rw-r--r--. root root unconfined_u:object_r:var_run_t:s0 php-fpm-5.3.pid
-rw-r--r--. root root unconfined_u:object_r:initrc_var_run_t:s0 php-fpm.pid
Исходя из этого, я бы предположил, что тип розеток был var_run_t
...
Итак, я пытаюсь использовать эту политику:
policy_module(httpd_php_fpm, 1.0)
require {
type unconfined_t;
type var_run_t;
type httpd_t;
type httpd_sys_content_t;
class sock_file write;
}
#============= httpd_t ==============
allow httpd_t var_run_t:sock_file write;
#doesn't work
allow httpd_t var_run_t:unix_stream_socket connectto;
#works
#allow httpd_t unconfined_t:unix_stream_socket connectto;
Но запрещает доступ к розеткам.
В audit.log
говорит:
type=AVC msg=audit(1400402777.579:642): avc: denied { connectto } for pid=11068 comm="httpd" path="/var/run/php-fpm/i10000_test-1.testtest.org.sock" scontext=unconfined_u:system_r:httpd_t:s0 tcontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tclass=unix_stream_socket
type=SYSCALL msg=audit(1400402777.579:642): arch=c000003e syscall=42 success=no exit=-13 a0=c a1=7ffe42329818 a2=32 a3=0 items=0 ppid=6136 pid=11068 auid=4294967295 uid=48 gid=48 euid=48 suid=48 fsuid=48 egid=48 sgid=48 fsgid=48 tty=(none) ses=4294967295 comm="httpd" exe="/usr/sbin/httpd" subj=unconfined_u:system_r:httpd_t:s0 key=(null)
И audit2allow -a
производит:
allow httpd_t unconfined_t:unix_stream_socket connectto;
Где это tcontext=unconfined_u:unconfined_r:unconfined_t
приходят из, когда целью является сокет, а сокет помечен var_run_t
?
Изменив на unconfined_t
как "предложено" audit2allow, это работает (закомментировано выше). Но, насколько я понимаю, добавление политик, связанных с unconfined_t
- плохая идея (так как это позволит получить доступ к множеству ненужных сокетов?)
Может ли кто-нибудь сказать мне, что я неправильно понял - или как мне подойти к проблеме, если я просто ошибаюсь?
Обновление: Хорошо, значит, «unlimited_t» исходит от родительского главного процесса php-fpm; не из файла .sock.
ps xZ | grep php-fpm
:
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 31436 ? Ss 0:00 php-fpm: master process (/etc/php-5.3/php-fpm.conf)
Есть ли какое-то логическое объяснение, что это не отражено в ls -Z
?
И означает ли это, что проблема на самом деле хуже (чем я подозревал вначале)? Т.е. процесс php-fpm работает без ограничений, что позволяет ему делать практически все.
Обновление: мне удалось заставить php-fpm работать в том же домене, что и apache, просто:
chcon system_u:object_r:httpd_exec_t:s0 /usr/php-multi/5.3.28/sbin/php-fpm
В Apache уже определены правила перехода и политики selinux, поэтому процесс автоматически переходит к httpd_t
домен, как только он будет запущен, будь то во время загрузки или после ручного service php-fpm-5.3 start
(или restart
) - и PHP выполняется через apache без сбоев.
Однако я все еще не уверен, что это (совместное использование домена с apache) желательная ситуация (все еще с точки зрения безопасности). Должен ли я продолжать попытки поместить его в свой собственный домен и определять для этого политики вручную?
Обновление (я здесь новенький, так что кто-нибудь скажет мне, неуместно ли продолжать обновлять вопрос?):
Я узнал, как создать новый тип и запустить там демон php-fpm; вот моя новая политика:
policy_module(httpd_php_fpm, 1.0)
require {
type httpd_t;
type var_run_t;
type locale_t;
type httpd_sys_content_t;
}
#============= httpd_t ==============
allow httpd_t var_run_t:sock_file write;
#============= php_fpm_t ==============
type php_fpm_exec_t;
files_type(php_fpm_exec_t);
type php_fpm_t;
files_type(php_fpm_t);
allow php_fpm_t httpd_sys_content_t:file { read getattr open ioctl append };
allow php_fpm_t locale_t:dir search;
allow php_fpm_t locale_t:file { read getattr open };
allow php_fpm_t self:capability { setuid chown kill setgid };
allow php_fpm_t self:process { signal sigkill };
allow php_fpm_t var_run_t:dir { write remove_name add_name };
allow php_fpm_t var_run_t:file { write create unlink open };
allow php_fpm_t var_run_t:sock_file { write create unlink setattr };
init_daemon_domain(php_fpm_t, php_fpm_exec_t)
Правила генерируются с помощью audit2allow и могут разрешать больше, чем необходимо, но это работает ... конечно, php-fpm
двоичному файлу еще нужно присвоить новый тип:
chcon system_u:object_r:php_fpm_exec_t:s0 /usr/php-multi/5.3.28/sbin/php-fpm
Я до сих пор не уверен, какое решение лучше всего подходит для безопасности.
Я также по-прежнему открыт для любых комментариев по поводу общего подхода или предложений по потенциальным улучшениям этой политики ...
Попробуй это
policy_module(httpd_php_fpm, 1.0)
require {
type httpd_t;
type var_run_t;
}
#============= httpd_t ==============
allow httpd_t var_run_t:sock_file write_sock_file_perms;
allow httpd_t var_run_t:unix_stream_socket client_stream_socket_perms;
## not sure what this is for but..
init_stream_connect_script(httpd_t)
РЕДАКТИРОВАТЬ
Думая об этом, php-fpm
практически делает то, что делает веб-сервер. Попробуйте установить /usr/sbin/php-fpm
и /etc/rc.d/init.d/php-fpm
к httpd_exec_t
и httpd_initrc_exec_t
соответственно, тогда посмотрим, как это продержится.
Если вы переписываете для него политику, вам необходимо учесть ряд вещей:
php-fpm
вероятно, потребуется доступ к базе данных при выполнении сценариев PHP.php-fpm
чтобы прослушивать определенные сетевые порты и позволить apache подключаться к ним, а также к сокетам unix.fc
файл для определения контекстов файлов.user_content
типы httpd, а также системные.Ограничить то, что на самом деле является языком программирования, может быть довольно сложно из-за того, насколько надежной должна быть политика для работы со многими различными веб-приложениями.
php-fpm может попасть в httpd, поэтому нет необходимости создавать новый тип. Вот рабочая политика httpd, которую я написал (протестировано на AMI Linux, основанной на RHEL), которая работает с php-fpm, а также имеет обычно необходимые разрешения для предоставления httpd:
module my-httpd 1.0;
require {
type httpd_t;
type httpd_log_t;
type initrc_t;
type sysctl_vm_t;
type var_lib_t;
type var_run_t;
class unix_stream_socket connectto;
class dir { search read };
class file { write unlink };
class sock_file write;
}
#============= httpd_t ==============
allow httpd_t initrc_t:unix_stream_socket connectto;
allow httpd_t sysctl_vm_t:dir search;
allow httpd_t var_lib_t:file { write unlink };
allow httpd_t httpd_log_t:dir read;
allow httpd_t var_run_t:sock_file write;
По сути, для работы php-fpm нужна последняя строка (вместе с ее типами и объявлением класса)
allow httpd_t var_run_t:sock_file write;