Estou tentando configurar várias instâncias do php-fpm para executar múltiplas versões do php através do apache 2.2 rodando no centos 6.5.
Em algum momento no futuro, isso terminará em um ambiente de hospedagem compartilhada, por isso preciso da segurança mais rígida possível.
Portanto, estou tentando evitar desabilitar o selinux e tentar definir políticas o mais restritas possível.
Sou relativamente novo no selinux (nossos servidores existentes simplesmente o desativam). Eu fiz muita leitura sobre o tópico, mas a lógica ainda me escapa (como eu tenho certeza que esta pergunta mostra).
Ao chamar um script php, o apache produz este erro:
[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"
O diretório que contém os sockets do php-fpm se parece com isto:
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
Com base nisso, eu suporia que o tipo dos soquetes era var_run_t
...
Então, estou tentando executar com esta política:
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;
Mas nega acesso aos soquetes.
O audit.log
diz:
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)
E audit2allow -a
produz:
allow httpd_t unconfined_t:unix_stream_socket connectto;
De onde vem esse tcontext=unconfined_u:unconfined_r:unconfined_t
quando o alvo é o soquete e o soquete é rotulado var_run_t
?
Alterando para unconfined_t
como "sugerido" por audit2allow, funciona (comentados acima). Mas, até onde eu entendo, adicionar políticas envolvendo unconfined_t
é uma má ideia (já que permitiria acesso a muitos sockets que não são necessários?)
Alguém pode me dizer o que eu entendi mal - ou como eu deveria estar abordando a questão se eu estou simplesmente indo completamente errado?
Atualização:
Ok, então o 'unconfined_t' vem do processo mestre pai php-fpm; não do arquivo .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)
-
Existe alguma explicação lógica que não seja refletida em ls -Z
?
-
E isso significa que o problema é realmente pior (do que eu suspeitei primeiro)? Ie. o processo do php-fpm está sendo executado sem confinamento, permitindo que ele faça praticamente qualquer coisa.
Atualização:
Eu consegui executar o php-fpm no mesmo domínio que o apache:
chcon system_u:object_r:httpd_exec_t:s0 /usr/php-multi/5.3.28/sbin/php-fpm
O Apache já tem regras de transição e políticas de selinux definidas, portanto o processo transita automaticamente para o domínio httpd_t
assim que é lançado, seja durante a inicialização ou após um manual service php-fpm-5.3 start
(ou restart
) - e PHP é executado através do apache sem um soluço.
No entanto, ainda não estou certo de que (compartilhando o domínio com o apache) uma situação desejável (ainda de uma perspectiva de segurança). Devo continuar tentando colocá-lo em seu próprio domínio e definindo políticas para isso manualmente?
Atualizar (eu sou novo aqui, então alguém me diz se é inapropriado continuar atualizando a questão?):
Eu descobri como criar um novo tipo e obter o daemon do php-fpm para rodar lá; aqui está minha nova política:
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)
As regras são geradas com audit2allow e podem permitir mais do que o necessário, mas isso funciona ... é claro que o binário php-fpm
ainda precisa receber o novo tipo:
chcon system_u:object_r:php_fpm_exec_t:s0 /usr/php-multi/5.3.28/sbin/php-fpm
Ainda não tenho certeza de qual solução é realmente a melhor segurança.
Ainda estou aberto a comentários sobre a abordagem geral ou sugestões sobre possíveis melhorias a essa política ...