Nguyên lý hoạt động của eBPF và lợi ích bảo mật cho Database
eBPF (Extended Berkeley Packet Filter) là một công nghệ cho phép thực thi các chương trình bytecode an toàn bên trong nhân Linux mà không cần thay đổi kernel source code hoặc tải module kernel tùy chỉnh.
Trong bối cảnh bảo mật Database, eBPF hoạt động như một lớp giám sát không xâm lấn (non-intrusive). Thay vì chèn code vào ứng dụng Database (như PostgreSQL hay MySQL), eBPF hook vào các điểm gọi hệ thống (system calls) hoặc kernel functions để theo dõi hoạt động I/O, mạng, và bộ nhớ.
Lợi ích cốt lõi khi áp dụng eBPF cho Database:
- Giảm Overhead: Bytecode được biên dịch thành machine code của CPU tại runtime, giảm thiểu tác động đến hiệu năng Database so với các công cụ tracing truyền thống.
- Chặn tấn công thời gian thực: Có thể phát hiện và chặn các hành vi bất thường (như truy cập file nhạy cảm, SQL injection qua system call) ngay khi chúng xảy ra trong kernel.
- Bảo mật Kernel: VM của eBPF (Virtual Machine) thực thi trong kernel với các giới hạn chặt chẽ về vòng lặp và bộ nhớ, ngăn chặn code độc hại làm treo hệ thống.
Cài đặt BCC tools và Kernel module hỗ trợ eBPF
Để sử dụng eBPF, kernel Linux cần được biên dịch với các tùy chọn hỗ trợ (CONFIG_BPF, CONFIG_BPF_JIT). Hầu hết các bản phát hành Ubuntu 20.04+, Debian 10+, và RHEL 8+ đều đã hỗ trợ sẵn.
Bước đầu tiên là kiểm tra xem kernel hiện tại có hỗ trợ eBPF hay không.
grep -E "BPF|bpf" /boot/config-$(uname -r)
Kết quả mong đợi: Bạn phải thấy các dòng như CONFIG_BPF=y và CONFIG_BPF_JIT=y. Nếu không thấy, kernel cần được upgrade hoặc rebuild.
Tiếp theo, cài đặt gói BCC (BPF Compiler Collection) chứa các công cụ như bpftrace, libbpf, và các tool giám sát có sẵn.
Trên Ubuntu/Debian:
sudo apt update
sudo apt install bpfcc-tools bpftrace linux-headers-$(uname -r) clang llvm
Trên RHEL/CentOS/Rocky Linux (yêu cầu habnab repo hoặc EPEL):
sudo dnf install bpfcc-tools bpftrace kernel-devel kernel-headers clang llvm
Kết quả mong đợi: Các package được cài đặt thành công, không có lỗi về dependency. Đặc biệt, linux-headers phải khớp chính xác với phiên bản kernel đang chạy.
Verify cài đặt bằng cách chạy một công cụ đơn giản để đảm bảo quyền truy cập vào eBPF map.
bpftrace --version
Kết quả mong đợi: Hiển thị phiên bản bpftrace (ví dụ: bpftrace v0.19.0). Nếu lỗi "Permission denied" hoặc "libbpf not found", kiểm tra lại việc cài đặt headers và quyền sudo.
Sử dụng bpftrace để theo dõi System Calls của Database
Bây giờ chúng ta sẽ áp dụng bpftrace để giám sát hoạt động của Database. Mục tiêu là theo dõi các System Call liên quan đến I/O và Socket, nơi thường xảy ra các hoạt động tấn công hoặc bottleneck.
Giả sử Database đang chạy là PostgreSQL. Trước hết, xác định Process ID (PID) của Database server.
pgrep -f "postgres"
Kết quả mong đợi: Hiển thị danh sách PID (ví dụ: 1234). Lưu lại PID này để dùng trong lệnh bpftrace.
Sử dụng bpftrace để theo dõi số lần gọi system call write (ghi dữ liệu) của PostgreSQL. Đây là chỉ số quan trọng để phát hiện hoạt động ghi dữ liệu bất thường hoặc SQL Injection gây ra lượng write khổng lồ.
Lệnh dưới đây sẽ đếm số lần gọi write cho mỗi PID của PostgreSQL và in ra khi chương trình kết thúc.
sudo bpftrace -e 'tracepoint:syscalls:sys_enter_write /pid == 1234/ { @[comm] = count(); }' --duration=5
Thay 1234 bằng PID thực tế của bạn. Tham số --duration=5 giới hạn thời gian chạy trong 5 giây để an toàn.
Kết quả mong đợi: Sau 5 giây, bpftrace sẽ in ra bảng thống kê tên process (ví dụ: postgres) và số lần gọi write. Nếu không có số nào, có thể PID sai hoặc process không có hoạt động write trong khoảng thời gian đó.
Tiếp theo, chúng ta nâng cao lên việc theo dõi nội dung của các gói tin mạng (Socket) để phát hiện SQL Injection. Chúng ta sẽ theo dõi system call sendto hoặc sendmsg của Database để xem dữ liệu đi ra.
Lệnh này sẽ in ra PID, tên process, và độ dài dữ liệu (len) mỗi khi có cuộc gọi send.
sudo bpftrace -e 'tracepoint:syscalls:sys_enter_sendto /pid == 1234/ { printf("%s %d %d\n", comm, pid, args->len); }' --duration=5
Kết quả mong đợi: Dòng log xuất hiện liên tục với định dạng postgres 1234 256. Nếu bạn thực hiện một truy vấn SQL phức tạp từ client, bạn sẽ thấy số lượng dòng tăng vọt.
Để giám sát toàn bộ các system calls liên quan đến file I/O (rất quan trọng cho Database performance và bảo mật), sử dụng template có sẵn trong BCC.
sudo bpftrace -e 'tracepoint:syscalls:sys_enter_* /pid == 1234/ { printf("%s: %s\n", comm, probe); }' --duration=5
Kết quả mong đợi: Danh sách các system calls mà PostgreSQL thực hiện (ví dụ: sys_enter_openat, sys_enter_read, sys_enter_fsync). Điều này giúp bạn hiểu hành vi I/O của Database để xây dựng chính sách chặn trong các phần sau.
Verify kết quả giám sát
Để xác nhận giám sát đang hoạt động chính xác, thực hiện một thao tác tạo tải giả lập trên Database.
psql -c "COPY (SELECT * FROM generate_series(1,10000)) TO '/tmp/test_dump.csv';"
Đồng thời mở một terminal khác chạy lệnh bpftrace theo dõi write như ở trên. Bạn sẽ thấy số lượng count tăng đột biến khi lệnh COPY được thực thi.
Kết quả mong đợi: Số lượng write tăng cao tương ứng với lượng dữ liệu được ghi ra file. Nếu bpftrace không ghi nhận, kiểm tra lại PID hoặc quyền sudo (cần quyền root để hook vào kernel).
Xử lý sự cố thường gặp
- Lỗi "Permission denied": Đảm bảo chạy lệnh bằng
sudo. Kiểm tra cat /proc/sys/kernel/unprivileged_bpf_disabled. Nếu là 1, cần root để chạy eBPF.
- Lỗi "libbpf: failed to attach program": Có thể do kernel quá cũ hoặc thiếu cấu hình
CONFIG_BPF_SYSCALL. Upgrade kernel lên bản mới nhất.
- Không thấy output: Kiểm tra xem process Database có đang chạy không (
ps aux | grep postgres) và PID có khớp không.
Đ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 3: Cấu hình AppArmor và SELinux để cô lập Database
Phần 5: Xây dựng chính sách eBPF để chặn các cuộc tấn công SQL Injection »