ใช้งาน SELinux บน AlmaLinux และ Rocky Linux โดยไม่ต้องปิด

เข้าใจ Label ของ SELinux อ่าน AVC Denial และแก้ปัญหา Permission denied ด้วย restorecon, semanage และ setsebool โดยไม่ต้องปิด SELinux

โดย ทีมงาน THAI DATA CLOUD อัปเดต อ่าน 11 นาที เข้าชม 5 ครั้ง

แชร์FacebookXLINELinkedIn
AlmaLinux — ใช้งาน SELinux บน AlmaLinux และ Rocky Linux โดยไม่ต้องปิด
ใช้งาน SELinux บน AlmaLinux และ Rocky Linux โดยไม่ต้องปิด

คำตอบสั้น ๆ: เข้าใจ Label ของ SELinux อ่าน AVC Denial และแก้ปัญหา Permission denied ด้วย restorecon, semanage และ setsebool โดยไม่ต้องปิด SELinux

คู่มือนี้อธิบาย AlmaLinux ทีละขั้นตอน พร้อมคำสั่งที่ใช้ได้จริงและปัญหาที่พบบ่อย

SELinux (Security-Enhanced Linux) เปิดใช้งานมาตั้งแต่ติดตั้งบน AlmaLinux และ Rocky Linux เป็นชั้นป้องกันที่ทำงานเพิ่มจากสิทธิ์ไฟล์แบบปกติ แม้โปรแกรมจะรันเป็นผู้ใช้ที่อ่านไฟล์ได้ตาม chmod แต่ถ้านโยบายของ SELinux ไม่อนุญาต การเข้าถึงนั้นก็จะถูกปฏิเสธ ประโยชน์ที่ชัดเจนคือ ถ้าเว็บไซต์ถูกเจาะ ผู้โจมตีที่ได้สิทธิ์ของ Nginx หรือ Apache จะยังถูกจำกัดให้อยู่ในขอบเขตที่เว็บเซิร์ฟเวอร์ควรทำได้เท่านั้น

คำแนะนำในอินเทอร์เน็ตจำนวนมากบอกให้ "ปิด SELinux" ทันทีที่เจอ Permission denied บทความนี้แสดงวิธีที่ถูกต้องกว่า คือหาว่า SELinux ปฏิเสธอะไร แล้วแก้เฉพาะจุดด้วยเครื่องมือมาตรฐานสามตัว ได้แก่ File Context, Boolean และ Port Label ซึ่งครอบคลุมปัญหาที่พบบนเว็บเซิร์ฟเวอร์เกือบทั้งหมด

สิ่งที่ต้องเตรียม (AlmaLinux)

  • AlmaLinux หรือ Rocky Linux 8 หรือ 9 และผู้ใช้ที่มีสิทธิ์ sudo
  • ติดตั้งเครื่องมือจัดการ SELinux:
sudo dnf install -y policycoreutils-python-utils setroubleshoot-server

policycoreutils-python-utils ให้คำสั่ง semanage และ audit2why ส่วน setroubleshoot-server ให้คำสั่ง sealert ที่อธิบายสาเหตุเป็นภาษาคนอ่านเข้าใจ

ขั้นตอนที่ 1: ตรวจสถานะ SELinux (AlmaLinux)

getenforce
sestatus
โหมดความหมาย
Enforcingบังคับใช้นโยบาย ปฏิเสธและบันทึก Log (ค่าที่ควรใช้)
Permissiveไม่ปฏิเสธ แต่บันทึก Log ว่าจะปฏิเสธอะไร ใช้ตรวจหาปัญหาชั่วคราว
Disabledปิดทั้งหมด ไม่มีการบันทึก

ขั้นตอนที่ 2: เข้าใจ Label (AlmaLinux)

SELinux ตัดสินจาก Label (Context) ที่ติดอยู่กับทุกไฟล์และทุกโปรเซส ดูได้ด้วยตัวเลือก -Z:

ls -Z /var/www/html
ps -eZ | grep -E "nginx|httpd"

ตัวอย่างผลลัพธ์:

unconfined_u:object_r:httpd_sys_content_t:s0 index.html
system_u:system_r:httpd_t:s0    1320 ?  00:00:00 nginx

ส่วนที่สำคัญคือส่วนที่สาม เรียกว่า Type โปรเซส Nginx และ Apache รันใน Type httpd_t และนโยบายอนุญาตให้ httpd_t อ่านไฟล์ที่เป็น httpd_sys_content_t ได้ ถ้าไฟล์เว็บมี Type อื่น เช่น user_home_t หรือ default_t เว็บเซิร์ฟเวอร์จะอ่านไม่ได้ แม้สิทธิ์ chmod จะเปิดเต็มที่ก็ตาม

Type ที่ใช้บ่อยกับเว็บ:

Typeใช้กับ
httpd_sys_content_tไฟล์เว็บที่อ่านอย่างเดียว
httpd_sys_rw_content_tโฟลเดอร์ที่เว็บต้องเขียน เช่น wp-content/uploads, storage ของ Laravel
httpd_log_tไฟล์ Log ของเว็บเซิร์ฟเวอร์

