Làm chủ SELinux trên RHEL và Rocky Linux: Quản lý Context, Boolean và khắc phục lỗi từ chối truy cập với audit2allow

Linux tutorial - IT technology blog
Linux tutorial - IT technology blog

So sánh các phương pháp: Xử lý lỗi từ chối truy cập SELinux trên môi trường Production

Hệ thống giám sát của bạn kích hoạt cảnh báo lúc 2 giờ sáng. Nginx reverse proxy mới triển khai trên Rocky Linux 9 không thể phân phối các tài nguyên tĩnh (static assets) từ một thư mục tùy chỉnh, liên tục trả về mã lỗi 403 Forbidden và 500 Internal Server Error. Phân quyền POSIX truyền thống hoàn toàn bình thường—0755 với quyền sở hữu là nginx:nginx. Tuy nhiên, daemon vẫn không thể truy cập vào các tệp tin này. Rào cản ở đây chính là SELinux (Security-Enhanced Linux) đang thực thi cơ chế Mandatory Access Control (MAC).

Khi sự cố đang xảy ra, các kỹ sư thường chọn một trong bốn hướng tiếp cận sau để xử lý các lỗi từ chối truy cập (denial) của SELinux:

  • Phương pháp 1: Tắt SELinux (setenforce 0 hoặc chỉnh sửa /etc/selinux/config) — Cách giải quyết nhanh đầy rủi ro khi loại bỏ hoàn toàn các lớp bảo vệ MAC trên toàn bộ máy chủ. Phương pháp này xử lý lỗi ngay lập tức nhưng khiến hệ điều hành hoàn toàn không còn được bảo vệ.
  • Phương pháp 2: Bật/tắt SELinux Boolean (setsebool -P) — Thay đổi các công tắc ở cấp độ kernel đã được Red Hat cấu hình sẵn. Hướng tiếp cận này mở khóa an toàn cho các tác vụ phổ biến, chẳng hạn như cho phép reverse proxy kết nối tới backend socket trên cổng 8080 hoặc truy cập PostgreSQL từ xa trên cổng 5432.
  • Phương pháp 3: Gán lại Security Context (semanage fcontext + restorecon) — Cập nhật nhãn định danh tệp và thư mục bền vững để các daemon có thể truy cập tài nguyên tại các đường dẫn không chuẩn (như /data/web/).
  • Phương pháp 4: Tạo Module Policy tùy chỉnh (audit2allow) — Phân tích nhật ký từ chối AVC (Access Vector Cache) để biên dịch các module Type Enforcement (.pp) chuyên dụng cho các daemon tự phát triển hoặc các system call không chuẩn.

Trên một máy chủ Rocky Linux 9 chịu tải cao với hơn 4.000 yêu cầu mỗi giây, việc tắt SELinux sẽ phá hủy các tiêu chuẩn tuân thủ SOC2 và PCI-DSS chỉ bằng một câu lệnh duy nhất. Một quy trình xử lý sự cố có bài bản sẽ giúp bạn cô lập nguyên nhân gốc rễ, áp dụng giải pháp chặt chẽ nhất có thể và giữ an toàn cho toàn bộ hệ thống production.

Ưu và nhược điểm của các chiến lược xử lý sự cố SELinux

Mỗi hướng xử lý đều đi kèm với những đánh đổi vận hành riêng biệt. Dưới đây là bảng so sánh chi tiết:

