Sáng thứ Hai thót tim: Nginx sập và dấu vết biến mất
9h sáng đầu tuần, hệ thống bất ngờ ném lỗi 502 Bad Gateway liên tục. Khách hàng bắt đầu nhắn tin phàn nàn. Mở file /etc/nginx/nginx.conf ra check, mình thấy ai đó đã sửa upstream lúc 23:15 đêm hôm trước khiến Nginx fail syntax khi reload. Tra cứu /var/log/auth.log, server ghi nhận có đúng 3 ông DevOps cùng SSH vào tầm giờ đó.
Đến lúc check ~/.bash_history của từng người, mọi chuyện mới thực sự đi vào ngõ cụt. Lịch sử trống trơn. Người thì dùng session tmux rồi rớt mạng thoát ngang, người thì chung tài khoản deploy, hoặc lệnh sửa file được chạy ngầm qua một bash script. Không ai nhận trách nhiệm. Ai đã mở file? Tiến trình nào ghi đè dữ liệu? UID thực sự đằng sau là ai? Mọi dấu vết đều bốc hơi hoàn toàn.
Vì sao log mặc định của Ubuntu dễ dàng bị qua mặt?
Nhiều anh em sysadmin hay tin tưởng vào syslog, journalctl hay bash history để điều tra sự cố. Đáng tiếc, những cơ chế này chỉ hoạt động ở tầng nổi và rất dễ bị vô hiệu hóa:
- Bash history nằm ở User Space: Chỉ cần gõ
set +o history, bấm phím cách trước câu lệnh, hoặc xóa luôn file~/.bash_historylà lịch sử thao tác biến mất không tì vết. - Syslog chỉ thụ động chờ app gửi tin: Nginx hay SSH chỉ báo log khi có sự kiện ứng dụng (như login hay reload). Chúng hoàn toàn mù tịt khi ai đó dùng
vim,nanohay lệnhsedmở đọc trộm private key trong/etc/ssl/private/. - Mất dấu vết khi leo thang quyền lực: Khi ai đó chạy
sudo suđể sang root, danh tính ban đầu rất dễ bị chìm xuồng. Nếu không có cơ chế theo dõi Audit User ID (auid) gắn liền từ phiên login đầu tiên, bạn sẽ không thể biết ai đứng sau user root đó.
Các giải pháp chắp vá và giới hạn thực tế
Trước khi tìm đến Auditd, team mình từng thử qua vài cách quen thuộc nhưng đều gặp rào cản:
1. Khóa file bằng chattr +i
Lệnh chattr +i /etc/nginx/nginx.conf chặn sửa xóa rất hiệu quả, ngay cả root cũng chịu thua. Thế nhưng, cách này chỉ hợp với file tĩnh tuyệt đối. Mỗi lần CI/CD deploy cần update config là pipeline gãy ngay. Chưa kể, lệnh này không cho biết kẻ nào đã cố tình đụng vào file.
2. Giám sát tính toàn vẹn với AIDE hoặc Tripwire
Các công cụ này quét hash định kỳ qua cronjob (ví dụ 30 phút một lần). Nhược điểm chí mạng là độ trễ. Chúng chỉ báo tin khi file đã bị sửa xong xuôi, hoàn toàn không theo thời gian thực và không thể chỉ ra PID hay UID của kẻ phá hoại.
3. Dùng script theo dõi inotifywait
Script bắt sự kiện file khá nhanh nhưng ngốn CPU và RAM khủng khiếp khi thư mục có nhiều file con. Chỉ cần hệ thống dính đợt ghi đĩa dồn dập, hàng đợi inotify tràn bộ đệm và script crash ngay.
Giải pháp chuẩn chỉ: Bắt trọn sự kiện từ Linux Kernel bằng Auditd
Thay vì chạy theo ở tầng ứng dụng, Linux Audit Daemon (Auditd) bắt sự kiện trực tiếp từ Linux Kernel. Bất kể user có dùng script tinh vi hay cố tình xóa log ở user space, mọi system call như openat, execve hay unlink đều bị kernel ghi lại nguyên vẹn.
Dưới đây là cấu hình mình đã kiểm thử kỹ lưỡng trên cụm Ubuntu 22.04 LTS (chịu tải khoảng 3.500 requests/giây). Cấu hình này vừa đảm bảo bắt trọn hành vi nhạy cảm, vừa giữ mức tiêu thụ CPU của Auditd dưới 1.5%.
Bước 1: Cài đặt Auditd
Ubuntu Server thường không bật sẵn Auditd. Bạn cài đặt các gói cần thiết bằng lệnh sau:
sudo apt update
sudo apt install -y auditd audispd-plugins
sudo systemctl enable --now auditd
sudo systemctl status auditd
Bước 2: Viết Audit Rules theo chuẩn bảo mật
Auditd nạp rule từ thư mục /etc/audit/rules.d/. Đừng bao giờ sửa file tạm /etc/audit/audit.rules vì nó sẽ bị ghi đè sau mỗi lần reboot. Hãy tạo một file rule riêng:
sudo nano /etc/audit/rules.d/custom-security.rules
Dán vào nội dung rule thực chiến sau:
## 1. Xóa sạch rules cũ trong bộ nhớ kernel
-D
## 2. Tăng buffer size lên 8192 (tránh drop log khi I/O tăng vọt)
-b 8192
## Khi buffer bị đầy: 1 = gửi cảnh báo syslog, 2 = kernel panic (dùng 1 cho an toàn)
-f 1
## 3. Bắt hành vi can thiệp tài khoản và phân quyền sudo
-w /etc/passwd -p wa -k identity_changes
-w /etc/shadow -p wa -k identity_changes
-w /etc/group -p wa -k identity_changes
-w /etc/sudoers -p wa -k sudoers_tamper
-w /etc/sudoers.d/ -p wa -k sudoers_tamper
## 4. Giám sát cấu hình Nginx và chứng chỉ SSL
-w /etc/nginx/ -p wa -k nginx_config_changes
-w /etc/ssl/ -p rwa -k ssl_key_access
## 5. Bắt các system call cố tình tua ngược hoặc chỉnh giờ hệ thống
-a always,exit -F arch=b64 -S adjtimex,settimeofday,clock_settime -k time_modification
## 6. Giám sát hành vi can thiệp service và firewall
-w /bin/systemctl -p x -k service_mgmt
-w /sbin/iptables -p x -k iptables_mgmt
-w /sbin/ufw -p x -k firewall_mgmt
## 7. Khóa cứng cấu hình (chống root tắt auditd, chỉ gỡ được khi reboot server)
-e 2
Ý nghĩa các tham số cần nhớ:
-w <đường_dẫn>: Đường dẫn file hoặc thư mục cần theo dõi (Watch).-p rwa: Các hành vi cần tóm:r(read – đọc),w(write – ghi đè),a(attribute – đổi chmod/chown),x(execute – chạy lệnh).-k <tên_key>: Tag định danh giúp bạn lọc nhanh log sau này.-e 2: Chuyển toàn bộ rule sang chế độ bất biến. Kể cả tài khoản root gõ lệnh xóa rule cũng bị kernel từ chối cho tới lần reboot máy tiếp theo.
Lưu file xong, bạn nạp rules vào kernel bằng lệnh:
sudo augenrules --load
sudo auditctl -l
Bước 3: Dùng ausearch truy lùng danh tính thật
Toàn bộ log được đẩy vào /var/log/audit/audit.log. Tuyệt đối không dùng grep hay cat vì log thô chứa toàn chuỗi mã hex rất khó đọc. Công cụ chuẩn nhất là ausearch.
Giờ hãy thử tìm xem ai đã can thiệp vào Nginx theo key nginx_config_changes:
sudo ausearch -k nginx_config_changes -i
Thêm cờ -i (interpret) là bước bắt buộc để công cụ tự dịch UID, syscall number và timestamp Unix sang tên người dùng và ngày giờ dễ đọc. Kết quả xuất hiện rõ ràng:
type=SYSCALL msg=audit(23/10/2026 23:15:30.124:412) : arch=x86_64 syscall=openat success=yes exit=3 a0=0xffffff9c a1=0x55d78a2f4160 a2=O_WRONLY|O_CREAT|O_TRUNC items=2 ppid=1420 pid=2105 auid=hungnv uid=root euid=root comm=nano exe=/bin/nano key="nginx_config_changes"
type=PATH msg=audit(23/10/2026 23:15:30.124:412) : item=0 name="/etc/nginx/nginx.conf" inode=131075 dev=08:01 mode=file,644 ouid=root ogid=root
Hãy nhìn kỹ vào 2 trường dữ liệu quan trọng nhất:
uid=root: Lệnh được thực thi dưới quyền root thông qua trình soạn thảo/bin/nano.auid=hungnv: Đây là Audit UID. Nó ghi lại chính xác userhungnvđã login qua SSH ban đầu rồi mớisudo sulên root.
Thủ phạm lộ diện. Bằng chứng rõ ràng, không thể chối cãi.
Bước 4: Xuất báo cáo nhanh với aureport
Mỗi sáng trước khi bắt đầu công việc, bạn có thể chạy 3 lệnh sau để nắm trọn tình hình an ninh server trong 24 giờ qua:
## Kiểm tra các lượt đăng nhập SSH thất bại (dấu hiệu brute-force)
sudo aureport -l --failed
## Thống kê các file nhạy cảm bị truy cập nhiều nhất
sudo aureport -f -i --summary
## Liệt kê các lệnh thực thi quyền root bất thường
sudo aureport -x --summary
Bước 5: Cấu hình xoay vòng log để tránh tràn ổ cứng
Trên server bận rộn, file audit.log có thể phình to vài GB mỗi ngày. Để tránh kịch bản server sập vì hết ổ đĩa, hãy mở file cấu hình /etc/audit/auditd.conf:
sudo nano /etc/audit/auditd.conf
Điều chỉnh các thông số lưu trữ an toàn:
# Giới hạn mỗi file log tối đa 50MB
max_log_file = 50
# Giữ lại tối đa 10 file cũ (tổng dung lượng cố định ~500MB)
num_logs = 10
# Tự động xoay vòng log khi đầy
max_log_file_action = ROTATE
# Bắn cảnh báo vào syslog khi dung lượng ổ cứng còn dưới 100MB
space_left = 100
space_left_action = SYSLOG
# Tạm dừng ghi log khi ổ cứng còn dưới 50MB (tránh làm tê liệt OS)
admin_space_left = 50
admin_space_left_action = SUSPEND
Lưu file và áp dụng cấu hình mới bằng lệnh:
sudo service auditd restart
Hai lưu ý sống còn khi đưa lên Production
Auditd là công cụ cực mạnh, nhưng dùng sai cách sẽ phản tác dụng:
- Tuyệt đối không bật cờ đọc (
-p r) trên thư mục rác: Đặt cờ đọc vào/var/log,/tmphay thư mục cache ứng dụng sẽ khiến kernel ghi log liên tục hàng nghìn lần mỗi giây. Hậu quả là IOPS ổ cứng tăng vọt và server lag ngay lập tức. - Cân nhắc kỹ trước khi bật
-e 2: Khi rule đã bị khóa cứng, bạn không thể xóa hay sửa bất kỳ dòng nào bằng lệnhauditctl. Mọi thay đổi bắt buộc phải reboot lại cả server. Vì vậy, hãy test thật kỹ trên môi trường Staging ít nhất 2 đến 3 ngày trước khi thêm dòng này vào Production.