ขั้นตอนที่ 3: หาว่า SELinux ปฏิเสธอะไร (AlmaLinux)

เมื่อเว็บขึ้น 403 หรือ 502 และ Log ของแอปแจ้ง Permission denied ทั้งที่สิทธิ์ไฟล์ถูกต้อง ให้ดูบันทึกการปฏิเสธ (AVC Denial):

sudo ausearch -m AVC,USER_AVC -ts recent

ตัวอย่างบรรทัดที่พบ:

type=AVC msg=audit(...): avc:  denied  { read } for  pid=1320 comm="nginx"
  name="index.html" scontext=system_u:system_r:httpd_t:s0
  tcontext=unconfined_u:object_r:user_home_t:s0 tclass=file permissive=0

อ่านได้ว่า โปรเซส nginx (Type httpd_t) ถูกปฏิเสธการ read ไฟล์ที่มี Type user_home_t ให้ส่งผลนี้เข้า audit2why หรือใช้ sealert เพื่อดูคำแนะนำ:

sudo ausearch -m AVC -ts recent | audit2why
sudo sealert -a /var/log/audit/audit.log

sealert มักบอกคำสั่งที่ควรใช้แก้มาให้ด้วย แต่ให้อ่านและเข้าใจก่อนทำตาม

ขั้นตอนที่ 4: แก้ปัญหาไฟล์ด้วย File Context

สาเหตุที่พบบ่อยที่สุดคือ ใช้ mv ย้ายไฟล์ จาก Home Directory ไปไว้ที่โฟลเดอร์เว็บ mv จะพา Label เดิม (user_home_t) ติดไปด้วย ส่วน cp จะให้ Label ตามโฟลเดอร์ปลายทาง วิธีแก้คือรีเซ็ต Label ให้ตรงกับนโยบาย:

sudo restorecon -Rv /var/www/example.com

ผลลัพธ์จะแสดงบรรทัด Relabeled ... from ... to ... สำหรับไฟล์ที่ถูกแก้

ถ้าเว็บอยู่นอกโฟลเดอร์มาตรฐาน เช่น /srv/www หรือ /data/sites ต้องเพิ่มกฎถาวรก่อน แล้วค่อย restorecon:

sudo semanage fcontext -a -t httpd_sys_content_t "/srv/www(/.*)?"
sudo restorecon -Rv /srv/www

โฟลเดอร์ที่เว็บต้องเขียนได้ ให้กำหนดเฉพาะโฟลเดอร์นั้น ไม่ใช่ทั้งเว็บ:

sudo semanage fcontext -a -t httpd_sys_rw_content_t "/srv/www/example.com/wp-content/uploads(/.*)?"
sudo restorecon -Rv /srv/www/example.com/wp-content/uploads

ดูกฎที่คุณเพิ่มไว้ทั้งหมดด้วย sudo semanage fcontext -l -C อย่าใช้ chcon เป็นวิธีถาวร เพราะค่าจาก chcon จะหายเมื่อมีการ Relabel ทั้งระบบ

ขั้นตอนที่ 5: เปิดความสามารถด้วย Boolean

Boolean คือสวิตช์เปิดปิดพฤติกรรมที่นโยบายเตรียมไว้ให้ ดูรายการของเว็บเซิร์ฟเวอร์ได้ด้วย:

getsebool -a | grep httpd

ที่ใช้บ่อย:

Booleanเปิดเมื่อ
httpd_can_network_connectเว็บต้องเชื่อมต่อออกไปยังเครือข่าย เช่น Nginx เป็น Reverse Proxy ให้แอป Node.js ที่พอร์ต 3000 หรือ PHP เรียก API ภายนอก
httpd_can_network_connect_dbเว็บต้องต่อฐานข้อมูลผ่าน TCP (เช่น ฐานข้อมูลอยู่อีกเครื่อง)
httpd_can_sendmailPHP ต้องส่งอีเมลผ่าน sendmail ในเครื่อง
httpd_enable_homedirsต้องให้บริการไฟล์จาก Home Directory ของผู้ใช้

เปิดแบบถาวรด้วยตัวเลือก -P (ไม่มี -P ค่าจะหายเมื่อรีบูต):

sudo setsebool -P httpd_can_network_connect on

อาการที่บ่งบอกว่าต้องเปิด Boolean ตัวแรก คือ Nginx แจ้ง 502 Bad Gateway และ Error Log มีข้อความ connect() to 127.0.0.1:3000 failed (13: Permission denied) ซึ่งพบบ่อยในการตั้ง Node.js กับ Nginx Reverse Proxy

ขั้นตอนที่ 6: อนุญาตพอร์ตที่ไม่ใช่ค่ามาตรฐาน

SELinux กำหนดว่าแต่ละ Service Bind พอร์ตใดได้บ้าง ถ้าคุณเปลี่ยน SSH ไปพอร์ต 2222 หรือให้ Nginx ฟังที่พอร์ตที่ไม่อยู่ในรายการ Service จะเริ่มไม่ได้ ตรวจรายการก่อน:

