Comment puis-je dire à SELinux d'autoriser l'accès nginx à un socket Unix sans audit2allow?

9

J'ai des demandes de transfert de nginx vers gunicorn via une prise Unix à /run/gunicorn/socket. Par défaut, ce comportement n'est pas autorisé par 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)

Partout où je regarde (par exemple, ici et ici ), les instructions pour permettre à ce dis de faire une demande à nginx, faire refuser la demande par SELinux, puis exécuter audit2allowpour autoriser les demandes futures. Je ne peux pas trouver de commande chconou semanagequi autorise ce comportement explicitement.

Est-ce le seul moyen? Il semble ridicule que vous ne puissiez pas mettre en place une stratégie qui permette à nginx d'écrire sur un socket sans avoir d'abord refusé une tentative, puis exécuté un outil qui permet les choses qui ont été refusées. Comment savez-vous exactement ce qui est activé? Comment est-ce censé fonctionner si vous configurez des machines sous automatisation?

J'utilise CentOS 7.

drs
la source
Vous devez nous montrer les messages refusés par AVC et il serait bon de savoir quel système d'exploitation et quelle version vous utilisez également.
user9517
@lain bon point.
drs

Réponses:

23

Il semble ridicule que vous ne puissiez pas mettre en place une stratégie qui permette à nginx d'écrire sur un socket sans avoir d'abord refusé une tentative, puis exécuté un outil qui permet les choses qui ont été refusées.

Eh bien non, SELinux est un contrôle d'accès obligatoire, les choses sont refusées par défaut et vous devez autoriser explicitement quelque chose. Si les auteurs de la politique n'ont pas pris en compte une pile particulière (franken) ou si les auteurs d'un démon ne l'ont pas prise en compte et écrite par SELinux, alors vous êtes seul. Vous devez analyser ce que font vos services et comment ils interagissent avec SELinux et élaborer votre propre politique pour l'autoriser. Il existe des outils pour vous aider à vérifier2 pourquoi , audit2allow, etc.

... Est-ce le seul moyen?

Non, mais cela dépend de ce que vous essayez de faire et de la façon dont vous essayez de le faire quant à la solution. Par exemple, vous pouvez lier nginx (httpd_t) au port 8010 (unreserved_port_t). Lorsque vous démarrez nginx, il échoue

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

et vous (éventuellement) regardez dans le journal d'audit et trouvez

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

Vous pouvez exécuter cela via audit2alllow et accepter naïvement ses conclusions

allow httpd_t port_t:tcp_socket name_bind;

ce qui permet ensuite à httpd_t de se connecter à n'importe quel port tcp. Ce n'est peut-être pas ce que vous voulez.

Vous pouvez utiliser sesearch pour enquêter sur la stratégie et voir à quels types de port httpd_t peut nommer_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 autres types, http_t peut se lier à http_port_t. Vous pouvez maintenant utiliser le semanage pour creuser un peu plus profondément.

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

Le port 8010 n'est pas répertorié. Comme nous voulons que nginx se lie au port 8010, il n'est pas déraisonnable de l'ajouter à la liste http_port_t

semanage port -a -t http_port_t -p tcp 8010

Maintenant, nginx sera autorisé à nommer_bind vers le port 8010 et pas tous les ports TCP comme ci-dessus.

Comment savez-vous exactement ce qui est activé?

Les changements de politique sont assez faciles à lire, en exécutant vos messages ci-dessus via audit2allow nous obtenons

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

qui semblent assez explicites.

Le premier fait référence au fichier avec inum 76151. Vous pouvez utiliser find pour obtenir son nom (find / -inum 76151), puis utiliser semanage fcontext -a -t ...pour modifier la stratégie et restorecon pour corriger le contexte.

La seconde concerne à /run/gunicorn/socketnouveau le mauvais contexte. En utilisant sesearch, nous pouvons voir que http_t peut se connecter à unix_stream_sockets de type (entre autres) http_t. On peut donc changer le contexte en conséquence par exemple

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

Cela définit le contexte de / run / gunicorn et l'arbre | fichiers en dessous à httpd_t.

Comment est-ce censé fonctionner si vous configurez des machines sous automatisation?

Vous devez analyser le système et apporter les modifications appropriées au test. Vous utilisez ensuite vos outils d'automatisation pour déployer les modifications, marionnette et ansible prennent en charge cela.

Bien sûr, vous pouvez tout faire en production avec SElinux réglé sur permissif. Collectez tous les messages, analysez-les, décidez de vos modifications et déployez-les.

Il y a beaucoup plus à savoir sur SELinux mais c'est la limite de mes compétences, Michael Hampton est meilleur et Mathew Ife est encore mieux, ils ont peut-être plus à ajouter.

user9517
la source
1
Vos conseils sont approfondis et me rapprochent beaucoup plus de la résolution de ces problèmes moi-même, bien que cela me laisse encore un peu court. allow httpd_t httpd_sys_content_t:sock_file write;n'est pas aussi explicite pour moi que vous l'espériez. Qu'est - ce que ce à dire la politique sur que les besoins de fichiers à modifier à (c. -à- ce qui se passe après -tla semanagecommande?
drs
De plus, je reçois des instructions d'utilisation lorsque j'utilise semanagedirectement vos commandes. Je dois ajouter un --addargument.
drs
En fait, je dois également dire qu'après avoir changé le type du fichier socket httpd_var_run_tcomme Michael Hampton l'a noté ci-dessous, le audit2allowmessage est:allow httpd_t var_run_t:sock_file write;
drs
Il semble que vous définissez à var_run_tpas httpd_var_run_t.
user9517
@lain, hmm .. pas de dés. Maintenant audit2allowditallow httpd_t var_run_t:sock_file write;
drs
2

Le type que vous souhaitez utiliser ne l'est pas httpd_sys_content_t. Il s'agit des fichiers statiques que le serveur Web est censé servir aux agents utilisateurs.

Pour un socket utilisé pour la communication interprocessus, le type que vous recherchez est httpd_var_run_t.

Cependant, veuillez noter que, comme vous avez exécuté gunicorn sans restriction, il peut y avoir des problèmes supplémentaires de communication avec lui.

Michael Hampton
la source
3
Merci! Il semble que cela ait résolu l'un des problèmes de SELinux. Des conseils sur la façon de configurer gunicorn (ou tout autre service) confiné?
drs
1

J'ai essayé les réponses précédentes sans succès, dans mon cas j'utilise un serveur nginx comme frontend pour une application uwsgi utilisant des sockets unix pour les communiquer, mon OS C'est un serveur Fedora 26.

Les sockets unix sont créés dans le répertoire /var/local/myapp:

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

Pour configurer SELinux, j'ai dû ajouter le type de contexte: httpd_sys_rw_content_t

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