Quyền trong Linux trả lời câu hỏi «ai được đọc tệp này». AppArmor trả lời một câu khác: «chương trình này rốt cuộc được phép làm gì». Khác biệt lộ ra khi bị đột nhập. Một web shell chạy dưới danh nghĩa người dùng của máy chủ web và thừa hưởng toàn bộ quyền của nó — tức là quyền đọc hơn nửa hệ thống. Hồ sơ AppArmor giới hạn tiến trình trong danh sách những gì nó cần cho công việc, và một nỗ lực đọc /etc/shadow hay chạy /bin/bash sẽ kết thúc bằng từ chối bất kể quyền của người dùng là gì.

Cái gì đã được bật sẵn

sudo aa-status

Kết quả trả lời ba câu hỏi: có bao nhiêu hồ sơ được nạp, trong đó bao nhiêu ở chế độ enforce và complain, và những tiến trình nào chạy hoàn toàn không có hồ sơ. Trên một Ubuntu điển hình sẽ có vài chục hồ sơ, nhưng gần như tất cả là của các chương trình phụ trợ như mantcpdump. Các dịch vụ chính — nginx, Apache, PHP-FPM — thường không có trong danh sách bị giới hạn.

Ba chế độ cần phân biệt:

  • enforce — quy tắc được áp dụng, mọi thứ thừa đều bị từ chối;
  • complain — vi phạm chỉ được ghi vào nhật ký, chẳng có gì bị chặn. Chế độ để tinh chỉnh;
  • unconfined — không có hồ sơ, chương trình chạy không bị hạn chế.

Phần hữu ích nhất trong kết quả của aa-status là phần cuối: những tiến trình lắng nghe trên mạng và chẳng bị gì giới hạn. Đó là danh sách nên bắt đầu.

Công cụ

sudo apt install apparmor-utils

Thiếu gói đó thì các lệnh aa-complain, aa-enforceaa-logprof không có trong hệ thống, dù chính AppArmor vẫn đang chạy.

Bật một hồ sơ thế nào mà không dừng dịch vụ

Trình tự là điều nền tảng. Một hồ sơ chuyển thẳng sang enforce với xác suất cao sẽ từ chối một thứ dịch vụ cần, và dịch vụ sẽ ngừng hoạt động — thường không phải ngay lập tức mà ở một thao tác hiếm gặp nào đó như tải tệp lên hay gửi thư.

Trình tự đúng:

sudo aa-complain /etc/apparmor.d/usr.sbin.nginx

Một tuần làm việc ở chế độ đó, bao gồm mọi kịch bản bất thường: sao lưu, cập nhật, tải các tệp lớn lên. Sau đó hãy duyệt qua những gì đã tích lũy:

sudo aa-logprof

Lệnh này đi qua các vi phạm đã ghi nhận và hỏi với từng cái là có cho phép hay không. Ở đây cần chú ý: hãy cho phép những gì thực sự thuộc về công việc của dịch vụ, chứ không phải mọi thứ đập vào mắt — nếu không bạn sẽ có một hồ sơ cho phép tất cả, và ý nghĩa mất sạch.

Và chỉ đến lúc đó mới:

sudo aa-enforce /etc/apparmor.d/usr.sbin.nginx

Xem các lần từ chối ở đâu

Mọi vi phạm đều đi vào nhật ký nhân:

sudo journalctl -k | grep -i apparmor
sudo grep 'apparmor="DENIED"' /var/log/audit/audit.log

Tệp thứ hai tồn tại nếu auditd đã được cài — và khi có nó thì các bản ghi chi tiết hơn hẳn. Một bản ghi từ chối cho thấy tên hồ sơ, thao tác được yêu cầu và đường dẫn bị truy cập; thế là đủ để biết nên sửa hồ sơ hay nên mừng vì nó đã kích hoạt.

Có một triệu chứng đáng nhớ: dịch vụ hành xử kỳ lạ — không đọc được tệp cấu hình, không ghi được vào thư mục, không mở được socket — trong khi nhật ký của chính nó báo lỗi «permission denied» với những quyền rõ ràng là đúng. Đó gần như luôn là AppArmor, và việc đầu tiên cần làm là xem trong nhật ký nhân.

Một biện pháp thực tế, không phải lý thuyết

Một hồ sơ cho PHP-FPM hay nginx mang lại lợi ích theo cách rất cụ thể. Khi tiến trình bị giới hạn, một web shell chạm được tới trang web sẽ không đọc được tệp hệ thống, không chạy được shell, và không ghi được gì ngoài các thư mục được phép. Một trang web bị hack vẫn chỉ là một trang web bị hack thay vì biến thành quyền truy cập cả máy — và chính bước chuyển đó chiếm phần lớn thiệt hại.

Trình tự áp dụng hợp lý: trước hết là hồ sơ cho thứ hướng ra Internet (máy chủ web, PHP-FPM), rồi đến cơ sở dữ liệu, rồi tùy nhu cầu. Không cần bật tất cả cùng lúc, và cũng chẳng có bộ dựng sẵn phổ quát nào: hồ sơ phụ thuộc vào việc tệp của bạn nằm ở đâu.

Cần kiểm tra gì định kỳ

Hồ sơ quay về unconfined thường xuyên hơn bạn tưởng: một bản cập nhật gói có thể thay tệp hồ sơ, việc gỡ lỗi bằng tay để dịch vụ nằm lại ở complain, còn một dịch vụ mới thì đến mà chẳng có hồ sơ nào. Hai con số là hữu ích: có bao nhiêu hồ sơ ở enforce, và có bao nhiêu tiến trình hướng ra mạng đang unconfined. Sự thay đổi của bất kỳ con số nào cũng đáng để biết. Khi gom lại trên một trang thì nó trông ra sao — xem ở demo bên dưới.