I'm attempting to set up multiple instances of php-fpm to run multiple versions of php through apache 2.2 running on centos 6.5.
At some point in the future this will end up in a shared hosting environment, so I need the tightest security possible.
Therefore I'm trying to avoid disabling selinux altogether, and trying to set policies as narrow as possible.
I am relatively new to selinux (our existing servers simply has it disabled). I have done a lot of reading on the topic, but the logic still escapes me (as I'm sure this question shows).
When calling a php-script apache produces this error:
[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"
The directory containing the php-fpm sockets looks like this:
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
Based on that I would assume the type of the sockets was var_run_t
...
So I'm trying to run under this policy:
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;
But it denies access to the sockets.
The audit.log
says:
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)
And audit2allow -a
produces:
allow httpd_t unconfined_t:unix_stream_socket connectto;
Where does that tcontext=unconfined_u:unconfined_r:unconfined_t
come from when the target is the socket, and the socket is labeled var_run_t
?
By changing to unconfined_t
as "suggested" by audit2allow it works (commented out above). But as far as I understand adding policies involving unconfined_t
is a bad idea (as it would allow access to a lot of sockets that aren't needed?)
Can anyone tell me what I've misunderstood - or how I should be aproaching the issue if I'm simply going about it completely wrong?
Update: Ok, so the 'unconfined_t' comes from the parent php-fpm master process; not from the .sock file.
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)
Is there any logical explanation this isn't reflected in
ls -Z
?And does this mean that the issue is actually worse (than I first suspected)? Ie. the php-fpm process is running unconfined, allowing it to do nearly anything.
Update: I managed to get php-fpm to run in the same domain as apache by simply:
chcon system_u:object_r:httpd_exec_t:s0 /usr/php-multi/5.3.28/sbin/php-fpm
Apache already has transition rules and selinux policies defined, so the process transitions automatically to the httpd_t
domain as soon as it is launched, whether during boot or after a manual service php-fpm-5.3 start
(or restart
) - and PHP is executed through apache without a hiccup.
However I am still not sure this (sharing the domain with apache) a desirable situation (still from a security perspective). Should I continue trying to get it into it's own domain and defining policies for that manually?
Update (I'm new here, so someone tell me if it's inappropriate to keep updating the question?):
I found out how to create a new type and get the php-fpm daemon to run there; here is my new policy:
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)
The rules are generated with audit2allow and may allow more than needed, but this works... of course the php-fpm
binary still needs to be given the new type:
chcon system_u:object_r:php_fpm_exec_t:s0 /usr/php-multi/5.3.28/sbin/php-fpm
I am still unsure which solution is actually best security wise.
I am also still open to any comments about the general approach, or suggestions on potential improvements to this policy...