Bảo mật những gì chưa được bảo mật
Tất cả chúng ta đều đã từng gặp trường hợp này: bạn dựng một dashboard Prometheus, một trang Wiki nội bộ, hoặc một script quản trị tùy chỉnh, rồi chợt nhận ra nó hoàn toàn không có tính năng bảo mật tích hợp. Để mặc chúng trên mạng nội bộ là một canh bạc. Còn đưa chúng lên web công khai mà không có mật khẩu thì chẳng khác nào đang “mời gọi” các vụ rò rỉ dữ liệu.
Thay vì chắp vá một hệ thống basic auth lỏng lẻo, bạn nên sử dụng OAuth2 Proxy. Nó đóng vai trò như một người gác cổng chuyên nghiệp, đứng trước dịch vụ của bạn và buộc người dùng phải đăng nhập qua Google, GitHub hoặc OpenID Connect trước khi họ có thể tiếp cận dù chỉ một byte dữ liệu.
Bắt đầu nhanh: Bảo mật ứng dụng trong 5 phút
Cách nhanh nhất để thấy công cụ này hoạt động là sử dụng Docker Compose. Trong ví dụ này, chúng ta sẽ bảo vệ một dịch vụ “Whoami” đơn giản bằng cách sử dụng GitHub làm nhà cung cấp danh tính (identity provider).
1. Tạo GitHub OAuth App
Truy cập vào GitHub Settings > Developer settings > OAuth Apps > New OAuth App. Thiết lập Homepage URL thành http://localhost:4180 và Authorization callback URL thành http://localhost:4180/oauth2/callback. Sau khi tạo xong, hãy lưu lại Client ID và Client Secret của bạn.
2. File Docker Compose
Tiếp theo, hãy tạo file docker-compose.yml. Đối với OAUTH2_PROXY_COOKIE_SECRET, bạn cần một chuỗi chính xác 32 byte. Tôi thường sử dụng trình tạo tại toolcraft.app vì nó chạy hoàn toàn trong trình duyệt. Nếu secret này không đúng 32 ký tự, proxy sẽ không thể khởi động.
version: '3'
services:
oauth2-proxy:
image: quay.io/oauth2-proxy/oauth2-proxy:latest
ports:
- "4180:4180"
environment:
OAUTH2_PROXY_PROVIDER: github
OAUTH2_PROXY_CLIENT_ID: "YOUR_CLIENT_ID"
OAUTH2_PROXY_CLIENT_SECRET: "YOUR_CLIENT_SECRET"
OAUTH2_PROXY_COOKIE_SECRET: "YOUR_32_BYTE_SECRET"
OAUTH2_PROXY_UPSTREAM: "http://webapp:80"
OAUTH2_PROXY_HTTP_ADDRESS: "0.0.0.0:4180"
OAUTH2_PROXY_EMAIL_DOMAINS: "*"
webapp:
image: traefik/whoami
container_name: webapp
Khởi chạy bằng lệnh docker-compose up -d. Bây giờ, hãy truy cập http://localhost:4180. Bạn sẽ bị chặn bởi màn hình đăng nhập GitHub. Chỉ sau khi đăng nhập thành công, trang “Whoami” mới xuất hiện.
Cơ chế hoạt động bên trong
OAuth2 Proxy hoạt động như một reverse proxy. Khi có yêu cầu gửi đến, nó sẽ tìm kiếm một session cookie cụ thể. Nếu cookie đó thiếu hoặc đã hết hạn, proxy sẽ chuyển hướng người dùng đến nhà cung cấp (như Google). Sau khi người dùng đăng nhập, nhà cung cấp sẽ gửi họ quay lại kèm theo một mã ủy quyền (authorization code). Proxy sau đó đổi mã này lấy một token, đặt một cookie bảo mật vào trình duyệt và cuối cùng cho phép lưu lượng truy cập đi qua để đến ứng dụng của bạn.
Các chi tiết cấu hình quan trọng
- Upstreams: Đây là URL nội bộ của ứng dụng. Lưu lượng truy cập chỉ đến được đích này sau khi proxy xác minh danh tính người dùng.
- Email Domains: Đây là lớp phòng thủ chính của bạn. Thay vì sử dụng
*, hãy đặt thànhyourcompany.com. Điều này đảm bảo rằng ngay cả khi ai đó có tài khoản GitHub, họ cũng không thể vào trừ khi có email của công ty. - Cookie Secret: Dùng để ký các session cookie nhằm ngăn chặn việc giả mạo. Nếu khóa này bị lộ, kẻ tấn công có thể giả mạo phiên đăng nhập.
Chuyển sang xác thực Google
Google là tiêu chuẩn cho hầu hết các thiết lập doanh nghiệp. Để sử dụng, hãy tạo thông tin xác thực trong Google Cloud Console mục “OAuth client ID”. Chọn “Web application” và đặt redirect URI thành https://your-domain.com/oauth2/callback. Trong cấu hình của bạn, chỉ cần đổi provider thành google và cập nhật các ID tương ứng.
Thiết lập nâng cao: Tích hợp Nginx
Trong môi trường production, tôi hiếm khi để lộ trực tiếp OAuth2 Proxy. Tốt hơn là sử dụng Nginx làm điểm truy cập chính và để nó giao tiếp với proxy thông qua module auth_request. Cách này cho phép một instance OAuth2 Proxy duy nhất bảo vệ hàng chục subdomain khác nhau.
Dưới đây là cách bạn yêu cầu Nginx kiểm tra proxy trước khi cấp quyền truy cập:
server {
listen 80;
server_name private-app.example.com;
location /oauth2/ {
proxy_pass http://127.0.0.1:4180;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Auth-Request-Redirect $request_uri;
}
location / {
auth_request /oauth2/auth;
error_page 401 = /oauth2/sign_in;
# Chuyển thông tin người dùng đã xác thực đến ứng dụng của bạn
auth_request_set $user $upstream_http_x_auth_request_user;
auth_request_set $email $upstream_http_x_auth_request_email;
proxy_set_header X-User $user;
proxy_set_header X-Email $email;
proxy_pass http://internal-service:8080;
}
}
Cách tiếp cận này cực kỳ gọn gàng. Dịch vụ nội bộ của bạn không cần biết bất cứ điều gì về OAuth hay token. Nó chỉ đơn giản là đọc header X-User, thứ mà Nginx chỉ cung cấp sau khi proxy đã thực hiện xong các bước xác thực nặng nề.
Kinh nghiệm triển khai thực tế
Việc chuyển từ thử nghiệm cục bộ sang môi trường thực tế thường nảy sinh một vài trở ngại. Dưới đây là những gì tôi đã rút ra được từ việc quản lý các lần triển khai này.
1. Giải quyết vấn đề “Cookie quá lớn”
OAuth2 Proxy lưu trữ dữ liệu phiên (session) trong cookie theo mặc định. Nếu người dùng của bạn thuộc nhiều nhóm, kích thước token có thể dễ dàng vượt quá giới hạn 4KB của trình duyệt, gây ra lỗi 400 Bad Request ngẫu nhiên. Để khắc phục, hãy chuyển sang sử dụng Redis để lưu trữ session. Khi đó, cookie sẽ chỉ còn là một session ID nhỏ, trong khi dữ liệu nặng vẫn nằm trên máy chủ của bạn.
2. Kiểm soát truy cập chi tiết
Việc giới hạn theo domain thường quá rộng. Nếu bạn dùng GitHub, hãy sử dụng flag --github-org="your-org" để giới hạn quyền truy cập cho các thành viên trong một tổ chức cụ thể. Đối với người dùng Google Workspace, flag --google-admin-group cho phép bạn giới hạn ứng dụng cho các phòng ban cụ thể, ví dụ như [email protected].
3. Bẫy “Vòng lặp đăng nhập”
Luôn đặt --cookie-secure=true trong môi trường production. Điều này bắt buộc cookie chỉ được truyền qua HTTPS. Tuy nhiên, nếu bạn đang thử nghiệm trên HTTP/localhost, cài đặt này sẽ gây ra vòng lặp đăng nhập vì trình duyệt sẽ âm thầm từ chối cookie không an toàn. Hãy tắt nó khi dev local, nhưng đừng bao giờ tắt ở production.
4. Gỡ lỗi sai lệch URL
Nếu bạn gặp lỗi “Redirect URI Mismatch”, hãy kiểm tra kỹ các dấu gạch chéo ở cuối URL. Các nhà cung cấp OAuth cực kỳ khắt khe. http://app.com/oauth2 và http://app.com/oauth2/ là hai URL khác nhau đối với họ. Khi nghi ngờ, hãy kiểm tra log của container; chúng thường chỉ ra chính xác URL mà nhà cung cấp đang mong đợi.
Bằng cách triển khai OAuth2 Proxy, bạn đã thêm một lớp bảo mật mạnh mẽ cho các công cụ vốn không được thiết kế cho việc đó. Đây là một giải pháp có khả năng mở rộng tốt hơn nhiều so với việc quản lý người dùng cục bộ hoặc mật khẩu cứng cho từng công cụ nội bộ mà bạn triển khai.

