Como posso dizer ao SELinux para permitir o acesso do nginx a um soquete unix sem audit2allow?

9

Eu tenho pedidos de encaminhamento nginx para gunicorn através de um soquete unix em /run/gunicorn/socket. Por padrão, esse comportamento não é permitido pelo SELinux:

grep nginx /var/log/audit/audit.log
type=SERVICE_START msg=audit(1454358912.455:5390): pid=1 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:init_t:s0 msg='unit=nginx comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'
type=AVC msg=audit(1454360194.623:7324): avc:  denied  { write } for  pid=9128 comm="nginx" name="socket" dev="tmpfs" ino=76151 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:httpd_sys_content_t:s0 tclass=sock_file
type=SYSCALL msg=audit(1454360194.623:7324): arch=c000003e syscall=42 success=no exit=-13 a0=c a1=1f6fe58 a2=6e a3=7ffee1da5710 items=0 ppid=9127 pid=9128 auid=4294967295 uid=995 gid=993 euid=995 suid=995 fsuid=995 egid=993 sgid=993 fsgid=993 tty=(none) ses=4294967295 comm="nginx" exe="/usr/sbin/nginx" subj=system_u:system_r:httpd_t:s0 key=(null)
type=AVC msg=audit(1454361591.701:13343): avc:  denied  { connectto } for  pid=9128 comm="nginx" path="/run/gunicorn/socket" scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:system_r:initrc_t:s0 tclass=unix_stream_socket
type=SYSCALL msg=audit(1454361591.701:13343): arch=c000003e syscall=42 success=no exit=-13 a0=c a1=1f6fe58 a2=6e a3=7ffee1da5950 items=0 ppid=9127 pid=9128 auid=4294967295 uid=995 gid=993 euid=995 suid=995 fsuid=995 egid=993 sgid=993 fsgid=993 tty=(none) ses=4294967295 comm="nginx" exe="/usr/sbin/nginx" subj=system_u:system_r:httpd_t:s0 key=(null)

Em todo lugar que eu olho (por exemplo, aqui e aqui ), as instruções para habilitar isso dizem para fazer um pedido ao nginx, têm o pedido negado pelo SELinux e, em seguida, são executadas audit2allowpara permitir pedidos futuros. Eu não consigo descobrir qualquer chconou semanagede comando que permite que este comportamento de forma explícita.

É este o único caminho? Parece ridículo que você não possa configurar uma política que permita ao nginx gravar em um soquete sem primeiro ter uma tentativa negada e, em seguida, executando uma ferramenta que permita as coisas negadas. Como você sabe exatamente o que está sendo ativado? Como isso deve funcionar se você estiver configurando máquinas sob automação?

Estou usando o CentOS 7.

drs
fonte
Você precisa nos mostrar as mensagens negadas pelo AVC e seria bom saber qual SO e versão você também está executando.
user9517
@ bom ponto.
drs 13/03

Respostas:

23

Parece ridículo que você não possa configurar uma política que permita ao nginx gravar em um soquete sem primeiro ter uma tentativa negada e, em seguida, executando uma ferramenta que permita as coisas negadas.

Bem, não, o SELinux é Controle de Acesso Obrigatório, as coisas são negadas por padrão e você precisa permitir algo explicitamente. Se os autores da política não consideraram uma pilha (franken) específica ou os autores de um daemon não a tornaram consciente do SELinux e escreveram uma política para ela, você estará por sua conta. Você precisa analisar o que seus serviços estão fazendo e como eles estão interagindo com o SELinux e criar sua própria política para permitir isso. Existem ferramentas disponíveis para ajudá-lo a audit2why , audit2allow etc.

... É este o único caminho?

Não, mas depende do que você está tentando fazer e de como está tentando fazer qual é a solução. Por exemplo, você pode querer ligar o nginx (httpd_t) à porta 8010 (unreserved_port_t). Quando você inicia o nginx, ele falha

Starting nginx: nginx: [emerg] bind() to 0.0.0.0:8010 failed (13: Permission denied)

e você (eventualmente) olha no log de auditoria e encontra

type=AVC msg=audit(1457904756.503:41673): avc:  denied  { name_bind } for
pid=30483 comm="nginx" src=8010 scontext=unconfined_u:system_r:httpd_t:s0
tcontext=system_u:object_r:port_t:s0 tclass=tcp_socket

Você pode executar isso através do audit2alllow e aceitar ingenuamente suas descobertas

allow httpd_t port_t:tcp_socket name_bind;

que permite ao httpd_t se conectar a qualquer porta TCP. Pode não ser o que você deseja.

Você pode usar sesearch para investigar a política e ver a quais tipos de porta httpd_t pode name_bind

