Bagaimana saya bisa memberitahu SELinux untuk mengizinkan akses nginx ke soket unix tanpa audit2allow?

9

Saya memiliki permintaan penerusan nginx ke gunicorn melalui soket unix di /run/gunicorn/socket. Secara default, perilaku ini tidak diizinkan oleh 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)

Di mana-mana saya melihat (misalnya, di sini dan di sini ), instruksi untuk mengaktifkan ini mengatakan untuk membuat permintaan ke nginx, minta permintaan ditolak oleh SELinux, kemudian jalankan audit2allowuntuk mengizinkan permintaan di masa depan. Saya tidak tahu chconatau semanageperintah apa pun yang memungkinkan perilaku ini secara eksplisit.

Apakah ini satu-satunya jalan? Tampaknya konyol bahwa Anda tidak dapat mengatur kebijakan yang memungkinkan nginx untuk menulis ke soket tanpa terlebih dahulu upaya ditolak dan kemudian menjalankan alat yang memungkinkan hal-hal yang ditolak. Bagaimana Anda tahu persis apa yang sedang diaktifkan? Bagaimana ini bisa berfungsi jika Anda mengatur mesin di bawah otomatisasi?

Saya menggunakan CentOS 7.

drs
sumber
Anda perlu menunjukkan kepada kami pesan yang ditolak AVC dan alangkah baiknya untuk mengetahui OS dan versi apa yang Anda jalankan juga.
user9517
@lain poin bagus.
drs

Jawaban:

23

Tampaknya konyol bahwa Anda tidak dapat mengatur kebijakan yang memungkinkan nginx untuk menulis ke soket tanpa terlebih dahulu upaya ditolak dan kemudian menjalankan alat yang memungkinkan hal-hal yang ditolak.

Yah tidak, SELinux adalah Kontrol Akses Wajib, semuanya ditolak secara default dan Anda harus secara eksplisit mengizinkan sesuatu. Jika pembuat kebijakan belum mempertimbangkan tumpukan tertentu (franken) atau penulis daemon belum membuatnya SELinux mengetahui dan menulis kebijakan untuk itu maka Anda sendiri. Anda harus menganalisis apa yang dilakukan layanan Anda dan bagaimana mereka berinteraksi dengan SELinux dan membuat kebijakan Anda sendiri untuk mengizinkannya. Ada alat yang tersedia untuk membantu Anda audit2why , audit2allow dll

... Apakah ini satu-satunya jalan?

Tidak, tetapi itu tergantung pada apa yang Anda coba lakukan dan bagaimana Anda mencoba melakukannya untuk apa solusinya. Misalnya Anda mungkin ingin mengikat nginx (httpd_t) ke port 8010 (unreserved_port_t). Ketika Anda mulai nginx gagal

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

dan Anda (akhirnya) melihat log audit dan menemukan

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

Anda dapat menjalankan ini melalui audit2alllow dan secara naif menerima temuan itu

allow httpd_t port_t:tcp_socket name_bind;

yang kemudian memungkinkan httpd_t untuk terhubung ke port tcp. Ini mungkin bukan yang Anda inginkan.

Anda dapat menggunakan sesearch untuk menyelidiki kebijakan dan melihat jenis port apa yang bisa dinamai httpd_t

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

Di antara jenis-jenis lain http_t dapat diikat ke http_port_t. Sekarang Anda dapat menggunakan semanage untuk menggali lebih dalam.

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

Port 8010 tidak terdaftar. Karena kami ingin nginx mengikat ke port 8010, tidak masuk akal untuk menambahkannya ke daftar http_port_t

semanage port -a -t http_port_t -p tcp 8010

Sekarang nginx akan diizinkan untuk name_bind ke port 8010 dan tidak semua port tcp seperti di atas.

Bagaimana Anda tahu persis apa yang sedang diaktifkan?

