1 điểm bởi GN⁺ 2024-05-13 | 1 bình luận | Chia sẻ qua WhatsApp
  • 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 iptableslibpam, đồng thời phải chạy bằng root để quản lý iptables và 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 AllowedIP cho 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 sysctl liên quan như net.ipv6.conf.all.forwarding=1
  • 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/tun vào container
  • Cài đặt thủ công cần iptableslibpam
  • Wag phải chạy bằng root để quản lý iptablesthiế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.1npm

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ền
    • registration: 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 động
    • users: 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 MFA
    • webadmin: 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ản
    • version, firewall cũ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.Enabled thành true
  • 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 ListenAddress127.0.0.1 hoặc localhost và dùng SSH forwarding để truy cập

Các mục cấu hình chính

  • NumberProxies chỉ định số reverse proxy đáng tin cậy phía trước client, để Wag phản ánh X-Forward-For và phân tích IP client
  • Socket là 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áy
  • NAT bậ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ủ VPN
  • NATExcludeRanges chỉ định các dải CIDR được loại trừ khỏi NAT khi NAT=true
  • ExposePorts mở các cổng của máy chủ VPN cho client và thêm các quy tắc iptables
  • CheckUpdates mặ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ập api.github.com
  • Acls đị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 UI
  • Webserver bao 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ị
  • Wireguard cấ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ủ DNS
  • Clustering bao 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 /16 là MFA và một /32 cụ thể bên trong là Allow, thì /32 cụ 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 /32 chỉ có deny thì truy cập các cổng khác trên cùng /32 cũ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 any thì 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
  • 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 AllowedIP cho 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 . trong internal/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

 
GN⁺ 2024-05-13
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 client
    Hơ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ư persistentkeepalive vào file cấu hình để lấy một URL và kiểm tra định kỳ. Nếu nhận OK thì bình thường, nếu không có phản hồi thì là sự cố mạng, còn nếu có header Location thì mở trình duyệt đến đó để tái xác thực phiên, đại loại vậy
    Tôi vẫn chưa tìm được client nào như thế

    • URL đăng ký có thể tùy chọn nhận cả tham số 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ẫn
      Trả 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ị treo
      Tuy 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ính năng như vậy sẽ thực sự rất hay, và tôi hy vọng tác giả dự án này sẽ cân nhắc
    • Tôi từng làm một server tương tự. Nó cần chứng chỉ client theo từng thiết bị, dùng mTLS để vào trang đăng nhập, sau đó xác thực người dùng bằng OIDC rồi kích hoạt tunnel; phần khó là client
      Tôi đã viết một Go client cho Mac và dùng lệnh wg từ Brew để xử lý cả việc tạo khóa, nhưng nó khá thô và cần sudo
      Mộ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

    • Nếu là cho mục đích đó thì tôi sẽ dùng Firezone. Nó có tùy chọn buộc người dùng phải đăng nhập lại định kỳ vào nền tảng, và khi kết hợp OIDC với nhà cung cấp định danh bên ngoài thì đây là một giải pháp rất chắc chắn và đơn giản cho quản lý phiên
    • Trong ngữ cảnh wag, tôi không chắc chính xác “session key vĩnh viễn” ở đây có nghĩa là gì
      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
    • Nếu làm một VPN client kiểu GlobalProtect trên WireGuard, có lẽ tôi sẽ dùng một khóa xác thực lâu dài cho từng client để dựng tunnel ban đầu tới VPN controller, thực hiện xác thực bên trong đó rồi nhận một session key riêng. Tunnel đầu tiên sẽ bị ngắt ngay khi hoàn tất xác thực và nhận được session key thực tế
    • Nếu cần một kênh thứ hai để xoay vòng session key định kỳ, kết thúc phiên, đổi địa chỉ IP, cấu hình route mới và tái xác thực, thì chẳng phải đó thực chất là giao thức IKE của IPsec sao? Vậy sao không dùng luôn IPsec?
  • 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ó

    • Có cơ chế phòng thủ trước brute-force mã TOTP. Mỗi lần xác thực có giới hạn số lần người dùng được phép thử, và nếu vượt quá thì tài khoản sẽ bị khóa, quản trị viên phải mở khóa
      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
    • Chắc là ở đây: https://github.com/NHAS/wag/blob/cdbdbec3393fa86bf6c823117c8...
    • Tôi không rõ chi tiết triển khai này, nhưng nhìn chung nếu đã có thông tin đăng nhập đủ để đi tới bước TOTP, tức là username và password, thì người dùng đó về cơ bản đã bị xâm phạm rồi
  • 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

    • Chắc chắn là giống ở chỗ đều dùng WireGuard
      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 định sẽ sớm thêm hỗ trợ IPv6, và cũng đang nghĩ tới cách ánh xạ địa chỉ IPv4 của mọi người sang không gian IPv6 riêng tư để giảm nguy cơ xung đột với mạng cục bộ thực tế của người dùng
      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
    • Tôi muốn biết ưu điểm của ULA ở đây theo bạn là gì