Come posso dire a SELinux di consentire l'accesso nginx a un socket unix senza audit2allow?


9

Ho richieste di inoltro nginx a Gunicorn tramite un socket Unix a /run/gunicorn/socket. Di default, questo comportamento non è permesso da 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)

Ovunque io guardi (ad esempio, qui e qui ), le istruzioni per abilitare questo dicono di fare una richiesta a nginx, che la richiesta sia negata da SELinux, quindi eseguita audit2allowper consentire future richieste. Non riesco a capire alcuno chcono semanagecomando che consenta esplicitamente questo comportamento.

È l'unico modo? Sembra ridicolo che non sia possibile impostare una politica che consenta a nginx di scrivere su un socket senza prima aver tentato di negare un tentativo e quindi eseguire uno strumento che abilita le cose che sono state negate. Come fai a sapere esattamente cosa viene abilitato? Come dovrebbe funzionare se la configurazione delle macchine è automatizzata?

Sto usando CentOS 7.


Devi mostrarci i messaggi negati da AVC e sarebbe bene sapere anche quale sistema operativo e versione stai utilizzando.
user9517

@lain buon punto.
Dott.

Risposte:


23

Sembra ridicolo che non sia possibile impostare una politica che consenta a nginx di scrivere su un socket senza prima aver tentato di negare un tentativo e quindi eseguire uno strumento che abilita le cose che sono state negate.

Bene no, SELinux è un controllo di accesso obbligatorio, le cose sono negate di default e devi consentire esplicitamente qualcosa. Se gli autori delle politiche non hanno preso in considerazione un particolare stack (franco) o gli autori di un demone non lo hanno reso consapevole di SELinux e ne hanno scritto una politica, allora si è soli. Devi analizzare cosa stanno facendo i tuoi servizi e come interagiscono con SELinux e elaborare la tua politica per consentirlo. Ci sono strumenti disponibili per aiutarti audit2why , audit2allow ecc.

... È l'unico modo?

No, ma dipende da cosa stai cercando di fare e da come stai cercando di farlo su quale sia la soluzione. Ad esempio, potresti voler associare nginx (httpd_t) alla porta 8010 (unreserved_port_t). Quando avvii nginx, fallisce

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

e tu (eventualmente) guardi nel registro di controllo e trovi

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

È possibile eseguire questo attraverso audit2alllow e accettare ingenuamente i risultati

allow httpd_t port_t:tcp_socket name_bind;

che quindi consente a httpd_t di connettersi a qualsiasi porta tcp. Questo potrebbe non essere quello che vuoi.

È possibile utilizzare sesearch per esaminare la politica e vedere a quali tipi di porta httpd_t può associare 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 ;
...

Tra gli altri tipi, http_t può essere associato a http_port_t. Ora puoi usare la semanage per scavare un po 'più a fondo.

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

La porta 8010 non è elencata. Poiché vogliamo che nginx si colleghi alla porta 8010, non è irragionevole aggiungerlo all'elenco http_port_t

semanage port -a -t http_port_t -p tcp 8010

Ora nginx sarà autorizzato a name_bind alla porta 8010 e non tutte le porte tcp come sopra.

Come fai a sapere esattamente cosa viene abilitato?

Le modifiche alla politica sono abbastanza facili da leggere, eseguendo i tuoi messaggi sopra tramite audit2 consente di ottenere

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

che sembrano abbastanza autoesplicativi.

Il primo di questi fa riferimento al file con inum 76151. È possibile utilizzare find per ottenere il nome (find / -inum 76151) e quindi utilizzare semanage fcontext -a -t ...per modificare la politica e ripristinarla per correggere il contesto.

La seconda riguarda la /run/gunicorn/socketquale ha di nuovo il contesto sbagliato. Usando sesearch possiamo vedere che http_t può connettersi a unix_stream_socket di tipo (tra gli altri) http_t. Quindi possiamo cambiare il contesto di conseguenza, per esempio

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

Questo imposta il contesto di / run / gunicorn e l'albero | file sottostanti a httpd_t.

Come dovrebbe funzionare se la configurazione delle macchine è automatizzata?

È necessario analizzare il sistema e apportare le modifiche appropriate al test. Quindi utilizzare gli strumenti di automazione per distribuire le modifiche, fantoccio e ansible hanno il supporto per questo.

Ovviamente puoi fare tutto in produzione con SElinux impostato su permissivo. Raccogli tutti i messaggi, analizzali decidi sulle modifiche e distribuiscili.

C'è molto altro da sapere su SELinux, ma questo è il limite delle mie capacità, Michael Hampton è migliore e Mathew Se è di nuovo molto meglio, potrebbero avere di più da aggiungere.


1
Il tuo consiglio è approfondito e mi avvicina molto di più a risolvere questi problemi da solo, anche se mi lascia ancora un po 'corto. allow httpd_t httpd_sys_content_t:sock_file write;non mi spiega da solo come speravi. Cosa sta dicendo questo la politica su quel file deve essere cambiata in (cioè, cosa succede dopo -tnel semanagecomando?
drs

Inoltre, ricevo le istruzioni per l'uso quando si utilizzano semanagedirettamente i comandi. Devo aggiungere un --addargomento.
Dr

In realtà, dovrei anche dire che dopo aver cambiato il tipo di file socket httpd_var_run_tcome indicato di seguito da Michael Hampton, il audit2allowmessaggio è:allow httpd_t var_run_t:sock_file write;
drs

Sembra che si imposta var_run_tnon httpd_var_run_t.
user9517

@lain, hmm .. no dice. Ora audit2allowdiceallow httpd_t var_run_t:sock_file write;
dr

2

Il tipo che si desidera utilizzare non lo è httpd_sys_content_t. Questo è per i file statici che il server Web è destinato a servire agli agenti utente.

Per un socket utilizzato per la comunicazione tra processi, il tipo che stai cercando è httpd_var_run_t.

Tuttavia, tieni presente che poiché hai eseguito il gunicorn non confinato, potrebbero esserci ulteriori problemi di comunicazione con esso.


3
Grazie! Sembra che questo abbia risolto uno dei problemi di SELinux. Qualche suggerimento su come impostare gunicorn (o qualsiasi altro servizio) limitato?
Dr

1

Ho provato le risposte precedenti senza successo, nel mio caso sto usando un server nginx come frontend per un'applicazione uwsgi che usa socket unix per comunicarle, il mio sistema operativo è un server Fedora 26.

I socket unix vengono creati nella directory /var/local/myapp:

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

Per configurare SELinux ho dovuto aggiungere il tipo di contesto: httpd_sys_rw_content_t

semanage fcontext -at httpd_sys_rw_content_t "/var/local/myapp(/.*)?"
restorecon -R -v '/var/local/myapp' 
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.