Show HN: Hệ thống đăng ký và xác thực đa yếu tố Wag cho WireGuard
(github.com/NHAS)- Wag là một dự án bổ sung xác thực đa yếu tố, giới hạn tuyến và đăng ký thiết bị cho WireGuard, cho phép phân biệt giữa các tuyến yêu cầu MFA và các tuyến công khai luôn có thể truy cập
- Cung cấp API đăng ký client mới, khả dụng cao, cập nhật người dùng và thông báo theo thời gian thực, cùng nhiều tích hợp MFA như Security Key, SSO, PAM và TOTP
- Việc vận hành máy chủ yêu cầu bật IP forwarding; khi chạy thủ công cần cài
iptablesvàlibpam, đồng thời phải chạy bằng root để quản lýiptablesvà thiết bị WireGuard - Có thể quản trị bằng web UI và CLI; CLI có các lệnh con
start,registration,devices,users,webadminđể xử lý token đăng ký, khóa thiết bị, đặt lại MFA và tài khoản quản trị web - Hạn chế gồm chỉ hỗ trợ một
AllowedIPcho mỗi client, chủ yếu dành cho Linux, còn Windows có thể hoạt động nếu thực hiện thêm một số bước
Các tính năng Wag bổ sung cho WireGuard
- Wag bổ sung MFA, giới hạn tuyến và đăng ký thiết bị cho WireGuard
- Có thể định nghĩa các tuyến thành những đường đi yêu cầu xác thực MFA và tuyến công khai luôn có thể truy cập
- Cung cấp API dễ dùng để đăng ký client mới
- Hỗ trợ khả dụng cao, cập nhật người dùng và thông báo theo thời gian thực
- Tích hợp MFA bao gồm các phương thức sau
- Security Key
- SSO
- PAM
- TOTP
- Tài liệu được cung cấp tại Documentation
Điều kiện cài đặt và chạy
- Cần bật forwarding trên máy chủ
- Với IPv4, dùng thiết lập
net.ipv4.ip_forward=1 - Với IPv6, dùng các thiết lập
sysctlliên quan nhưnet.ipv6.conf.all.forwarding=1
- Với IPv4, dùng thiết lập
- Ví dụ chạy bằng Docker Compose sử dụng image
wagvpn/wag:latest- Ví dụ cổng trang quản trị là
4433/tcp - Ví dụ cổng trang đăng ký công khai là
8081/tcp - Ví dụ cổng WireGuard là
53230/udp - Gắn thiết bị
/dev/net/tunvào container
- Ví dụ cổng trang quản trị là
- Cài đặt thủ công cần
iptablesvàlibpam - Wag phải chạy bằng root để quản lý
iptablesvà thiết bị WireGuard - Bản phát hành nhị phân yêu cầu
glibc 2.31+ - Biên dịch từ mã nguồn cần
go1.23.1vànpm
Cách quản trị
- Sau khi bật UI quản trị và cấu hình Wag, hệ thống sẽ tạo quản trị viên đầu tiên và in mật khẩu ra STDOUT
- Sau đó có thể đăng nhập vào web UI để quản lý người dùng
- Người dùng root có thể quản lý máy chủ Wag bằng CLI
- Cú pháp CLI là
wag subcommand [-options] - Các lệnh con được hỗ trợ gồm
start: khởi động máy chủ Wag và không chạy nềnregistration: xử lý tạo, xóa và liệt kê token đăng kýdevices: xử lý liệt kê, xóa, khóa, mở khóa thiết bị WireGuard và xem các phiên MFA đang hoạt độngusers: xử lý quản lý MFA của người dùng, xóa người dùng, khóa tài khoản và đặt lại MFAwebadmin: xử lý thêm, xóa, liệt kê người dùng quản trị web UI, khóa và mở khóa tài khoảnversion,firewallcũng nằm trong các lệnh được hỗ trợ
Token đăng ký và luồng MFA
- Để đăng ký thiết bị mới, trước tiên tạo token đăng ký bằng lệnh như
wag registration -add -username tester - Khi gửi token đã tạo tới endpoint đăng ký công khai, có thể nhận phản hồi cấu hình WireGuard
- Cấu hình được trả về bao gồm các mục như
Interface,PrivateKey,Address,Peer,Endpoint,PublicKey,AllowedIPs,PersistentKeepAlive - Người dùng kết nối tới địa chỉ VPN của máy chủ và nhập mã 2FA
- Thời gian phiên tồn tại trước khi hết hạn được chỉ định trong tệp cấu hình
Bảng điều khiển quản trị web
- Để đăng nhập vào bảng điều khiển quản trị, cần đặt
Webserver.Management.Enabledthànhtrue - Trong bảng điều khiển, thêm tài khoản quản trị web bằng
sudo ./wag webadmin -add -username <your_username> -password <your-password-here> - Sau đó truy cập địa chỉ lắng nghe quản trị và nhập thông tin xác thực
- Bản thân giao diện web không thể thêm người dùng quản trị
- Khuyến nghị không để lộ cổng quản trị ra bên ngoài; nên đặt
ListenAddresslà127.0.0.1hoặclocalhostvà dùng SSH forwarding để truy cập
Các mục cấu hình chính
NumberProxieschỉ định số reverse proxy đáng tin cậy phía trước client, để Wag phản ánhX-Forward-Forvà phân tích IP clientSocketlà socket điều khiển của Wag; nếu thay đổi, có thể chạy nhiều instance Wag trên cùng một máyNATbật hoặc tắt masquerading; khi bật, mọi lưu lượng sẽ trông như bắt nguồn từ máy chủ VPNNATExcludeRangeschỉ định các dải CIDR được loại trừ khỏi NAT khiNAT=trueExposePortsmở các cổng của máy chủ VPN cho client và thêm các quy tắciptablesCheckUpdatesmặc định tắt; nếu bật, UI quản trị sẽ hiển thị thông báo phiên bản Wag mới và truy cậpapi.github.comAclsđịnh nghĩa nhóm và chính sách nhưng chỉ được áp dụng ở lần chạy đầu tiên; trong thời gian chạy thì chỉnh sửa qua web UIWebserverbao gồm cấu hình endpoint đăng ký công khai, cổng MFA cho đường hầm và cổng quản trịWireguardcấu hình tên thiết bị, cổng lắng nghe, khóa riêng, subnet do VPN phụ trách, MTU và máy chủ DNSClusteringbao gồm các thiết lập về tên cụm, trạng thái cụm etcd, mức log, witness node, vị trí cơ sở dữ liệu và chứng chỉ cụm
Cách hoạt động của chính sách ACL
Policiesđịnh nghĩa các tuyến mà VPN sẽ bắt và các cổng, giao thức sẽ đi qua Wag- Việc áp dụng quy tắc sử dụng độ dài prefix của subnet, và kết quả khớp cụ thể nhất sẽ quyết định mức truy cập tuyến
- Ví dụ, nếu định nghĩa
/16là MFA và một/32cụ thể bên trong là Allow, thì/32cụ thể hơn sẽ được ưu tiên và có thể truy cập mà không cần MFA - Hành vi này đã thay đổi trong
v6.0.0; trước đây các tuyến MFA luôn được ưu tiên - Nếu nhiều chính sách được định nghĩa cho cùng một tuyến, chúng sẽ được hợp thành, trong đó quy tắc MFA được ưu tiên
- Từ các phiên bản chưa phát hành, có thể chặn truy cập tuyến bằng quy tắc
Deny - Quy tắc cụ thể nhất tạo ra một “bucket” quy tắc mới, vì vậy nếu bucket
/32chỉ có deny thì truy cập các cổng khác trên cùng/32cũng có thể không được phép
Quy tắc cổng và giao thức
- Có thể định nghĩa truy cập dịch vụ bằng các quy tắc cổng và giao thức
- Có 3 kiểu quy tắc được hỗ trợ
- Any: nếu không có quy tắc riêng hoặc dùng từ khóa
anythì cho phép mọi tổ hợp dịch vụ và cổng - Single Service: cho phép các cổng TCP·UDP cụ thể của host như
192.168.1.1 22/tcp 53/udp - Ranges: chỉ định dải cổng như
192.168.1.1 22-1024/tcp 23-53/any
- Any: nếu không có quy tắc riêng hoặc dùng từ khóa
- Với dải cổng, phải ghi cổng thấp trước
- ICMP không có cổng, nên có thể chỉ định không kèm cổng như
1.1.1.1 icmp
Hạn chế và phát triển
- Wag chỉ hỗ trợ một
AllowedIPcho mỗi client - Hạn chế này phù hợp với cấu trúc từ client đến máy chủ
- Chủ yếu chỉ dành cho Linux, còn Windows có thể hoạt động nếu thực hiện thêm một số bước
- Trong chế độ phát triển, có thể dùng biến môi trường để đặt IP của các yêu cầu đi vào đường hầm thành IP client
- Ví dụ kiểm thử chạy
sudo go test -v .tronginternal/router - Đóng góp từ bên ngoài được hướng dẫn là nên viết test khi có thể khi thêm tính năng hoặc sửa lỗi, rồi mở Pull Request
1 bình luận
Bình luận trên Hacker News
Trông có vẻ ổn, nhưng có vài điểm khiến tôi băn khoăn
Nhìn vào ví dụ
curl [http://public.server.address:8080/register_device?key=e83253...](<http://public.server.address/register_device/…;)và mô tả rằng “dịch vụ trả về phản hồi được template hóa hoàn toàn”, có vẻ như trong quy trình đăng ký, thay vì client tạo private key rồi gửi public key lên server, thì server lại tạo private key và gửi về cho clientHơn nữa ví dụ lại dùng HTTP, nên ít nhất phần đó cũng nên được đổi đi để mọi người không nghĩ HTTP cũng là một lựa chọn chấp nhận được
Tôi cũng thắc mắc liệu khi phiên hết hạn thì client có cách nào nhận biết không. Hay là các thứ như phiên SSH sẽ просто bị treo?
Thỉnh thoảng tôi có tìm một WireGuard client hoạt động kiểu phát hiện captive portal của Wi‑Fi; lý tưởng nhất là chỉ cần thêm một dòng như
persistentkeepalivevào file cấu hình để lấy một URL và kiểm tra định kỳ. Nếu nhậnOKthì bình thường, nếu không có phản hồi thì là sự cố mạng, còn nếu có headerLocationthì mở trình duyệt đến đó để tái xác thực phiên, đại loại vậyTôi vẫn chưa tìm được client nào như thế
pubkey, nên không nhất thiết phải phụ thuộc vào cách server tạo private key. Tài liệu còn thiếu nên dễ gây nhầm lẫnTrả lời câu hỏi cuối, eBPF XDP mà tôi dùng chỉ có thể làm
PASS,DROP,REDIRECT. Vì thế tôi xử lý bằng kết quả đơn giản nhất làPASS/DROP, và kết nối sẽ просто bị treoTuy vậy, nếu thêm trang phát hiện captive portal vào danh sách MFA của wag thì vẫn có thể tự cấu hình việc phát hiện, sau đó phần còn lại sẽ do trình duyệt xử lý
Tôi không định triển khai trong wag các tính năng hoạt động kiểu chặn bắt hay proxy. Làm vậy có thể sẽ giúp xử lý hết hạn xác thực hoặc logout dễ hơn, nhưng đó không phải hướng đi tôi muốn
Tôi đã viết một Go client cho Mac và dùng lệnh
wgtừ Brew để xử lý cả việc tạo khóa, nhưng nó khá thô và cầnsudoMột ứng dụng native đúng nghĩa dùng quyền mạng thì sẽ tốt hơn, nhưng điều đó vượt quá khả năng của tôi
Tôi muốn biết liệu vấn đề quản lý phiên đã được xử lý hay có kế hoạch xử lý chưa
Về bản chất, WireGuard key giống như session key tồn tại vĩnh viễn
Nếu phần mềm triển khai lớp truyền tải WireGuard là một giải pháp VPN server đúng nghĩa, thì theo tôi nó cũng phải triển khai quản lý phiên. Tức là phải có kênh thứ hai với server để định kỳ xoay vòng session key, kết thúc phiên, đổi địa chỉ IP, thiết lập route mới và nếu cần thì xác thực lại
WireGuard key cho phép giao tiếp với wag server, nhưng phiên thực tế được duy trì bằng bản đồ eBPF chứa trạng thái người dùng đã được xác thực hay chưa
Vì vậy, ngay cả khi ai đó đánh cắp dữ liệu private key thì họ vẫn không thể truy cập các route bị giới hạn bằng MFA
Tôi tò mò không biết có đang chặn brute-force mã TOTP hay không. Ví dụ như giới hạn tốc độ hay giới hạn số lần thử
Tôi lướt nhanh qua code nhưng không thấy phần xử lý như vậy
Kịch bản tôi hình dung là ai đó mở UI nhập TOTP trên trình duyệt, bật devtools rồi lặp thử tất cả các mã TOTP có thể có
Một phần chủ ý ở đây cũng là để người dùng tự nghĩ xem vì sao thiết bị lại đang cố ép xác thực như vậy. Vì tình huống đó có thể là dấu hiệu endpoint đã bị xâm phạm
Nghe rất giống Headscale hay Tailscale. Thật tốt khi thấy có thêm lựa chọn để quản lý mạng WireGuard
Tôi muốn biết có tài liệu so sánh nào để hiểu các tính năng chồng lấp đến đâu, có gì được thêm vào, có gì khác biệt, và những gì sẽ không được triển khai về sau không
Tôi chưa đưa so sánh trực tiếp vào tài liệu, nhưng hiện tại đó không phải hướng tôi đang muốn đi. Dự án này phù hợp với nhu cầu của tôi và cũng khá thú vị
Wag phù hợp với cấu trúc hub-and-spoke nơi bạn muốn có ranh giới chặt chẽ, hơn là mesh kiểu Tailscale nơi mọi thứ chạm được vào nhau và các rule định nghĩa lớp overlay
Cả wag và Tailscale đều thêm tích hợp SSO và gần như là 2FA để bảo vệ người dùng
Cả hai đều có phương thức đăng ký và web UI để quản trị, nhưng tôi là một lập trình viên solo không thích web development nên Tailscale chắc chắn được hoàn thiện hơn nhiều
Điều tôi chắc chắn sẽ không triển khai là phần chặn bắt hay TLS proxy để redirect người dùng sau khi logout phiên. Lý do chính là hiện tại làm điều đó bằng eBPF vẫn hơi quá sức với tôi, và để nó hoạt động có lẽ tôi sẽ phải dùng các thành phần DNAT/SNAT mà tôi không muốn viết
Chỉ hỗ trợ IPv4 à, nếu đã chọn WireGuard thì tôi nghĩ nhiều nơi có lẽ sẽ có cấu hình hiện đại hơn và dùng khá nhiều ULA kiểu self-service
Tôi tò mò không biết khi nhắc tới ULA thì có điểm gì cụ thể mà bạn đang nghĩ đến không