Hướng dẫn cấu hình AppArmor trên Ubuntu: Giới hạn quyền tiến trình để bảo vệ server

Security tutorial - IT technology blog
Security tutorial - IT technology blog

Bảo vệ server: Không chỉ có firewall và SSH

Anh em làm hệ thống chắc không lạ gì chuyện gia cố server. Chúng ta thường bắt đầu với những thứ cơ bản: cấu hình firewall với ufw, đổi port SSH, cấm login bằng password, hay cài Fail2Ban. Nhưng đó mới chỉ là phòng thủ vòng ngoài. Điều gì sẽ xảy ra nếu một plugin WordPress cũ trên server của bạn dính lỗ hổng RCE (Thực thi mã từ xa)? Kẻ tấn công đã vào được bên trong. Chúng sẽ làm gì tiếp theo?

Mình từng có một kỷ niệm nhớ đời lúc nửa đêm. Con server cá nhân bị một con bot brute-force SSH với hàng nghìn lượt truy cập mỗi phút. May mà mình phát hiện kịp và chưa mất mát gì nghiêm trọng. Từ lần đó, mình luôn bị ám ảnh bởi việc phải bảo mật từ trong ra ngoài. Khi kẻ tấn công đã vào được bên trong, dù với quyền user hạn chế như www-data, chúng sẽ không ngồi yên. Mục tiêu của chúng là leo thang đặc quyền (privilege escalation) để chiếm quyền root. Đây mới là lúc cuộc chiến thực sự bắt đầu.

Vậy làm sao để ngăn một tiến trình bị chiếm quyền “làm bậy”? Đây là lúc các cơ chế Mandatory Access Control (MAC) phát huy tác dụng.

DAC và MAC: Hai cách tiếp cận để giới hạn tiến trình

Trên Linux, có hai triết lý chính để kiểm soát quyền truy cập của một chương trình:

  1. Discretionary Access Control (DAC): Đây là cơ chế phân quyền rwx (read, write, execute) quen thuộc cho user, group, và others. Vấn đề của nó là “tùy quyền”. Nếu một chương trình chạy với quyền của user app_user, nó sẽ kế thừa toàn bộ quyền mà app_user sở hữu. Khi chương trình bị hack, kẻ tấn công cũng có ngần ấy quyền.
  2. Mandatory Access Control (MAC): Đây là cơ chế “bắt buộc”. Kernel sẽ thực thi một bộ chính sách (policy) bảo mật định sẵn để quyết định một tiến trình được phép làm gì. Quan trọng là, kể cả khi tiến trình chạy với quyền root, nó vẫn bị policy này giới hạn.

Hai “ông lớn” trong thế giới MAC: AppArmor và SELinux

Khi nói đến MAC trên Linux, hai cái tên nổi bật nhất là SELinux và AppArmor.

  • SELinux (Security-Enhanced Linux): Do NSA phát triển, cực kỳ mạnh mẽ, chi tiết và… phức tạp. Nó “dán nhãn” (labeling) cho mọi đối tượng trên hệ thống (file, process, port) và định nghĩa luật tương tác giữa các nhãn. SELinux là tiêu chuẩn trên các distro họ Red Hat (CentOS, Fedora, RHEL).
  • AppArmor (Application Armor): Dễ tiếp cận hơn, hoạt động dựa trên đường dẫn file (path-based). Thay vì dán nhãn, bạn định nghĩa một “profile” cho mỗi ứng dụng, liệt kê các đường dẫn mà nó được hoặc không được truy cập. AppArmor là lựa chọn mặc định trên các distro họ Debian (Ubuntu, Debian).

Chọn AppArmor hay SELinux? Cái nào “dễ thở” hơn?

Đây là câu hỏi kinh điển. Nếu hỏi một chuyên gia bảo mật, họ có thể sẽ nói SELinux ưu việt hơn vì khả năng kiểm soát cực kỳ chi tiết. Nhưng với anh em DevOps hay SysAdmin phải quản lý hàng chục server, yếu tố “dễ quản lý” và “dễ debug” lại được đặt lên hàng đầu.

