ฉันจะบอกให้ SELinux อนุญาตให้ nginx เข้าถึงซ็อกเก็ตยูนิกซ์ได้โดยไม่ต้อง audit2allow ได้อย่างไร


10

ฉันมีคำขอส่งต่อ Nginx เพื่อ gunicorn /run/gunicorn/socketผ่านซ็อกเก็ตที่ใช้ระบบปฏิบัติการยูนิกซ์ โดยค่าเริ่มต้นพฤติกรรมนี้ไม่ได้รับอนุญาตจาก 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)

ทุกที่ที่ฉันดู (เช่นที่นี่และที่นี่ ) คำแนะนำในการเปิดใช้งานคำพูดนี้เพื่อขอให้ nginx มีการปฏิเสธคำขอจาก SELinux จากนั้นเรียกใช้audit2allowเพื่ออนุญาตคำขอในอนาคต ฉันไม่สามารถหาคำสั่งใด ๆchconหรือsemanageคำสั่งที่อนุญาตพฤติกรรมนี้อย่างชัดเจน

นี่เป็นวิธีเดียวหรือไม่ ดูเหมือนว่าไร้สาระที่คุณไม่สามารถตั้งค่านโยบายที่อนุญาตให้ nginx เขียนไปยังซ็อกเก็ตโดยที่ไม่ได้พยายามปฏิเสธก่อนแล้วจึงเรียกใช้เครื่องมือที่ช่วยให้สิ่งต่าง ๆ ถูกปฏิเสธ คุณจะรู้ได้อย่างแม่นยำว่ากำลังเปิดใช้งานอะไรอยู่ สิ่งนี้จะทำงานอย่างไรถ้าการตั้งค่าเครื่องภายใต้ระบบอัตโนมัติ?

ฉันใช้ CentOS 7


คุณต้องแสดงให้เราเห็นว่า AVC ปฏิเสธข้อความและจะเป็นการดีที่จะรู้ว่าระบบปฏิบัติการและเวอร์ชั่นใดที่คุณใช้งานอยู่
user9517

@ จุดที่ดีที่ดี
drs

คำตอบ:


23

ดูเหมือนว่าไร้สาระที่คุณไม่สามารถตั้งค่านโยบายที่อนุญาตให้ nginx เขียนไปยังซ็อกเก็ตโดยที่ไม่ได้พยายามปฏิเสธก่อนแล้วจึงเรียกใช้เครื่องมือที่ช่วยให้สิ่งต่าง ๆ ถูกปฏิเสธ

ไม่มีเลย SELinux คือการควบคุมการเข้าถึงที่จำเป็นสิ่งต่าง ๆ ถูกปฏิเสธโดยค่าเริ่มต้นและคุณต้องอนุญาตอะไรบางอย่างอย่างชัดเจน หากผู้เขียนนโยบายไม่ได้พิจารณาสแต็ค (ตรงไปตรง) เฉพาะหรือผู้เขียน daemon ของไม่ได้ทำให้มัน SELinux ทราบและเขียนนโยบายสำหรับมันแล้วคุณจะอยู่ในตัวคุณเอง คุณต้องวิเคราะห์สิ่งที่บริการของคุณกำลังทำอยู่และวิธีการที่พวกเขาโต้ตอบกับ SELinux และกำหนดนโยบายของคุณเองเพื่อให้อนุญาต มีเครื่องมือที่จะช่วยให้คุณตรวจสอบ 2why , audit2allowฯลฯ

... นี่เป็นวิธีเดียวหรือไม่

ไม่ แต่ขึ้นอยู่กับสิ่งที่คุณพยายามทำและวิธีที่คุณพยายามทำเช่นนั้นกับวิธีแก้ปัญหา ตัวอย่างเช่นคุณอาจต้องการผูก nginx (httpd_t) กับพอร์ต 8010 (unreserved_port_t) เมื่อคุณเริ่ม nginx มันล้มเหลว

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

และคุณ (ในที่สุด) ดูในบันทึกการตรวจสอบและค้นหา

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

คุณอาจดำเนินการผ่าน audit2alllow และยอมรับข้อค้นพบอย่างไร้เดียงสา

allow httpd_t port_t:tcp_socket name_bind;

ซึ่งอนุญาตให้ httpd_t เชื่อมต่อกับพอร์ต tcp ใด ๆ นี่อาจไม่ใช่สิ่งที่คุณต้องการ

คุณสามารถใช้sesearchเพื่อตรวจสอบนโยบายและดูว่าพอร์ตประเภทใด httpd_t ที่สามารถ 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 ;
...

ในบรรดาประเภทอื่น ๆ http_t สามารถผูกกับ http_port_t ตอนนี้คุณสามารถใช้เซมาเนจเพื่อขุดลึกลงไปอีกเล็กน้อย

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

พอร์ต 8010 ไม่อยู่ในรายการ เนื่องจากเราต้องการให้ nginx เชื่อมโยงกับพอร์ต 8010 จึงไม่มีเหตุผลที่จะเพิ่มลงในรายการ http_port_t

semanage port -a -t http_port_t -p tcp 8010

ตอนนี้ nginx จะได้รับอนุญาตให้ name_bind ไปที่พอร์ต 8010 และไม่ใช่ทุกพอร์ต tcp ดังที่กล่าวมา

คุณจะรู้ได้อย่างแม่นยำว่ากำลังเปิดใช้งานอะไรอยู่

