1. Khi máy chủ chao đảo nhưng Grafana vẫn báo màu xanh
2 giờ sáng một ngày giữa tuần, cụm 3 node Nginx và API backend của team mình đột ngột tê liệt. Mình mở Grafana kiểm tra ngay: CPU dưới 35%, RAM trống hơn 60%, Disk I/O phẳng lặng. Prometheus im re, không một dòng alert quá tải phần cứng.
Thế nhưng khách hàng liên tục réo vì lỗi 504 Gateway Timeout. SSH gấp vào máy chủ kiểm tra log Nginx, mình mới tá hỏa: hơn 9.000 request/phút đang dồn dập đổ về. Hệ thống đang hứng đợt quét lỗ hổng WordPress và SQL injection từ hơn 400 IP phân tán. Cùng lúc đó, cổng SSH cũng nghẽn cứng vì bị brute-force.
Fail2ban trên server lúc đó hoàn toàn quá tải. Regex cào file log nặng hàng gigabyte khiến tiến trình Python giật cục. Tệ hơn, nó không có cách nào chia sẻ danh sách IP độc hại sang 2 node còn lại.
Đau đầu nhất là team vận hành hoàn toàn ‘mù’ trước các đợt tấn công tầng ứng dụng. Chúng mình thiếu hẳn số liệu thời gian thực: Đang có bao nhiêu IP xấu? Loại tấn công nào chiếm đa số? Tốc độ chặn ra sao?
2. Khoảng trống giữa System Monitoring và Security Tools
Mổ xẻ lại sự cố, mình thấy rõ 3 điểm gãy trong kiến trúc giám sát cũ:
- Node Exporter chỉ nhìn thấy phần cứng: Prometheus biết CPU đang chạy bao nhiêu phần trăm. Nhưng nó chịu chết trước 15.000 request 403 mỗi phút hay 50 lần đăng nhập SSH thất bại liên tiếp.
- Fail2ban thiếu cơ chế xuất metrics: Công cụ này lưu trạng thái trong log phẳng hoặc SQLite cục bộ. Muốn kéo dữ liệu sang Prometheus để vẽ biểu đồ, bạn buộc phải viết thêm script trung gian rất cồng kềnh.
- Bảo vệ đơn độc, thiếu thông tin tình báo: Fail2ban chỉ hành động khi kẻ xấu đã gõ cửa server nhiều lần. Nếu một IP vừa càn quét hàng nghìn server khác trên Internet, máy chủ của bạn vẫn ngây thơ mở cửa đón tiếp.
3. Ba hướng tiếp cận và bài toán đánh đổi
Để kéo dữ liệu an ninh mạng về chung một dashboard, mình đã cân nhắc ba phương án:
Phương án 1: Viết script parse log đẩy sang Prometheus Textfile Collector
Mình từng cho một script Python chạy cronjob 1 phút/lần. Nhiệm vụ của nó là đếm số dòng ‘Failed password’ rồi nhả ra file .prom. Cách này làm nhanh nhưng file log phình to vài GB là ngốn sạch CPU. Chưa kể, dữ liệu rất dễ thất lạc mỗi khi logrotate kích hoạt.
Phương án 2: Đẩy toàn bộ log về cụm Elasticsearch / Graylog
Gom log về SIEM tập trung rất tiện cho việc điều tra sau sự cố (forensics). Tuy nhiên, cụm ELK ngốn tối thiểu 8GB đến 16GB RAM. Với các dàn server cỡ vừa và nhỏ, chi phí này quá xa xỉ. Ngoài ra, việc query log để bắn alert luôn có độ trễ lớn hơn việc Prometheus pull metric định kỳ.
Phương án 3: Thay thế Fail2ban bằng CrowdSec, mở Prometheus metrics
CrowdSec cũng phân tích log để bắt hành vi xấu nhưng được viết bằng Go. Nó cực nhẹ, chỉ chiếm khoảng 60MB – 80MB RAM trên production. Quan trọng nhất, CrowdSec tích hợp sẵn endpoint Prometheus ở cổng 6060. Prometheus có thể kéo trực tiếp số lượng IP bị cấm, kịch bản tấn công và tốc độ phân tích log mà không cần cài thêm bất kỳ exporter nào.
4. Triển khai CrowdSec kết hợp Prometheus và Grafana
Dưới đây là 5 bước cấu hình chi tiết team mình đang chạy ổn định trên Ubuntu 22.04 LTS suốt 6 tháng qua.
Bước 1: Cài đặt CrowdSec và Remediation Component (Bouncer)
Cài đặt CrowdSec engine và bouncer iptables để tự động drop gói tin từ IP xấu:
curl -s https://packagecloud.io/install/repositories/crowdsec/crowdsec/script.deb.sh | sudo bash
sudo apt-get update
sudo apt-get install crowdsec
sudo apt-get install crowdsec-firewall-bouncer-iptables
CrowdSec sẽ tự quét các service đang chạy (Nginx, SSH) và nạp sẵn các parser tương ứng.
Bước 2: Mở Prometheus Metrics Endpoint trên CrowdSec
Mặc định CrowdSec đã bật sẵn Prometheus endpoint nhưng giới hạn trong 127.0.0.1:6060. Mở file cấu hình:
sudo nano /etc/crowdsec/config.yaml
Kiểm tra block prometheus. Giữ nguyên 127.0.0.1 nếu Prometheus nằm chung server, hoặc đổi sang IP mạng nội bộ (private IP):
prometheus:
enabled: true
listen_addr: 127.0.0.1
listen_port: 6060
Khởi động lại CrowdSec để nhận cấu hình:
sudo systemctl restart crowdsec
Kiểm tra endpoint trả về dữ liệu hay chưa:
curl -s http://127.0.0.1:6060/metrics | grep cs_
Màn hình sẽ hiển thị các metric có tiền tố cs_ như cs_alerts, cs_active_decisions và cs_reader_hits_total.
Bước 3: Thêm Scrape Job vào Prometheus
Mở file prometheus.yml trên Prometheus server và thêm job thu thập số liệu:
scrape_configs:
- job_name: 'crowdsec'
scrape_interval: 15s
static_configs:
- targets: ['10.0.1.15:6060']
labels:
instance: 'web-prod-01'
Tải lại cấu hình Prometheus không cần restart service:
curl -X POST http://localhost:9090/-/reload
Bước 4: Dựng Dashboard trực quan trên Grafana
CrowdSec có sẵn dashboard chính thức rất trực quan. Bạn vào Grafana > Dashboards > Import, nhập ID 13380 hoặc 14115, sau đó chọn nguồn dữ liệu Prometheus vừa cấu hình.
Các biểu đồ quan trọng cần chú ý:
- Active Decisions: Số lượng IP đang bị khóa theo thời gian thực.
- Alerts by Scenarios: Phân loại tấn công (ssh-bf, http-probing, crawl-non-statics).
- Parser Performance: Tốc độ đọc và bóc tách log mỗi giây.
Bước 5: Thiết lập Alert rules và xử lý triệt để Alert Fatigue
Tạo file rule cảnh báo crowdsec_alerts.yml cho Prometheus:
groups:
- name: CrowdSecSecurityAlerts
rules:
- alert: SuddenAttackSpike
expr: sum(increase(cs_alerts[5m])) by (instance) > 20
for: 2m
labels:
severity: warning
annotations:
summary: "Server {{ $labels.instance }} bị tấn công dồn dập"
description: "Ghi nhận hơn 20 cảnh báo vi phạm mới trong 5 phút qua."
Những ngày đầu vận hành, mình từng cài hễ có 1 IP bị chặn là bot Telegram lại réo. Kết quả: điện thoại rung bần bật cả ngày vì bot scan dạo liên tục. Cả team bị ‘chai sạn thông báo’ (alert fatigue) và suýt tắt thông báo luôn kênh đó.
Kinh nghiệm xương máu là hãy alert theo tốc độ tăng đột biến thay vì bắt lẻ từng sự kiện. Đặt mức Warning khi có trên 20 IP bị chặn trong 5 phút. Chỉ kích hoạt mức Critical khi cuộc tấn công đi kèm dấu hiệu quá tải CPU hoặc tỷ lệ HTTP 5xx tăng vọt.