Vì sao AppArmor lại được ưa chuộng?

  • Dễ học, dễ viết policy: Cú pháp profile của AppArmor rất trực quan. Bạn chỉ cần liệt kê đường dẫn và các quyền như r, w, x.
  • Tích hợp sẵn trên Ubuntu: Bạn không cần cài đặt gì thêm. Hầu hết dịch vụ cốt lõi đã có sẵn profile.
  • Công cụ hỗ trợ tận răng: Các tiện ích như aa-genprofaa-logprof giúp việc tạo profile mới đơn giản hơn rất nhiều.
  • Dễ chẩn đoán lỗi: Vì profile dựa trên đường dẫn, bạn dễ dàng phán đoán tại sao một ứng dụng bị chặn truy cập.

Nhược điểm của AppArmor?

  • Ít chi tiết bằng SELinux. Ví dụ, nó không thể phân quyền dựa trên ngữ cảnh hay nhãn bảo mật động của file.

Thực tế, meme “Làm sao sửa lỗi SELinux? -> setenforce 0” (tức là tắt béng nó đi) tồn tại là có lý do. SELinux nổi tiếng là khó debug và dễ gây ra lỗi không lường trước. Ngược lại, AppArmor đạt được sự cân bằng tuyệt vời giữa an toàn và tính khả dụng. Nó đủ mạnh để chặn phần lớn các cuộc tấn công leo thang đặc quyền phổ biến. Quan trọng hơn, nó không khiến bạn phải vò đầu bứt tai mỗi khi triển khai ứng dụng mới.

Hướng dẫn cấu hình AppArmor trên Ubuntu từng bước

Lý thuyết đủ rồi, giờ vào thực hành. Mình sẽ hướng dẫn cách tạo một profile AppArmor từ đầu. Để minh họa, hãy cùng tạo profile cho Nginx (dù trên thực tế Nginx đã có profile sẵn).

Bước 1: Kiểm tra trạng thái AppArmor

Đầu tiên, hãy xem AppArmor đang hoạt động thế nào trên server của bạn.

sudo aa-status

Lệnh này sẽ liệt kê các profile đã được load. Bạn sẽ thấy profile nào đang ở chế độ enforce (thực thi và chặn vi phạm) và profile nào đang ở chế độ complain (chỉ ghi log, không chặn).

Bước 2: Hiểu về chế độ Enforce và Complain

  • Enforce mode: Chế độ hoạt động chính thức. Mọi hành động vi phạm policy sẽ bị chặn đứng và ghi lại trong log hệ thống.
  • Complain mode: Chế độ “học hỏi” và gỡ lỗi. AppArmor sẽ không chặn bất kỳ hành động nào. Thay vào đó, nó chỉ ghi lại tất cả các vi phạm vào log. Chế độ này cực kỳ hữu ích khi bạn xây dựng profile cho một ứng dụng mới.

Để chuyển một profile sang chế độ complain (ví dụ cho Nginx):

sudo aa-complain /usr/sbin/nginx

Và để bật lại chế độ enforce:

sudo aa-enforce /usr/sbin/nginx

Bước 3: Thực hành: Tự động tạo profile với `aa-genprof`

Đây là phần thú vị nhất. AppArmor có thể “học” hành vi của một ứng dụng để tự động tạo ra một profile cơ bản.

1. Đặt ứng dụng ở chế độ Complain: Đảm bảo AppArmor không chặn Nginx trong quá trình chúng ta “dạy” nó.

sudo aa-complain /usr/sbin/nginx

2. Chạy trình tạo profile: Mở một terminal và chạy lệnh sau. Nó sẽ bắt đầu theo dõi các log hệ thống.

sudo aa-genprof /usr/sbin/nginx

3. Tương tác với ứng dụng: Mở một terminal khác. Bây giờ, bạn cần sử dụng Nginx để nó thực hiện các hành động cần thiết. Càng tương tác kỹ, profile tạo ra càng chính xác.

# Khởi động lại service
sudo systemctl restart nginx

