So sánh AppArmor và SELinux trong môi trường Database
AppArmor (Application Armor) hoạt động dựa trên cơ chế path-based, nghĩa là nó kiểm soát quyền truy cập dựa trên đường dẫn tuyệt đối của file hoặc socket. Điều này giúp việc viết profile đơn giản, trực quan và dễ quản lý hơn cho các ứng dụng có cấu trúc file cố định như PostgreSQL hay MySQL.
SELinux (Security-Enhanced Linux) sử dụng cơ chế context-based (dựa trên nhãn bảo mật) và chính sách type enforcement. SELinux phức tạp hơn, yêu cầu định nghĩa các domain, type và booleans, nhưng mang lại khả năng kiểm soát chi tiết hơn về hành vi của tiến trình (process) và tài nguyên hệ thống, bất kể đường dẫn file nằm ở đâu.
Chọn lựa cho Database: Nếu bạn chạy trên Ubuntu/Debian, AppArmor là lựa chọn mặc định, ít gây xung đột hiệu năng và dễ debug hơn. Nếu bạn chạy trên RHEL/CentOS/Fedora, SELinux là tiêu chuẩn. Trong hướng dẫn này, chúng ta sẽ tập trung vào AppArmor vì tính thực tế cao trong môi trường triển khai nhanh, sau đó nêu nguyên lý tương đương cho SELinux.
Cấu hình AppArmor để cô lập PostgreSQL
Mục tiêu: Tạo một profile AppArmor tùy chỉnh (custom profile) để hạn chế PostgreSQL chỉ được truy cập vào thư mục dữ liệu (`/var/lib/postgresql`), thư mục log (`/var/log/postgresql`) và socket giao tiếp, đồng thời chặn hoàn toàn quyền truy cập vào các thư mục nhạy cảm khác như `/etc/shadow` hoặc `/root`.
Bước 1: Cài đặt và kích hoạt AppArmor (nếu chưa có)
Trên Ubuntu/Debian, AppArmor thường đã cài sẵn. Nếu chưa, hãy cài đặt gói `apparmor` và `apparmor-profiles`.
sudo apt update && sudo apt install apparmor apparmor-profiles -y
Kiểm tra trạng thái của AppArmor để đảm bảo nó đang chạy ở chế độ enforcing.
sudo aa-status
Kết quả mong đợi: Bạn thấy dòng `apparmor` đang ở chế độ `enforce` và có một số profile đang chạy (như `unconfined` hoặc các service mặc định).
Bước 2: Tạo Profile tùy chỉnh cho PostgreSQL
Chúng ta sẽ tạo một file profile mới tại `/etc/apparmor.d/local/usr.sbin.postgres` (hoặc `/etc/apparmor.d/usr.sbin.postgres` tùy phiên bản). Profile này sẽ thay thế hoặc bổ sung cho profile mặc định để thắt chặt hơn.
Tạo file config mới với nội dung dưới đây. Lưu ý: Profile này chỉ cho phép `r` (read), `w` (write), `x` (execute) cho các đường dẫn cụ thể cần thiết cho Database hoạt động.
cat > /etc/apparmor.d/local/usr.sbin.postgres
Kết quả mong đợi: File config được tạo thành công. Profile này sẽ giới hạn PostgreSQL chỉ hoạt động trong phạm vi thư mục dữ liệu và log, ngăn chặn truy cập trái phép vào hệ thống.
Bước 3: Kích hoạt và tải profile mới
Sử dụng lệnh `aa-enforce` để chuyển profile sang chế độ thực thi (enforce mode).
sudo aa-enforce /etc/apparmor.d/local/usr.sbin.postgres
Kiểm tra lại trạng thái để đảm bảo profile đã được gắn vào tiến trình `postgres`.
sudo aa-status | grep postgres
Kết quả mong đợi: Bạn thấy dòng `postgres` hoặc `/usr/bin/postgres` với trạng thái `enforce`.
Viết Policy SELinux tương đương cho MySQL/MariaDB (Trên RHEL/CentOS)
Mục tiêu: Nếu bạn đang sử dụng RHEL/CentOS/Fedora, AppArmor không khả dụng. Thay vào đó, ta dùng SELinux. Ta sẽ sử dụng công cụ `audit2allow` để tự động tạo policy từ log bị từ chối (denial).
Bước 1: Đặt chế độ Permissive để thu thập log
Đầu tiên, chuyển SELinux sang chế độ `permissive`. Trong chế độ này, SELinux chỉ ghi log lỗi mà không chặn thực sự, giúp ta quan sát được những gì MySQL cần.
sudo setenforce 0
Khởi động lại dịch vụ MySQL/MariaDB để tạo hoạt động và sinh log.
sudo systemctl restart mysqld
Thực hiện một số truy vấn cơ bản để kích hoạt các hành động.
sudo mysql -u root -p -e "SELECT VERSION(); SHOW DATABASES;"
Kiểm tra log denial trong `/var/log/audit/audit.log`.
grep "mysqld" /var/log/audit/audit.log | tail -n 20
Kết quả mong đợi: Bạn thấy các dòng log bắt đầu bằng `type=AVC msg=audit(...)` với `denied` và `comm="mysqld"`.
Bước 2: Tạo Policy từ log denied
Sử dụng công cụ `audit2allow` để phân tích log và tạo file policy `.te` (type enforcement).
sudo grep "mysqld" /var/log/audit/audit.log | audit2allow -M mysql_custom
Lệnh này sẽ tạo ra 2 file: `mysql_custom.te` (mã nguồn policy) và `mysql_custom.pp` (file compiled policy).
Để an toàn hơn, ta không load toàn bộ policy tự động mà kiểm tra nội dung file `.te` trước.
cat mysql_custom.te
Kết quả mong đợi: Bạn thấy các rule cho phép mysqld truy cập vào các file hoặc socket cụ thể mà nó đang bị từ chối.
Bước 3: Load Policy và chuyển về Enforcing
Load file policy đã biên dịch vào hệ thống.
sudo semodule -i mysql_custom.pp
Chuyển SELinux về chế độ `enforcing` để bảo vệ thực sự.
sudo setenforce 1
Khởi động lại MySQL để áp dụng chính sách mới.
sudo systemctl restart mysqld
Kiểm tra xem MySQL có chạy bình thường không và không còn lỗi denied mới.
grep "mysqld" /var/log/audit/audit.log | grep "denied" | tail -n 5
Kết quả mong đợi: Không còn dòng log `denied` nào mới xuất hiện liên quan đến hoạt động bình thường của MySQL.
Kiểm tra và xử lý các lỗi Denials
Mục tiêu: Sau khi kích hoạt AppArmor hoặc SELinux, Database có thể bị từ chối truy cập vào một số file cần thiết mà ta chưa khai báo. Ta cần biết cách đọc log và sửa profile để sửa lỗi.
Trường hợp 1: Xử lý lỗi Denial với AppArmor
Khi AppArmor chặn một hành động, nó sẽ ghi vào `/var/log/kern.log` hoặc `/var/log/syslog`.
Tìm kiếm các lỗi liên quan đến postgres.
sudo grep "APPARMOR" /var/log/syslog | grep "postgres" | tail -n 20
Hoặc dùng công cụ `dmesg` để xem log kernel mới nhất.
sudo dmesg | grep "APPARMOR" | grep "postgres"
Kết quả mẫu:
`audit: type=1400 audit(...): apparmor="DENIED" operation="open" profile="/usr/bin/postgres" name="/var/lib/postgresql/data/base/16384/12345" ...`
Phân tích: PostgreSQL cố gắng mở file `12345` trong thư mục `base/16384` nhưng bị chặn vì profile chưa cho phép quyền `r` (read) hoặc `w` (write) cho đường dẫn đó.
Sửa profile: Thêm quyền truy cập cụ thể vào file profile.
sudo nano /etc/apparmor.d/local/usr.sbin.postgres
Thêm dòng sau vào phần nội dung (thay vì `rw` chung chung nếu cần chi tiết, hoặc mở rộng wildcard `**`):
/var/lib/postgresql/data/base/** rwkl,
Tải lại profile sau khi sửa.
sudo aa-reload /etc/apparmor.d/local/usr.sbin.postgres
Kết quả mong đợi: Không còn dòng `APPARMOR DENIED` mới xuất hiện khi Database hoạt động.
Trường hợp 2: Xử lý lỗi Denial với SELinux
Sử dụng công cụ `ausearch` hoặc `grep` để tìm lỗi.
sudo ausearch -m avc -ts recent | grep mysqld
Kết quả mẫu:
`type=AVC msg=audit(...): avc: denied { read } for pid=1234 comm="mysqld" name="socket" scontext=system_u:system_r:mysqld_t:s0 tcontext=system_u:object_r:var_run_t:s0 tclass=unix_stream_socket`
Phân tích: mysqld (mysqld_t) bị từ chối đọc socket (var_run_t). Điều này thường xảy ra khi socket nằm ở vị trí lạ hoặc nhãn (label) sai.
Giải pháp 1: Chỉnh sửa nhãn file (restorecon) nếu file mới tạo bị sai nhãn.
sudo restorecon -Rv /var/run/mysqld
Giải pháp 2: Nếu lỗi vẫn còn và cần mở rộng quyền, tạo policy mới.
sudo ausearch -m avc -ts recent | grep mysqld | audit2allow -M mysql_fix
sudo semodule -i mysql_fix.pp
Kết quả mong đợi: MySQL hoạt động trơn tru, không còn lỗi AVC denied.
Verify kết quả cuối cùng
Kiểm tra tính toàn vẹn của Database: Đảm bảo Database vẫn có thể thực hiện các thao tác CRUD (Create, Read, Update, Delete) bình thường.
sudo -u postgres psql -c "SELECT 1;"
sudo -u postgres psql -c "CREATE TABLE test_hardening (id INT);"
sudo -u postgres psql -c "INSERT INTO test_hardening VALUES (1);"
sudo -u postgres psql -c "SELECT * FROM test_hardening;"
Kiểm tra khả năng chống truy cập trái phép: Thử thực hiện một lệnh mà profile đã chặn.
sudo -u postgres cat /etc/shadow
Kết quả mong đợi:
1. Các lệnh SQL chạy thành công.
2. Lệnh `cat /etc/shadow` bị từ chối với lỗi `Permission denied` (AppArmor) hoặc không thể mở file (SELinux), chứng tỏ cơ chế cô lập đã hoạt động.
Kiểm tra trạng thái bảo vệ cuối cùng:
sudo aa-status
sudo getenforce
Kết quả mong đợi: AppArmor hiển thị profile `postgres` đang `enforce`, SELinux hiển thị `Enforcing`.
Điều hướng series:
Mục lục: Series: Triển khai Database an toàn với Linux Kernel Hardening và eBPF
« Phần 2: Kiểm toán và tối ưu hóa tham số Kernel cho Database
Phần 4: Giới thiệu eBPF và công cụ BCC cho giám sát Database »