Etiqueta SElinux para sockets php-fpm

5

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 ...

    
por Mikk3lRo 18.05.2014 / 12:47

1 resposta

1

Tente isso

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)

EDITAR

Pensando nisso, php-fpm está praticamente fazendo o que o servidor web faz. Tente definir /usr/sbin/php-fpm e /etc/rc.d/init.d/php-fpm para httpd_exec_t e httpd_initrc_exec_t , respectivamente, e veja como isso ocorre.

Se você reescrever uma política para isso, precisará considerar várias coisas:

  • Você provavelmente deve certificar-se de que os arquivos tmp sejam rotulados como algo especial.
  • Faça com que o php-fpm também rotule os soquetes var_run e os arquivos pid de algo especial, depois altere o apache para poder se conectar a eles.
  • php-fpm provavelmente desejará acesso ao banco de dados ao executar scripts PHP.
  • Provavelmente você precisará permitir que php-fpm ouça portas de rede específicas e permita que o apache se conecte a elas, bem como a soquetes unix.
  • Você precisa definir um arquivo fc para especificar contextos de arquivo.
  • Verifique se o php-fpm pode fazer outras coisas, como imap, pop3, smtp, http, https, para citar pelo menos alguns.
  • Deve ser capaz de escrever de volta no conteúdo do httpd onde a gravação é permitida e usar o rótulo correto.
  • Deve ser capaz de ler user_content tipos de httpd, bem como de sistema.

Confinar o que é, na verdade, uma linguagem de programação pode ser bastante complicado por causa da robustez da política para trabalhar com muitos aplicativos da Web diferentes.

    
por 18.05.2014 / 13:25