# Truy cập trang web
curl http://localhost

# Thử truy cập một trang không tồn tại để tạo log lỗi
curl http://localhost/non-existent-page

4. Quét log và tạo luật: Quay lại terminal đang chạy aa-genprof, nhấn phím S (Scan) để nó quét log và tìm các hành động mà Nginx đã thực hiện.

Công cụ sẽ hỏi bạn về từng hành động một. Ví dụ:

Profile:  /usr/sbin/nginx
Path:     /var/log/nginx/access.log
Mode:     w

  (A)llow / (D)eny / (I)gnore / (N)ew / (G)lob / Glob with (E)xt / (S)kip / (F)inish

Ở đây, nó hỏi bạn có cho phép Nginx ghi (w – write) vào file access.log không. Đây là hành động hợp lệ, nên bạn nhấn A (Allow). Hãy xem xét cẩn thận từng yêu cầu. Nếu không chắc chắn, bạn có thể nhấn I (Ignore) để bỏ qua. Sau khi duyệt qua hết các hành động, nhấn S (Save) để lưu các quy tắc mới và F` (Finish) để kết thúc.</p>

<h3>Bước 4: Đọc và tinh chỉnh profile thủ công</h3>
<p>Profile bạn vừa tạo sẽ được lưu tại <code>/etc/apparmor.d/usr.sbin.nginx
. Hãy mở file này ra xem. Nội dung của nó sẽ tương tự như sau:

#include <tunables/global>

/usr/sbin/nginx flags=(complain) {
  #include <abstractions/base>
  #include <abstractions/nginx>

  capability dac_override,
  capability net_bind_service,
  capability setgid,
  capability setuid,

  network tcp,

  /etc/nginx/nginx.conf r,
  /var/log/nginx/access.log w,
  /var/log/nginx/error.log w,
  /var/www/html/** r,

}

Cú pháp khá dễ đọc:

  • r: cho phép đọc (read).
  • w: cho phép ghi (write).
  • x: cho phép thực thi (execute).
  • *: ký tự đại diện cho một phần của tên file.
  • **: ký tự đại diện cho mọi thứ trong thư mục con.

Bạn hoàn toàn có thể sửa file này bằng tay để thêm/bớt quyền, sau đó chỉ cần load lại profile.

Bước 5: Kích hoạt và theo dõi

Khi đã hài lòng với profile, hãy chuyển nó sang chế độ enforce:

sudo aa-enforce /usr/sbin/nginx

Nếu bạn vừa sửa file profile bằng tay, hãy dùng lệnh sau để reload lại nó:

sudo apparmor_parser -r /etc/apparmor.d/usr.sbin.nginx

Làm sao để biết có hành động nào bị chặn hay không? Hãy theo dõi log hệ thống trong thời gian thực:

sudo journalctl -f | grep 'apparmor="DENIED"'

Nếu thấy một dòng DENIED liên quan đến Nginx, điều đó có nghĩa là profile của bạn còn thiếu quyền. Bạn cần dùng aa-logprof để cập nhật hoặc sửa file profile bằng tay, sau đó reload lại.

Lời kết: Một lớp bảo vệ thường bị bỏ quên

AppArmor là một lớp bảo vệ cực kỳ giá trị nhưng lại thường bị bỏ qua. Nó không phải là thuốc tiên chữa mọi vấn đề bảo mật. Tuy nhiên, nó tạo ra một rào cản vững chắc chống lại các kỹ thuật leo thang đặc quyền phổ biến nhất. Một khi đã quen, việc tạo profile cho các ứng dụng tự code (Python, Node.js, Go) sẽ trở nên cực kỳ nhanh chóng.

Hãy dành ra một buổi chiều để tìm hiểu và “khóa chặt” các dịch vụ quan trọng bằng AppArmor. Bạn sẽ ngủ ngon hơn nhiều đấy. Nó chính là cái chốt chặn lớp thứ hai, vị cứu tinh thầm lặng phòng khi vòng ngoài bị xuyên thủng.

Share: