Jak mogę powiedzieć SELinux, aby zezwalał nginxowi na dostęp do gniazda unix bez audit2allow?

10

Mam prośby o przesłanie przez Nginx do gunicorn przez gniazdo unix w /run/gunicorn/socket. Domyślnie takie zachowanie nie jest dozwolone przez 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)

Gdziekolwiek spojrzę (np. Tutaj i tutaj ), instrukcje pozwalające temu powiedzieć na wysłanie żądania do nginx, mają zostać odrzucone przez SELinux, a następnie uruchomione, audit2allowaby zezwolić na przyszłe żądania. Nie mogę znaleźć żadnego polecenia chconani semanagepolecenia, które zezwalałoby na to zachowanie.

Czy to jedyny sposób? To absurdalne, że nie można skonfigurować polityki, która pozwala nginx pisać do gniazda bez uprzedniej próby odmowy, a następnie uruchomienia narzędzia, które umożliwia odmowę. Skąd dokładnie wiesz, co jest włączone? Jak to ma działać, jeśli konfigurujesz maszyny w trybie automatyzacji?

Używam CentOS 7.

dr
źródło
Musisz nam pokazać komunikaty o odmowie AVC i dobrze byłoby wiedzieć, który system operacyjny i wersję też używasz.
user9517
@ utrzymuj dobry punkt.
drs

Odpowiedzi:

23

To absurdalne, że nie można skonfigurować polityki, która pozwala nginx pisać do gniazda bez uprzedniej próby odmowy, a następnie uruchomienia narzędzia, które umożliwia odmowę.

Cóż, nie, SELinux jest obowiązkową kontrolą dostępu, domyślnie odmawia się i trzeba na coś wyraźnie zezwolić. Jeśli autorzy zasad nie brali pod uwagę konkretnego stosu (franken) lub autorzy demona nie sprawili, że SELinux jest świadomy i napisał dla niego zasady, to jesteś sam. Musisz przeanalizować, co robią twoje usługi i ich interakcje z SELinux, i opracować własną politykę, która na to pozwala. Dostępne są narzędzia, które pomogą Ci audit2why , audit2allow itp.

... Czy to jedyny sposób?

Nie, ale zależy to od tego, co próbujesz zrobić i jak próbujesz to zrobić, jakie jest rozwiązanie. Na przykład możesz powiązać nginx (httpd_t) z portem 8010 (unreserved_port_t). Po uruchomieniu nginx nie działa

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

a ty (ewentualnie) przeglądasz dziennik kontroli i znajdujesz

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

Możesz uruchomić to przez audit2alllow i naiwnie zaakceptować jego ustalenia

allow httpd_t port_t:tcp_socket name_bind;

co następnie pozwala httpd_t połączyć się z dowolnym portem TCP. To może nie być to, czego chcesz.

Możesz użyć wyszukiwarki, aby sprawdzić zasady i zobaczyć, do jakich typów portów httpd_t może przypisać nazwę

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

Wśród innych typów http_t może wiązać się z http_port_t. Teraz możesz użyć semanage, aby kopać nieco głębiej.

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

Port 8010 nie znajduje się na liście. Ponieważ chcemy, aby nginx powiązał się z portem 8010, dodanie go do listy http_port_t nie jest nierozsądne.

semanage port -a -t http_port_t -p tcp 8010

Teraz nginx będzie mógł przypisać nazwę do portu 8010 i nie do każdego portu TCP jak wyżej.

Skąd dokładnie wiesz, co jest włączone?

Zmiany w polityce są dość łatwe do odczytania, uruchamiamy twoje wiadomości powyżej za pośrednictwem audit2allow, które otrzymujemy

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

które wydają się dość oczywiste.

Pierwszy z nich odnosi się do pliku z inum 76151. Możesz użyć find, aby uzyskać jego nazwę (find / -inum 76151), a następnie użyć semanage fcontext -a -t ...do zmiany polityki i przywracania, aby naprawić kontekst.

Drugi odnosi się do /run/gunicorn/socketktórego ponownie ma niewłaściwy kontekst. Za pomocą sesearch możemy zobaczyć, że http_t może łączyć się z uniksowymi_stream_sockets typu (między innymi) http_t. Możemy na przykład odpowiednio zmienić kontekst

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

To ustawia kontekst / run / gunicorn i drzewa | pliki poniżej to httpd_t.

Jak to ma działać, jeśli konfigurujesz maszyny w trybie automatyzacji?

Musisz przeanalizować system i wprowadzić odpowiednie zmiany w teście. Następnie używasz narzędzi automatyzacji do wdrożenia zmian, kukiełka i ansible mają na to wsparcie.

Oczywiście możesz to wszystko zrobić w produkcji z SElinux ustawionym na permisywny. Zbierz wszystkie wiadomości, przeanalizuj je, zdecyduj o zmianach i wdróż je.

O SELinuksie można dowiedzieć się o wiele więcej, ale to jest granica moich umiejętności, Michael Hampton jest lepszy, a Mathew Ife jest znowu lepszy, mogą mieć więcej do dodania.

użytkownik9517
źródło
1
Twoja rada jest dokładna i przybliża mnie do samodzielnego rozwiązywania tych problemów, choć wciąż pozostaje mi trochę za mało. allow httpd_t httpd_sys_content_t:sock_file write;nie jest dla mnie tak oczywiste, jak się spodziewałeś. Co to jest powiedzenie politykę na który potrzebuje plików ma być zmieniony na (czyli po co idzie -tw semanagekomendzie?
DRS
Otrzymuję również instrukcje użytkowania, gdy używam twoich semanagepoleceń bezpośrednio. Muszę dodać --addargument.
drs
Właściwie powinienem również powiedzieć, że po zmianie typu pliku gniazda na, httpd_var_run_tjak zauważył poniżej Michael Hampton, audit2allowkomunikat brzmi:allow httpd_t var_run_t:sock_file write;
drs
Wygląda na to, że go var_run_tnie ustawiłeś httpd_var_run_t.
user9517
@ lein, hmm .. bez kości. Teraz audit2allowmówiallow httpd_t var_run_t:sock_file write;
drs
2

Typ, którego chcesz użyć, nie jest httpd_sys_content_t. Dotyczy to plików statycznych, które serwer WWW ma udostępniać agentom użytkownika.

W przypadku gniazda używanego do komunikacji międzyprocesowej poszukiwany jest typ httpd_var_run_t.

Pamiętaj jednak, że ponieważ uruchomiłeś gunicorn bez ograniczeń, mogą wystąpić dodatkowe problemy z komunikacją z nim.

Michael Hampton
źródło
3
Dzięki! Wygląda na to, że zajął się jednym z problemów SELinuksa. Jakieś wskazówki dotyczące konfiguracji gunicorn (lub jakiejkolwiek innej usługi) są ograniczone?
drs
1

Próbowałem wcześniejszych odpowiedzi bez powodzenia, w moim przypadku używam serwera nginx jako nakładki dla aplikacji uwsgi używającej gniazd unix do komunikacji, mój system operacyjny To serwer Fedora 26.

Gniazda unixowe są tworzone w katalogu /var/local/myapp:

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

Aby skonfigurować SELinux, musiałem dodać typ kontekstu: httpd_sys_rw_content_t

semanage fcontext -at httpd_sys_rw_content_t "/var/local/myapp(/.*)?"
restorecon -R -v '/var/local/myapp' 
rsc1975
źródło