Phương pháp Ưu điểm Nhược điểm Rủi ro trên Production
Tắt SELinux / Chuyển sang Permissive Mode Khôi phục lưu lượng dịch vụ chỉ trong vòng chưa đầy 5 giây khi xảy ra sự cố nghiêm trọng. Xóa bỏ lớp cô lập ở cấp kernel, che giấu lỗi cấu hình phân quyền và không đạt các chứng chỉ tuân thủ (PCI-DSS, SOC2, HIPAA). Rất cao (Critical)
SELinux Boolean (setsebool -P) Đã được nhà cung cấp kiểm thử kỹ lưỡng, lưu lại cấu hình sau khi reboot và có hiệu lực ngay lập tức mà không cần biên dịch policy. Chỉ áp dụng cho các hành vi đã được dự tính và lập trình sẵn bởi đội ngũ phát triển policy của Red Hat. Rất thấp (Minimal)
Gán lại Context (semanage + restorecon) Thực thi nghiêm ngặt nguyên tắc đặc quyền tối thiểu (least privilege) bằng các định nghĩa targeted policy tiêu chuẩn. Đòi hỏi hiểu biết về file context và các mẫu regex đường dẫn. Rất thấp (Very Low)
Module tùy chỉnh (audit2allow) Khắc phục sự cố truy cập cho các phần mềm nhị phân nội bộ hoặc agent chuyên biệt khi không có sẵn boolean mặc định. Có thể vô tình cấp các quyền hạn nguy hiểm (chẳng hạn như quyền execmem diện rộng) nếu tạo policy từ log dump chưa qua sàng lọc. Trung bình (Moderate)

Mô hình khuyến nghị: Phân cấp xử lý sự cố từng bước

Tuyệt đối không để máy chủ production chạy ở chế độ permissive. Thay vào đó, hãy thực hiện tuần tự theo quy trình 4 bước sau:

  1. Kiểm tra nhật ký audit: Truy vấn tệp /var/log/audit/audit.log bằng lệnh ausearch để xác định chính xác syscall bị chặn.
  2. Kiểm tra boolean có sẵn: Xác minh xem Red Hat đã cung cấp sẵn công tắc boolean cho hành động bạn cần thực hiện hay chưa.
  3. Sửa nhãn thư mục và tệp: Đảm bảo các đường dẫn lưu trữ tùy chỉnh được gắn đúng type context (ví dụ: httpd_sys_content_t cho tài nguyên web tĩnh).
  4. Xây dựng module tùy chỉnh: Chỉ sử dụng audit2allow khi cả boolean và việc gán lại context đều không đáp ứng được yêu cầu của daemon.

Hướng dẫn triển khai: Chẩn đoán và khắc phục lỗi SELinux Denial

Bước 1: Chẩn đoán lỗi Access Vector Cache (AVC) Denial

Bắt đầu bằng việc kiểm tra trạng thái thực thi hiện tại của SELinux trên hệ thống:

getenforce
# Kết quả: Enforcing

sestatus

Để xác nhận chính xác SELinux có phải là nguyên nhân gây lỗi hay không, hãy chuyển tạm thời sang chế độ permissive và kiểm tra endpoint bằng curl -I http://localhost/:

# Tạm thời chuyển sang chế độ permissive để kiểm tra
setenforce 0

# Kiểm tra ứng dụng ngay lập tức; nếu trả về HTTP 200, SELinux chính là nguyên nhân gây chặn
curl -I http://127.0.0.1:80/

# Bật lại chế độ enforcement ngay lập tức
setenforce 1

Tiếp theo, trích xuất thông tin chi tiết về các lỗi từ chối truy cập từ audit log:

# Tìm kiếm các lỗi AVC denial gần đây trong vòng 10 phút qua
ausearch -m AVC,USER_AVC -ts recent

# Phân tích log audit thô bằng audit2why để nhận giải thích rõ ràng về nguyên nhân gốc rễ
ausearch -c 'nginx' --raw | audit2why

audit2why sẽ dịch các thông điệp AVC khó hiểu thành các hướng dẫn trực quan, dễ hiểu. Công cụ này sẽ chỉ rõ bạn cần bật boolean nào hay phải điều chỉnh lại nhãn file nào.

Bước 2: Xử lý lỗi không khớp File Context (semanage fcontext & restorecon)

Khi bạn lưu dữ liệu website tại các đường dẫn tùy chỉnh như /data/web/app1 thay vì đường dẫn chuẩn /var/www/html, thư mục sẽ kế thừa nhãn mặc định default_t hoặc var_t. Nginx chạy trong domain httpd_t và không có quyền đọc các nhãn này.

Kiểm tra các thuộc tính bảo mật hiện tại:

ls -lZ /data/web/app1
# Kết quả: -rw-r--r--. 1 nginx nginx unconfined_u:object_r:default_t:s0 index.html