การเปลี่ยนแปลงนโยบายค่อนข้างง่ายต่อการอ่านเรียกใช้ข้อความของคุณด้านบนผ่านทาง audit2allow ที่เราได้รับ

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

ซึ่งดูเหมือนจะอธิบายด้วยตนเองอย่างเป็นธรรม

ตัวแรกหมายถึงไฟล์ที่มี inum 76151 คุณสามารถใช้ find เพื่อรับชื่อ (find / -inum 76151) จากนั้นใช้semanage fcontext -a -t ...เพื่อเปลี่ยนนโยบายและ restorecon เพื่อแก้ไขบริบท

เรื่องที่สองเกี่ยวข้องกับ/run/gunicorn/socketบริบทที่ไม่ถูกต้องอีกครั้ง การใช้ sesearch เราจะเห็นว่า http_t สามารถเชื่อมต่อกับ unix_stream_sockets ประเภท (ท่ามกลางคนอื่น ๆ ) http_t ดังนั้นเราสามารถเปลี่ยนบริบทให้สอดคล้องกันเช่น

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

สิ่งนี้ตั้งค่าบริบทของ / run / gunicorn และ tree | ไฟล์ด้านล่างเป็น httpd_t

สิ่งนี้จะทำงานอย่างไรถ้าการตั้งค่าเครื่องภายใต้ระบบอัตโนมัติ?

คุณต้องวิเคราะห์ระบบและทำการเปลี่ยนแปลงที่เหมาะสมในการทดสอบ จากนั้นคุณใช้เครื่องมืออัตโนมัติของคุณเพื่อปรับใช้การเปลี่ยนแปลงหุ่นเชิดและ ansible ได้รับการสนับสนุนในเรื่องนี้

แน่นอนคุณสามารถทำมันทั้งหมดในการผลิตด้วย SElinux กำหนดให้อนุญาต รวบรวมข้อความทั้งหมดวิเคราะห์การตัดสินใจของคุณและปรับใช้พวกเขา

มีอะไรอีกมากมายที่ต้องรู้เกี่ยวกับ SELinux แต่นั่นเป็นข้อ จำกัด ด้านทักษะของฉัน Michael Hampton ดีกว่าและ Mathew Ife ดีกว่าอีกครั้งพวกเขาอาจมีอะไรเพิ่มเติม


1
คำแนะนำของคุณอย่างละเอียดและทำให้ฉันเข้าใกล้การแก้ไขปัญหาเหล่านี้ด้วยตัวเองถึงแม้ว่าจะทำให้ฉันสั้น allow httpd_t httpd_sys_content_t:sock_file write;ไม่ใช่อธิบายให้ฉันอย่างที่คุณหวัง นี่คือสิ่งที่บอกว่านโยบายในไฟล์นั้นจะต้องมีการเปลี่ยนเป็น (เช่นสิ่งที่จะไปหลังจาก-tในsemanageคำสั่ง?
drs

นอกจากนี้ฉันยังได้รับคำแนะนำการใช้งานเมื่อใช้semanageคำสั่งของคุณโดยตรง ฉันต้องการเพิ่มการ--addโต้แย้ง
drs

ที่จริงแล้วฉันควรจะบอกด้วยว่าหลังจากเปลี่ยนประเภทของไฟล์ซ็อกเก็ตhttpd_var_run_tเป็นตามที่ Michael Hampton ระบุไว้ด้านล่างaudit2allowข้อความคือ:allow httpd_t var_run_t:sock_file write;
drs

ดูเหมือนว่าคุณตั้งค่าให้ไม่ได้var_run_t httpd_var_run_t
user9517

@lain อืม .. ไม่มีลูกเต๋า ตอนนี้audit2allowพูดว่าallow httpd_t var_run_t:sock_file write;
drs

2

httpd_sys_content_tประเภทที่คุณต้องการที่จะใช้งานไม่ได้ นี่เป็นไฟล์สแตติกที่เว็บเซิร์ฟเวอร์มีไว้เพื่อให้บริการกับตัวแทนผู้ใช้

httpd_var_run_tสำหรับซ็อกเก็ตที่ใช้สำหรับการสื่อสารประเภทที่คุณกำลังมองหาอยู่

แม้ว่าโปรดทราบว่าเนื่องจากคุณใช้งานปืนที่ไม่มีการกำหนดไว้อาจมีปัญหาเพิ่มเติมในการสื่อสารกับมัน


3
ขอบคุณ! ดูเหมือนว่าสิ่งนี้จะดูแลปัญหาหนึ่งใน SELinux ตัวชี้ใด ๆ เกี่ยวกับวิธีการตั้งค่า gunicorn (หรือบริการอื่น ๆ ) ถูกคุมขัง?
drs

1

ฉันลองคำตอบก่อนหน้านี้ไม่ประสบความสำเร็จในกรณีของฉันฉันใช้เซิร์ฟเวอร์ nginx เป็นส่วนหน้าสำหรับแอปพลิเคชัน uwsgi ที่ใช้ซ็อกเก็ตยูนิกซ์เพื่อสื่อสารกับพวกเขาระบบปฏิบัติการของฉันมันเป็นเซิร์ฟเวอร์ Fedora 26

ซ็อกเก็ตยูนิกซ์ถูกสร้างขึ้นในไดเรกทอรี/var/local/myapp:

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

ในการกำหนดค่า SELinux ฉันต้องเพิ่มประเภทบริบท: httpd_sys_rw_content_t

semanage fcontext -at httpd_sys_rw_content_t "/var/local/myapp(/.*)?"
restorecon -R -v '/var/local/myapp' 
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.