Perubahan kebijakan cukup mudah dibaca, menjalankan pesan Anda di atas melalui audit2, mari kita dapatkan

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

yang tampaknya cukup jelas.

Yang pertama merujuk ke file dengan inum 76151. Anda dapat menggunakan find untuk mendapatkan namanya (find / -inum 76151) dan kemudian gunakan semanage fcontext -a -t ...untuk mengubah kebijakan dan restorecon untuk memperbaiki konteks.

Yang kedua berhubungan dengan /run/gunicorn/socketyang lagi-lagi memiliki konteks yang salah. Menggunakan sesearch kita dapat melihat bahwa http_t dapat terhubung ke unix_stream_sockets jenis (antara lain) http_t. Jadi kita bisa mengubah konteksnya misalnya

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

Ini mengatur konteks / run / gunicorn dan pohon | file di bawahnya ke httpd_t.

Bagaimana ini bisa berfungsi jika Anda mengatur mesin di bawah otomatisasi?

Anda perlu menganalisis sistem dan membuat perubahan yang sesuai dalam pengujian. Anda kemudian menggunakan alat otomasi Anda untuk menyebarkan perubahan, boneka dan mungkin memiliki dukungan untuk ini.

Tentu saja Anda dapat melakukan semuanya dalam produksi dengan SElinux diatur ke permisif. Kumpulkan semua pesan, menganalisisnya memutuskan perubahan Anda dan menyebarkannya.

Ada banyak lagi yang perlu diketahui tentang SELinux, tetapi itulah batas kemampuan saya, Michael Hampton lebih baik dan Mathew Ife jauh lebih baik lagi, mereka mungkin harus menambahkan lebih banyak.

user9517
sumber
1
Saran Anda menyeluruh dan membuat saya lebih dekat untuk menyelesaikan masalah ini sendiri, meskipun masih menyisakan saya sedikit. allow httpd_t httpd_sys_content_t:sock_file write;tidak cukup jelas bagi saya seperti yang Anda harapkan. Apa maksudnya kebijakan pada file itu perlu diubah (yaitu, apa yang terjadi setelahnya -tdalam semanageperintah?
drs
Juga, saya mendapatkan instruksi penggunaan saat menggunakan semanageperintah Anda secara langsung. Saya perlu menambahkan --addargumen.
drs
Sebenarnya, saya juga harus mengatakan bahwa setelah mengubah jenis file socket menjadi httpd_var_run_tseperti Michael Hampton dicatat di bawah ini, audit2allowpesannya adalah:allow httpd_t var_run_t:sock_file write;
drs
Sepertinya Anda mengaturnya untuk var_run_ttidak httpd_var_run_t.
user9517
@lain, hmm .. tidak ada dadu. Sekarang audit2allowberkataallow httpd_t var_run_t:sock_file write;
drs
2

Jenis yang ingin Anda gunakan tidak httpd_sys_content_t. Ini untuk file statis yang dimaksudkan untuk melayani server web kepada agen pengguna.

Untuk soket yang digunakan untuk komunikasi antarproses, tipe yang Anda cari adalah httpd_var_run_t.

Meskipun, harap dicatat bahwa karena Anda menjalankan gunicorn tanpa batasan, mungkin ada masalah tambahan berkomunikasi dengannya.

Michael Hampton
sumber
3
Terima kasih! Sepertinya ini menangani salah satu masalah SELinux. Adakah petunjuk tentang cara mengatur gunicorn (atau layanan lain) terbatas?
drs
1

Saya mencoba jawaban sebelumnya tanpa hasil, dalam kasus saya saya menggunakan server nginx sebagai antarmuka untuk aplikasi uwsgi menggunakan soket unix untuk mengkomunikasikannya, OS saya Ini adalah server Fedora 26.

Soket unix dibuat di direktori /var/local/myapp:

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

Untuk mengkonfigurasi SELinux saya harus menambahkan tipe konteks: httpd_sys_rw_content_t

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