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

7

Eu tenho solicitações de encaminhamento nginx para o gunicorn por meio 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 todos os lugares que eu olho (por exemplo, aqui e aqui ), as instruções para permitir que isso seja dito para fazer uma solicitação ao nginx, pedido ser negado pelo SELinux, em seguida, execute audit2allow para permitir futuras solicitações. Não consigo descobrir nenhum comando chcon ou semanage que permita esse comportamento explicitamente.

Este é o único caminho? Parece ridículo que não seja possível configurar uma política que permita que o nginx grave em um soquete sem antes ter uma tentativa negada e, em seguida, executar uma ferramenta que permita as coisas que foram negadas. Como você sabe exatamente o que está sendo ativado? Como isso deve funcionar se você configurar máquinas sob automação?

Estou usando o CentOS 7.

    
por drs 13.03.2016 / 17:01

3 respostas

19

It seems ridiculous that you can't set up a policy that allows nginx to write to a socket without first having an attempt denied and then running a tool that enables things that were denied.

Bem, não, o SELinux é o Controle de Acesso Obrigatório, as coisas são negadas por padrão e você tem que permitir explicitamente alguma coisa. Se os autores da política não consideraram uma pilha particular (franken) ou os autores de um daemon não a tornaram política consciente e escrita do SELinux, então você está por conta própria. Você tem que 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 audit2why , audit2allow etc.

... Is this the only way?

Não, mas depende do que você está tentando fazer e de como você está tentando fazer o que 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) procurar no log de auditoria e encontrar

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 por meio do audit2alllow e ingenuamente aceitar suas descobertas

allow httpd_t port_t:tcp_socket name_bind;

, que permite que o httpd_t se conecte a qualquer porta tcp. Isso pode não ser o que você quer.

Você pode usar sesearch para investigar a política e ver que tipos de porta httpd_t podem nomear_bind para

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 se vincular a http_port_t. Agora você pode usar semanage para cavar 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 é irracional adicioná-lo à lista http_port_t

semanage port -a -t http_port_t -p tcp 8010

Agora o nginx terá permissão para nomear_bind para a porta 8010 nd e não para todas as portas tcp como acima.

How do you know exactly what is being enabled?

As alterações na política são relativamente fáceis de ler, executando suas mensagens acima por meio de auditoria2tudo recebemos

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

, que parecem bastante auto-explicativos.

O primeiro deles refere-se ao arquivo com o 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 relaciona-se com /run/gunicorn/socket , que novamente tem o contexto errado. Usando sesearch, podemos ver que http_t pode se conectar a unix_stream_sockets do tipo (entre outros) http_t. Então podemos 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 dele para httpd_t.

How is this supposed to work if your setting up machines under automation?

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

Claro que você pode fazer tudo em produção com o SElinux definido como permissivo. Colete todas as mensagens, analise-as e decida-as e implante-as.

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

    
por 14.03.2016 / 00:01
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 .

Embora, por favor, note que, como você executou o gunicorn unconfined, pode haver problemas adicionais ao se comunicar com ele.

    
por 13.03.2016 / 20:26
1

Eu tentei as respostas anteriores sem sucesso, no meu caso eu estou usando um servidor nginx como frontend para um aplicativo uwsgi usando sockets unix para comunicá-los, meu O.S. É 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 eu 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' 
    
por 24.09.2017 / 12:39

Tags