sudo semanage port -l | grep -E "^(ssh_port_t|http_port_t)"

เพิ่มพอร์ตที่ต้องการ:

sudo semanage port -a -t ssh_port_t -p tcp 2222
sudo semanage port -a -t http_port_t -p tcp 8090

ถ้าคำสั่งแจ้งว่าพอร์ตนั้นมี Type อื่นกำหนดไว้แล้ว ให้ใช้ -m แทน -a เพื่อแก้ไข การเปลี่ยนพอร์ต SSH ต้องทำขั้นตอนนี้ก่อนรีสตาร์ต SSH เสมอ และต้องเปิด SSH Session เดิมค้างไว้ แล้วทดสอบเข้าด้วยหน้าต่างใหม่ก่อนปิด ดูขั้นตอนเต็มที่ วิธีเปลี่ยน SSH Port บน Linux Server

ตรวจสอบผลลัพธ์

  • getenforce ยังเป็น Enforcing
  • ทดสอบเว็บหรือ Service ที่มีปัญหาอีกครั้ง แล้วรัน sudo ausearch -m AVC -ts recent ต้องไม่มีบรรทัดปฏิเสธใหม่ (อาจแสดง <no matches>)
  • ls -Z บนโฟลเดอร์เว็บแสดง Type ตามที่ตั้งไว้

ใช้ Permissive เพื่อวินิจฉัยเท่านั้น

ถ้าต้องการยืนยันว่าปัญหามาจาก SELinux จริงหรือไม่ ให้สลับเป็น Permissive ชั่วคราว ทดสอบ แล้วสลับกลับทันที:

sudo setenforce 0
# ทดสอบเว็บ
sudo setenforce 1

วิธีที่แคบกว่าคือทำให้เฉพาะ Domain ของเว็บเซิร์ฟเวอร์เป็น Permissive ขณะที่ส่วนอื่นยัง Enforcing:

sudo semanage permissive -a httpd_t
# หลังตรวจเสร็จ
sudo semanage permissive -d httpd_t

ปัญหาที่พบบ่อยเกี่ยวกับ AlmaLinux

ใช้ audit2allow สร้าง Module แล้วปัญหาหาย แต่ไม่รู้ว่าอนุญาตอะไรไป

audit2allow -M สร้างกฎจาก Log ทุกบรรทัดที่ได้รับ ซึ่งอาจอนุญาตกว้างเกินไป ใช้ได้เมื่อไม่มี Boolean หรือ File Context ที่ตรงกับกรณีของคุณแล้วเท่านั้น และต้องอ่านไฟล์ .te ที่สร้างขึ้นก่อนติดตั้ง

เคยปิด SELinux แล้วเปิดกลับ ระบบบูตแล้วมีปัญหาเต็มไปหมด

ขณะปิด ไฟล์ที่สร้างใหม่จะไม่มี Label ต้อง Relabel ทั้งระบบก่อนเปิดใช้งาน โดยตั้ง SELINUX=permissive ใน /etc/selinux/config แล้วรัน sudo touch /.autorelabel และรีบูต (ใช้เวลานานตามจำนวนไฟล์) เมื่อบูตเสร็จและไม่มี Denial สำคัญ จึงเปลี่ยนเป็น enforcing บน AlmaLinux/Rocky 9 การตั้ง SELINUX=disabled ในไฟล์นี้ไม่ได้ปิดทั้งหมดอีกต่อไป ต้องใช้ Kernel Parameter selinux=0 ซึ่งเป็นอีกเหตุผลที่ไม่ควรปิด

ไม่เห็น AVC ใน Log ทั้งที่สงสัยว่าเป็น SELinux

บางกฎถูกตั้งให้ปฏิเสธแบบไม่บันทึก (dontaudit) ปิดชั่วคราวด้วย sudo semodule -DB ทดสอบซ้ำ แล้วเปิดกลับด้วย sudo semodule -B

หากตรวจ Log แล้วยังหาทางแก้ที่ไม่ต้องปิด SELinux ไม่ได้ ติดต่อทีมซัพพอร์ต THAI DATA CLOUD ได้ที่ https://thaidata.cloud/contact/

สรุปขั้นตอน AlmaLinux

ทบทวน AlmaLinux ทั้งหมดตามลำดับ ก่อนนำไปใช้กับระบบจริง

  1. ตรวจสถานะ SELinux (AlmaLinux)
  2. เข้าใจ Label (AlmaLinux)
  3. หาว่า SELinux ปฏิเสธอะไร (AlmaLinux)
  4. แก้ปัญหาไฟล์ด้วย File Context
  5. เปิดความสามารถด้วย Boolean
  6. อนุญาตพอร์ตที่ไม่ใช่ค่ามาตรฐาน

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

อ่านเพิ่มเติมเกี่ยวกับ AlmaLinux

แชร์FacebookXLINELinkedIn

มีคำถามเรื่องบริการ? ติดต่อทีมงาน