Wie kann ich SELinux anweisen, nginx den Zugriff auf einen Unix-Socket ohne audit2allow zuzulassen?

9

Ich habe Nginx-Weiterleitungsanfragen an Gunicorn über einen Unix-Socket an /run/gunicorn/socket. Standardmäßig ist dieses Verhalten von SELinux nicht zulässig:

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)

Überall, wo ich hinschaue (z. B. hier und hier ), müssen die Anweisungen, die dies ermöglichen, eine Anfrage an nginx stellen, die Anfrage von SELinux abgelehnt und dann ausgeführt werden audit2allow, um zukünftige Anfragen zuzulassen. Ich kann nicht herausfinden , chconoder semanageBefehl, der dieses Verhalten explizit erlaubt.

Ist das der einzige Weg? Es scheint lächerlich, dass Sie keine Richtlinie einrichten können, die es Nginx ermöglicht, in einen Socket zu schreiben, ohne zuerst einen Versuch abzulehnen und dann ein Tool auszuführen, das Dinge ermöglicht, die abgelehnt wurden. Woher wissen Sie genau, was aktiviert wird? Wie soll das funktionieren, wenn Sie Maschinen unter Automatisierung einrichten?

Ich benutze CentOS 7.

drs
quelle
Sie müssen uns die von AVC abgelehnten Nachrichten anzeigen, und es wäre gut zu wissen, welches Betriebssystem und welche Version Sie ebenfalls ausführen.
user9517
@lain guten Punkt.
Dr.

Antworten:

23

Es scheint lächerlich, dass Sie keine Richtlinie einrichten können, die es Nginx ermöglicht, in einen Socket zu schreiben, ohne zuerst einen Versuch abzulehnen und dann ein Tool auszuführen, das Dinge ermöglicht, die abgelehnt wurden.

Nein, SELinux ist eine obligatorische Zugriffskontrolle, Dinge werden standardmäßig abgelehnt und Sie müssen explizit etwas zulassen. Wenn die Richtlinienautoren einen bestimmten (franken) Stapel nicht berücksichtigt haben oder die Autoren eines Dämons ihn nicht für SELinux sensibilisiert und Richtlinien dafür geschrieben haben, sind Sie auf sich allein gestellt. Sie müssen analysieren, was Ihre Dienste tun und wie sie mit SELinux interagieren, und Ihre eigenen Richtlinien erstellen, um dies zuzulassen. Es stehen Tools zur Verfügung, mit denen Sie audit2why , audit2allow usw. unterstützen können.

... Ist das der einzige Weg?

Nein, aber es hängt davon ab, was Sie versuchen und wie Sie es versuchen, was die Lösung ist. Beispielsweise möchten Sie möglicherweise nginx (httpd_t) an Port 8010 (unreserved_port_t) binden. Wenn Sie nginx starten, schlägt dies fehl

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

und Sie schauen (irgendwann) in das Überwachungsprotokoll und finden

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

Sie können dies über audit2alllow ausführen und die Ergebnisse naiv akzeptieren

allow httpd_t port_t:tcp_socket name_bind;

Dadurch kann httpd_t eine Verbindung zu einem beliebigen TCP-Port herstellen. Dies ist möglicherweise nicht das, was Sie wollen.

Sie können sesearch verwenden , um die Richtlinie zu untersuchen und festzustellen, an welche Porttypen httpd_t name_bind kann

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

Unter anderem kann http_t an http_port_t binden. Jetzt können Sie Semanage verwenden , um etwas tiefer zu graben.

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

Port 8010 ist nicht aufgeführt. Da Nginx an Port 8010 gebunden werden soll, ist es nicht unangemessen, es der Liste http_port_t hinzuzufügen

semanage port -a -t http_port_t -p tcp 8010

Jetzt darf nginx name_bind an Port 8010 und nicht an jeden TCP-Port wie oben.

Woher wissen Sie genau, was aktiviert wird?

Änderungen an Richtlinien sind ziemlich einfach zu lesen, da Ihre oben genannten Nachrichten über audit2allow ausgeführt werden

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

die scheinen ziemlich selbsterklärend.

Die erste bezieht sich auf die Datei mit inum 76151. Sie können find verwenden, um den Namen abzurufen (find / -inum 76151), und dann semanage fcontext -a -t ...die Richtlinie und die Wiederherstellungskonfiguration ändern, um den Kontext zu korrigieren.

Der zweite bezieht sich auf /run/gunicorn/socketden wiederum den falschen Kontext. Mit sesearch können wir sehen, dass http_t eine Verbindung zu unix_stream_sockets vom Typ (unter anderem) http_t herstellen kann. So können wir beispielsweise den Kontext entsprechend ändern

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

Dies legt den Kontext von / run / gunicorn und dem Baum | fest Dateien darunter zu httpd_t.

Wie soll das funktionieren, wenn Sie Maschinen unter Automatisierung einrichten?

Sie müssen das System analysieren und im Test entsprechende Änderungen vornehmen. Anschließend verwenden Sie Ihre Automatisierungstools, um die Änderungen bereitzustellen. Puppet und Ansible unterstützen dies.

Natürlich können Sie alles in der Produktion tun, wenn SElinux auf freizügig eingestellt ist. Sammeln Sie alle Nachrichten, analysieren Sie sie, entscheiden Sie über Ihre Änderungen und stellen Sie sie bereit.

Es gibt viel mehr über SELinux zu wissen, aber das ist die Grenze meiner Fähigkeiten, Michael Hampton ist besser und Mathew Ife ist wieder viel besser, sie haben vielleicht mehr hinzuzufügen.

user9517
quelle
1
Ihr Rat ist gründlich und bringt mich der Lösung dieser Probleme viel näher, lässt mich aber immer noch etwas kurz. allow httpd_t httpd_sys_content_t:sock_file write;ist für mich nicht so selbsterklärend, wie Sie gehofft haben. Was bedeutet das, dass die Richtlinie für diese Datei geändert werden muss (dh was folgt -tim semanageBefehl?
drs
Außerdem erhalte ich Gebrauchsanweisungen, wenn ich Ihre semanageBefehle direkt verwende. Ich muss ein --addArgument hinzufügen .
Dr.
Eigentlich sollte ich auch sagen, dass nach dem Ändern des Typs der Socket-Datei in httpd_var_run_twie Michael Hampton unten angegeben, die audit2allowNachricht lautet:allow httpd_t var_run_t:sock_file write;
drs
Es sieht so aus, als hätten Sie es var_run_tnicht eingestellt httpd_var_run_t.
user9517
@lain, hmm .. keine Würfel. Jetzt audit2allowsagtallow httpd_t var_run_t:sock_file write;
drs
2

Der Typ, den Sie verwenden möchten, ist nicht httpd_sys_content_t. Dies gilt für statische Dateien, die der Webserver für Benutzeragenten bereitstellen soll.

Für einen Socket, der für die Interprozesskommunikation verwendet wird, suchen Sie den Typ httpd_var_run_t.

Beachten Sie jedoch, dass es möglicherweise zusätzliche Probleme bei der Kommunikation gibt, da Sie Gunicorn unbeschränkt ausgeführt haben.

Michael Hampton
quelle
3
Vielen Dank! Es sieht so aus, als hätte sich dies um eines der SELinux-Probleme gekümmert. Irgendwelche Hinweise zum Einrichten von Gunicorn (oder einem anderen Dienst) beschränkt?
Dr.
1

Ich habe die vorherigen Antworten ohne Erfolg ausprobiert. In meinem Fall verwende ich einen Nginx-Server als Frontend für eine Uwsgi-Anwendung, die Unix-Sockets verwendet, um sie zu kommunizieren. Mein Betriebssystem Es ist ein Fedora-Server 26.

Die Unix-Sockets werden im Verzeichnis erstellt /var/local/myapp:

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

Um SELinux zu konfigurieren, musste ich den Kontexttyp hinzufügen: httpd_sys_rw_content_t

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