sesearch --allow -s httpd_t | grep name_bind
...
allow httpd_t http_port_t : tcp_socket name_bind ;
allow httpd_t http_port_t : udp_socket name_bind ;
...

Entre outros tipos, o http_t pode ser vinculado ao http_port_t. Agora você pode usar a semântica para se aprofundar um pouco mais.

semanage port -l | grep http_port_t
http_port_t                    tcp      80, 81, 443, 488, 8008, 8009, 8443, 9000
...

A porta 8010 não está listada. Como queremos que o nginx se ligue à porta 8010, não é razoável adicioná-lo à lista http_port_t

semanage port -a -t http_port_t -p tcp 8010

Agora, o nginx poderá nomear_bind para a porta 8010 e nem todas as portas tcp como acima.

Como você sabe exatamente o que está sendo ativado?

É fácil ler as alterações na política, executando suas mensagens acima através do audit2;

allow httpd_t httpd_sys_content_t:sock_file write;
allow httpd_t initrc_t:unix_stream_socket connectto;

o que parece bastante auto-explicativo.

O primeiro deles refere-se ao arquivo com inum 76151. Você pode usar find para obter seu nome (find / -inum 76151) e depois usar semanage fcontext -a -t ...para alterar a política e restorecon para corrigir o contexto.

O segundo refere-se ao /run/gunicorn/socketqual novamente tem o contexto errado. Usando a pesquisa, podemos ver que o http_t pode se conectar a unix_stream_sockets do tipo (entre outros) http_t. Para que possamos mudar o contexto de acordo, por exemplo

semanage fcontext -a -t httpd_t "/run/gunicorn(/.*)?"
restorecon -r /run

Isso define o contexto de / run / gunicorn e a árvore | arquivos abaixo para httpd_t.

Como isso deve funcionar se você estiver configurando máquinas sob automação?

Você precisa analisar o sistema e fazer as alterações apropriadas no teste. Em seguida, você usa suas ferramentas de automação para implantar as alterações, fantoches e ansible têm suporte para isso.

Obviamente, você pode fazer tudo isso em produção com o SElinux definido como permissivo. Colete todas as mensagens, analise-as e decida sobre suas alterações e implante-as.

Há muito mais a saber sobre o SELinux, mas esse é o limite de minhas habilidades, Michael Hampton é melhor e Mathew Ife é muito melhor novamente, eles podem ter mais a acrescentar.

user9517
fonte
1
Seu conselho é completo e me deixa muito mais perto de resolver esses problemas, embora ainda me deixe um pouco curto. allow httpd_t httpd_sys_content_t:sock_file write;não é tão auto-explicativo para mim quanto você esperava. O que é isso dizendo que a política nesse arquivo precisa ser alterada para (ou seja, o que ocorre depois -tno semanagecomando?
drs 14/03
Além disso, recebo instruções de uso ao usar seus semanagecomandos diretamente. Eu preciso adicionar um --addargumento.
drs 14/03
Na verdade, devo dizer também que, depois de alterar o tipo do arquivo de soquete para httpd_var_run_tcomo Michael Hampton observou abaixo, a audit2allowmensagem é:allow httpd_t var_run_t:sock_file write;
drs
Parece que você configurou para var_run_tnão httpd_var_run_t.
user9517
@ mentir, hmm .. sem dados. Agora audit2allowdizallow httpd_t var_run_t:sock_file write;
drs 14/03
2

O tipo que você deseja usar não é httpd_sys_content_t. Isso é para arquivos estáticos que o servidor da Web deve servir aos agentes do usuário.

Para um soquete usado para comunicação entre processos, o tipo que você está procurando é httpd_var_run_t.

No entanto, observe que, como você executou o gunicorn sem limites, pode haver problemas adicionais na comunicação com ele.

Michael Hampton
fonte
3
Obrigado! Parece que isso resolveu um dos problemas do SELinux. Alguma dica sobre como configurar o gunicorn (ou qualquer outro serviço) confinado?
drs 14/03
1

Eu tentei as respostas anteriores sem sucesso, no meu caso, estou usando um servidor nginx como interface para um aplicativo uwsgi usando soquetes unix para comunicá-los, meu SO É um servidor Fedora 26.

Os soquetes unix são criados no diretório /var/local/myapp:

/var/local/myapp/server.sock    
/var/local/myapp/stats.sock

Para configurar o SELinux, tive que adicionar o tipo de contexto: httpd_sys_rw_content_t

semanage fcontext -at httpd_sys_rw_content_t "/var/local/myapp(/.*)?"
restorecon -R -v '/var/local/myapp' 
rsc1975
fonte