Tiếng chuông báo động lúc 2 giờ sáng
Đúng 2 giờ sáng, điện thoại mình rung bần bật trên bàn làm việc. Alert từ Grafana báo về liên tục: hàng chục nghìn request lạ đang dồn dập dội vào trang quản trị của một dashboard nội bộ. Kiểm tra log, mình thấy một IP từ nước ngoài đang miệt mài brute-force tài khoản admin với tốc độ hơn 50.000 request/giờ.
Dù mật khẩu đặt khá phức tạp, nhưng cảm giác ngồi nhìn kẻ tấn công thử từng chiếc chìa khóa vào cửa nhà mình thật chẳng dễ chịu chút nào. Sau khi trực tiếp audit security cho hơn 10 hệ thống server, mình nhận ra một lỗ hổng chí mạng: sự phân mảnh. Mỗi ứng dụng như Nextcloud, Portainer hay Grafana lại dùng một bộ user/pass riêng. Có cái hỗ trợ 2FA, có cái không. Chỉ cần một mắt xích yếu bị bypass, toàn bộ hạ tầng coi như phơi bày trước hacker.
Rắc rối nằm ở đâu?
Vấn đề không chỉ là mật khẩu của bạn dài bao nhiêu ký tự. Khi bạn tự host (self-hosted) nhiều dịch vụ, việc quản lý quyền truy cập sẽ sớm trở thành một cơn ác mộng:
- Quản lý rời rạc: Mỗi app một kiểu login khiến bạn khó kiểm soát ai đang truy cập cái gì.
- Rủi ro khi nghỉ việc: Nếu một nhân viên rời team, bạn phải vào từng app để xóa tài khoản. Quên một chỗ là để lại một lỗ hổng chết người.
- Lỗ hổng từ app cũ: Nhiều công cụ mã nguồn mở lâu đời không hỗ trợ xác thực 2 lớp. Chúng là mục tiêu béo bở cho các cuộc tấn công dò mật khẩu.
Những phương án thường bị “loại từ vòng gửi xe”
Trước khi chốt phương án dùng Authelia, mình đã cân nhắc vài cách nhưng đều vấp phải những bất tiện riêng:
- Dùng VPN (WireGuard/OpenVPN): Rất an toàn nhưng cực kỳ phiền phức. Mỗi lần cần check nhanh dashboard trên điện thoại lại phải bật VPN và chờ kết nối.
- Nginx Basic Auth: Quá thô sơ. Nó không có giao diện đổi pass, không có 2FA và cực kỳ khó quản lý khi team bắt đầu đông người.
- Cloudflare Access: Khá xịn, nhưng bạn phải phụ thuộc vào cloud của họ. Với dữ liệu nhạy cảm cần lưu trữ on-premise hoàn toàn, đây không phải là lựa chọn ưu tiên.
Authelia – Chốt chặn SSO và 2FA mạnh mẽ
Authelia hoạt động như một “cửa ngõ” xác thực tập trung đứng trước các ứng dụng của bạn. Nó cung cấp Single Sign-On (SSO) và xác thực đa lớp (TOTP, Duo, U2F). Hiểu đơn giản: thay vì để user chạm trực tiếp vào app, Nginx sẽ đẩy họ sang Authelia để kiểm tra vân tay, mật khẩu và mã OTP. Nếu hợp lệ, cửa mới mở.
Bước 1: Chuẩn bị môi trường
Mình mặc định bạn đã cài sẵn Docker. Cấu trúc thư mục mình thường triển khai như sau:
/opt/authelia/
├── docker-compose.yml
└── config/
├── configuration.yml
└── users.yml
Bước 2: Khởi chạy với Docker Compose
File này sẽ chạy Authelia cùng một database Redis để lưu trữ session. Việc dùng Redis giúp trải nghiệm mượt mà hơn, user không phải login lại liên tục khi bạn restart container.
version: '3.8'
services:
authelia:
container_name: authelia
image: authelia/authelia:latest
volumes:
- ./config:/config
networks:
- proxy
environment:
- TZ=Asia/Ho_Chi_Minh
restart: unless-stopped
redis:
container_name: authelia-redis
image: redis:alpine
networks:
- proxy
restart: unless-stopped
networks:
proxy:
external: true
Bước 3: Cấu hình linh hồn hệ thống – configuration.yml
Đây là nơi mọi quy tắc vận hành được thiết lập. Bạn cần tạo các chuỗi secret ngẫu nhiên bằng lệnh openssl rand -hex 64.
server:
host: 0.0.0.0
port: 9091
authentication_backend:
file:
path: /config/users.yml
access_control:
default_policy: deny
rules:
- domain: "*.yourdomain.com"
policy: two_factor
session:
name: authelia_session
domain: yourdomain.com
expiration: 3600
inactivity: 900
redis:
host: authelia-redis
port: 6379
notifier:
filesystem:
filename: /config/notification.txt
Bước 4: Thiết lập người dùng
Trong file users.yml, mật khẩu phải được mã hóa. Bạn có thể dùng tool online hoặc chạy lệnh docker run --rm authelia/authelia:latest authelia hash-password "your_password" để lấy chuỗi hash Argon2id.
users:
admin:
displayname: "Administrator"
password: "$argon2id$v=19$m=65536,t=3,p=4$your_hashed_password"
email: [email protected]
groups:
- admins
Bước 5: Kết nối Reverse Proxy (Nginx)
Nếu dùng Nginx Proxy Manager, bạn hãy dán đoạn code này vào mục Advanced Custom Configuration của ứng dụng cần bảo mật:
auth_request /authelia;
auth_request_set $target_url $scheme://$http_host$request_uri;
auth_request_set $user $upstream_http_remote_user;
proxy_set_header Remote-User $user;
# Chuyển hướng về trang login nếu chưa xác thực
error_page 401 =302 https://auth.yourdomain.com/?rd=$target_url;
Kinh nghiệm thực chiến: Đừng để bị khóa ngoài cửa
Sau nhiều lần “ăn hành” khi triển khai thực tế, mình rút ra 3 điểm xương máu:
- Đồng bộ thời gian: Mã OTP (TOTP) dựa trên thời gian thực. Nếu giờ server và điện thoại lệch nhau quá 30 giây, bạn sẽ bị từ chối truy cập dù nhập đúng mã. Hãy cài
chronyđể đồng bộ giờ liên tục. - HTTPS là bắt buộc: Authelia và các trình duyệt hiện đại sẽ không cho phép chạy 2FA qua kết nối HTTP không bảo mật.
- Cookie Domain: Hãy chắc chắn session domain được đặt là
yourdomain.com(domain gốc). Có như vậy, khi bạn login ởauth.yourdomain.com, các subdomain khác nhưgrafana.yourdomain.commới nhận diện được phiên đăng nhập.
Từ ngày có Authelia, mình ngủ ngon hơn hẳn. Kẻ tấn công có thể mò ra mật khẩu, nhưng chúng không thể lấy được mã OTP trong túi quần mình. Việc quản lý user giờ đây chỉ gói gọn trong một file duy nhất, vừa an toàn, vừa chuyên nghiệp.