Cài đặt các công cụ quản lý, khai báo quy tắc context phù hợp vào cơ sở dữ liệu policy của SELinux và áp dụng xuống hệ thống tệp tin:

# Cài đặt policycoreutils nếu chưa có lệnh semanage
dnf install -y policycoreutils-python-utils

# Đăng ký định nghĩa context bền vững cho thư mục tùy chỉnh
semanage fcontext -a -t httpd_sys_content_t "/data/web/app1(/.*)?"

# Gán lại nhãn đệ quy cho toàn bộ cây thư mục và hiển thị chi tiết tiến trình
restorecon -Rv /data/web/app1

# Xác minh context đã được cập nhật
ls -lZ /data/web/app1
# Kết quả: -rw-r--r--. 1 nginx nginx unconfined_u:object_r:httpd_sys_content_t:s0 index.html

Bước 3: Quản lý giao tiếp mạng bằng Boolean

Theo mặc định, các web daemon không thể mở kết nối mạng đến các máy chủ ứng dụng backend (như PHP-FPM trên cổng 9000 hay Gunicorn trên cổng 8000) hoặc cơ sở dữ liệu từ xa. SELinux mặc định sẽ từ chối các thao tác socket này.

Tìm kiếm các boolean liên quan quản lý dịch vụ web:

getsebool -a | grep httpd

Bật các quyền truy cập mạng cần thiết. Luôn thêm cờ -P để lưu thay đổi vĩnh viễn vào ổ đĩa:

# Cho phép Nginx/Apache proxy request đến các dịch vụ mạng upstream ở backend
setsebool -P httpd_can_network_connect 1

# Cho phép Nginx/Apache kết nối trực tiếp đến máy chủ cơ sở dữ liệu
setsebool -P httpd_can_network_connect_db 1

Bước 4: Xây dựng Module Policy tùy chỉnh bằng audit2allow

Các microservice nội bộ, agent giám sát tùy chỉnh hoặc phần mềm của bên thứ ba có thể thực hiện các system call hợp lệ nhưng không có boolean mặc định nào hỗ trợ. Trong những tình huống này, hãy sử dụng audit2allow để xây dựng một module policy Type Enforcement với phạm vi quyền hạn tối thiểu.

Trước tiên, xem trước các quy tắc Type Enforcement (.te) mà không cần biên dịch:

# Kiểm tra chính xác các quy tắc allow mà audit2allow đề xuất
ausearch -c 'custom_agent' --raw | audit2allow -m custom_agent

Kiểm tra kỹ lưỡng kết quả đầu ra. Đảm bảo nó chỉ cấp quyền cho các tệp hoặc quyền hạn thực sự cần thiết cho dịch vụ. Khi đã chắc chắn, tiến hành tạo cả tệp Type Enforcement và gói nhị phân đã biên dịch (.pp):

# Tạo tệp custom_agent.te và custom_agent.pp
ausearch -c 'custom_agent' --raw | audit2allow -M custom_agent

# Xác minh lại các quy tắc nguồn lần cuối
cat custom_agent.te

# Nạp module policy đã biên dịch vào kernel đang hoạt động
semodule -i custom_agent.pp

Bước 5: Xác minh tính bền vững của Policy sau khi khởi động lại

Xác nhận rằng module policy mới đã hoạt động trong kho lưu trữ policy của hệ thống:

semodule -l | grep custom_agent

Theo dõi trực tiếp audit log trong quá trình ứng dụng hoạt động bình thường để đảm bảo tất cả các lỗi từ chối truy cập đã được giải quyết triệt để:

tail -f /var/log/audit/audit.log | grep -E "type=AVC.*denied"

Bằng cách kết hợp linh hoạt giữa file context bền vững (semanage), boolean vĩnh viễn (setsebool -P) và các gói policy chuyên biệt (semodule), hệ thống RHEL và Rocky Linux của bạn sẽ luôn được bảo vệ nghiêm ngặt, vận hành ổn định và đáp ứng đầy đủ các tiêu chuẩn tuân thủ qua các lần cập nhật kernel hay khởi động lại hệ thống.

Share: