1 points par GN⁺ 2024-05-13 | 1 commentaires | Partager sur WhatsApp
  • Wag est un projet qui ajoute l’authentification multifacteur, la restriction des routes et l’inscription des appareils à WireGuard, avec la possibilité de distinguer les routes nécessitant une MFA et les routes publiques toujours accessibles
  • Il fournit une API d’inscription de nouveaux clients, la haute disponibilité, des mises à jour et notifications utilisateurs en temps réel, ainsi que plusieurs intégrations MFA comme Security Key, SSO, PAM et TOTP
  • L’exploitation du serveur nécessite l’activation de l’IP forwarding et, en exécution manuelle, l’installation de iptables et libpam, ainsi qu’une exécution en root pour gérer iptables et les interfaces WireGuard
  • L’administration peut se faire via une interface web et une CLI ; la CLI propose les sous-commandes start, registration, devices, users, webadmin pour gérer les jetons d’inscription, le verrouillage des appareils, la réinitialisation MFA et les comptes d’administration web
  • Parmi les limites : un seul AllowedIP est pris en charge par client, et le projet vise principalement Linux, Windows pouvant fonctionner avec quelques manipulations

Fonctionnalités WireGuard ajoutées par Wag

  • Wag ajoute à WireGuard la MFA, la restriction des routes et l’inscription des appareils
  • Les routes peuvent être définies en séparant celles qui exigent une authentification MFA et les routes publiques toujours accessibles
  • Il fournit une API simple pour l’inscription de nouveaux clients
  • Il prend en charge la haute disponibilité, les mises à jour utilisateurs en temps réel et les notifications
  • Les intégrations MFA incluent les méthodes suivantes
    • Security Key
    • SSO
    • PAM
    • TOTP
  • La documentation est disponible sur Documentation

Installation et conditions d’exécution

  • Le forwarding doit être activé sur le serveur
    • Pour IPv4, utiliser le réglage net.ipv4.ip_forward=1
    • Pour IPv6, utiliser les réglages sysctl appropriés, comme net.ipv6.conf.all.forwarding=1
  • L’exemple d’exécution avec Docker Compose utilise l’image wagvpn/wag:latest
    • Exemple de port pour la page d’administration : 4433/tcp
    • Exemple de port pour la page publique d’inscription : 8081/tcp
    • Exemple de port WireGuard : 53230/udp
    • Le périphérique /dev/net/tun est connecté au conteneur
  • Une installation manuelle nécessite iptables et libpam
  • Wag doit être exécuté en root pour gérer iptables et les interfaces WireGuard
  • Les binaires publiés nécessitent glibc 2.31+
  • La compilation depuis les sources nécessite go1.23.1 et npm

Modes d’administration

  • Après avoir activé l’interface d’administration et configuré Wag, le premier administrateur est créé et son mot de passe est affiché sur la STDOUT
  • Il est ensuite possible de se connecter à l’interface web pour gérer les utilisateurs
  • L’utilisateur root peut administrer le serveur Wag via la CLI
  • Le format de la CLI est wag subcommand [-options]
  • Les sous-commandes prises en charge sont les suivantes
    • start : démarre le serveur Wag sans le passer en daemon
    • registration : gère la création, la suppression et la consultation des jetons d’inscription
    • devices : gère l’affichage, la suppression, le verrouillage, le déverrouillage des appareils WireGuard et la consultation des sessions MFA actives
    • users : gère la MFA des utilisateurs, la suppression d’utilisateurs, le verrouillage de compte et la réinitialisation MFA
    • webadmin : gère l’ajout, la suppression, la consultation, le verrouillage et le déverrouillage des administrateurs de l’interface web
    • version et firewall font aussi partie des commandes prises en charge

Jetons d’inscription et flux MFA

  • Pour enregistrer un nouvel appareil, on crée d’abord un jeton d’inscription avec une commande comme wag registration -add -username tester
  • En transmettant le jeton créé au point de terminaison public d’inscription, on peut recevoir une réponse de configuration WireGuard
  • La configuration renvoyée inclut des éléments comme Interface, PrivateKey, Address, Peer, Endpoint, PublicKey, AllowedIPs, PersistentKeepAlive
  • L’utilisateur se connecte ensuite à l’adresse VPN du serveur pour saisir un code 2FA
  • La durée de validité de la session avant expiration est définie dans le fichier de configuration

Console d’administration web

  • Pour se connecter à la console d’administration, il faut définir Webserver.Management.Enabled sur true
  • Depuis la console, un compte administrateur web est ajouté avec sudo ./wag webadmin -add -username <your_username> -password <your-password-here>
  • Il faut ensuite se connecter à l’adresse d’écoute d’administration et saisir les identifiants
  • L’interface web elle-même ne permet pas d’ajouter des utilisateurs administrateurs
  • Il est recommandé de ne pas exposer le portail d’administration à l’extérieur ; il est conseillé de définir ListenAddress sur 127.0.0.1 ou localhost et de l’exposer via un forwarding SSH

Principaux paramètres de configuration

  • NumberProxies indique le nombre de reverse proxies de confiance situés devant les clients et permet à Wag d’interpréter X-Forward-For pour analyser l’IP cliente
  • Socket est le socket de contrôle de Wag ; le modifier permet d’exécuter plusieurs instances de Wag sur la même machine
  • NAT active ou désactive le masquage ; lorsqu’il est activé, tout le trafic semble provenir du serveur VPN
  • NATExcludeRanges définit les plages CIDR à exclure du NAT lorsque NAT=true
  • ExposePorts expose des ports du serveur VPN aux clients et ajoute des règles iptables
  • CheckUpdates est désactivé par défaut ; lorsqu’il est activé, l’interface d’administration affiche des notifications de nouvelle version de Wag et accède à api.github.com
  • Acls définit les groupes et politiques, mais n’est pris en compte qu’au premier démarrage ; ensuite, l’édition se fait via l’interface web
  • Webserver inclut les réglages du point de terminaison public d’inscription, du portail MFA du tunnel et du portail d’administration
  • Wireguard configure le nom de l’interface, le port d’écoute, la clé privée, le sous-réseau géré par le VPN, la MTU et les serveurs DNS
  • Clustering inclut le nom du cluster, l’état du cluster etcd, le niveau de logs, les nœuds witness, l’emplacement de la base de données et les réglages liés aux certificats du cluster

Fonctionnement des politiques ACL

  • Policies définissent les routes capturées par le VPN ainsi que les ports et protocoles autorisés via Wag
  • L’application des règles utilise la longueur de préfixe du sous-réseau, et la correspondance la plus spécifique détermine le niveau d’accès à la route
  • Par exemple, si un /16 est défini en MFA et qu’un /32 spécifique à l’intérieur est défini en Allow, le /32 plus spécifique est prioritaire et devient accessible sans MFA
  • Ce comportement a changé dans v6.0.0 ; auparavant, les routes MFA étaient toujours prioritaires
  • Si plusieurs politiques sont définies pour une même route, elles sont combinées, et les règles MFA restent prioritaires
  • À partir d’une version pas encore publiée, des règles Deny permettront de bloquer l’accès à une route
  • La règle la plus spécifique crée un nouveau « bucket » de règles ; s’il n’y a qu’un deny dans un bucket /32, l’accès à d’autres ports de ce même /32 peut aussi ne pas être autorisé

Règles de ports et protocoles

  • L’accès aux services peut être défini avec des règles de ports et de protocoles
  • Trois types de règles sont pris en charge
    • Any : s’il n’y a pas de règle dédiée ou si le mot-clé any est utilisé, toutes les combinaisons de services et de ports sont autorisées
    • Single Service : permet d’autoriser des ports TCP ou UDP spécifiques d’un hôte, par exemple 192.168.1.1 22/tcp 53/udp
    • Ranges : permet de définir des plages de ports, par exemple 192.168.1.1 22-1024/tcp 23-53/any
  • Dans une plage de ports, le port le plus bas doit être indiqué en premier
  • ICMP n’ayant pas de port, il peut être indiqué sans port, comme 1.1.1.1 icmp

Limites et développement

  • Wag ne prend en charge qu’un seul AllowedIP par client
  • Cette limite convient à une architecture où le client se connecte au serveur
  • Le projet vise principalement Linux, et Windows peut fonctionner avec quelques manipulations
  • En mode développement, une variable d’environnement peut être utilisée pour définir l’IP des requêtes entrantes du tunnel comme IP cliente
  • L’exemple de test exécute sudo go test -v . dans internal/router
  • Pour les contributions externes, il est demandé d’ajouter des tests si possible lors d’un ajout de fonctionnalité ou d’une correction de bug, puis d’ouvrir une Pull Request

1 commentaires

 
GN⁺ 2024-05-13
Commentaires Hacker News
  • Ça a l’air bien, mais quelques points me gênent.
    L’exemple curl [http://public.server.address:8080/register_device?key=e83253...](<http://public.server.address/register_device/…;) et la description selon laquelle « le service renvoie une réponse entièrement templatisée » donnent l’impression que, pendant le processus d’enregistrement, ce n’est pas le client qui crée une clé privée et envoie la clé publique au serveur, mais le serveur qui crée la clé privée et l’envoie au client.
    En plus, l’exemple est en HTTP, donc il vaudrait mieux au moins changer ça pour éviter que les gens pensent que HTTP est aussi une option acceptable.
    Je me demande aussi si le client a un moyen de s’apercevoir qu’une session a expiré. Ou est-ce qu’une session SSH, par exemple, se contente de se figer ?
    J’ai parfois cherché un client WireGuard qui se comporte comme la détection de portail captif du Wi‑Fi. Idéalement, il suffirait d’ajouter une ligne du genre persistentkeepalive au fichier de configuration pour récupérer une URL et la vérifier périodiquement. Si OK revient, tout va bien ; s’il n’y a pas de réponse, c’est un problème réseau ; si un en-tête Location revient, le navigateur s’ouvre à cet emplacement pour réauthentifier la session, etc.
    Je n’ai pas encore trouvé un tel client.

    • L’URL d’enregistrement peut aussi accepter en option un paramètre pubkey, donc il n’est pas nécessaire de dépendre de la génération de la clé privée par le serveur. La documentation est limitée, donc la confusion est compréhensible.
      Pour répondre à la dernière question, eBPF XDP tel que je l’utilise ne permet que PASS, DROP et REDIRECT. Je traite donc ça avec le résultat le plus simple, PASS/DROP, et la connexion se fige simplement.
      Cela dit, si on ajoute la page de détection de portail captif à la liste MFA de wag, on peut configurer la détection soi-même, puis le navigateur s’occupera du reste.
      Je n’ai pas l’intention d’implémenter dans wag une fonction d’interception ou de proxy. Cela rendrait l’expiration d’authentification ou la déconnexion un peu plus faciles à gérer, mais ce n’est pas la direction prise.
    • Une telle fonctionnalité serait vraiment super, et j’espère que l’auteur de ce projet l’envisagera.
    • J’ai déjà créé un serveur similaire. Il nécessitait un certificat client par appareil : on accédait avec ce certificat à la page de connexion en mTLS, puis l’utilisateur était authentifié via OIDC et le tunnel était activé. La partie difficile, c’était le client.
      J’ai écrit un client en Go pour Mac et utilisé la ligne de commande wg de Brew pour gérer aussi la génération de clés, mais c’était rudimentaire et il fallait sudo.
      Une vraie application native utilisant les autorisations réseau serait idéale, mais c’est au-delà de mes compétences.
  • Je me demande si le problème de la gestion de session a déjà été traité ou s’il est prévu de l’être.
    Fondamentalement, une clé WireGuard ressemble à une clé de session éternelle.
    À mon avis, si le logiciel qui implémente la couche de transport WireGuard veut être une vraie solution de serveur VPN, il doit aussi implémenter la gestion de session. Autrement dit, via un second canal avec le serveur, il faudrait faire tourner périodiquement les clés de session, fermer les sessions, changer les adresses IP, configurer de nouvelles routes et répéter l’authentification si nécessaire.

    • Pour ce genre d’usage, j’utiliserais Firezone. Il propose une option pour forcer les utilisateurs à se reconnecter régulièrement à la plateforme, et combiné à un fournisseur d’identité externe via OIDC, cela donne une solution très robuste et simple pour la gestion de session.
    • Je ne suis pas sûr de comprendre exactement ce que signifie « clé de session éternelle » dans le contexte de wag.
      La clé WireGuard permet de communiquer avec le serveur wag, mais la session réelle est maintenue dans une map eBPF indiquant si l’utilisateur est authentifié ou non.
      Ainsi, même si quelqu’un vole les éléments de clé privée, il ne peut pas accéder aux routes protégées par MFA.
    • Si je devais créer un client VPN de type GlobalProtect avec WireGuard, je mettrais une clé d’authentification permanente par client pour établir un tunnel initial jusqu’au contrôleur VPN, puis l’authentification se ferait à l’intérieur de ce tunnel et une clé de session distincte serait remise. Le premier tunnel serait fermé dès que l’authentification est terminée et que la vraie clé de session a été reçue.
    • Un second canal pour la rotation périodique des clés de session, la fermeture de session, le changement d’adresse IP, la configuration de nouvelles routes et la réauthentification, ce n’est pas en fait le protocole IKE d’IPsec ? Pourquoi ne pas simplement utiliser IPsec ?
  • Je me demande s’il y a une protection contre le bruteforce des codes TOTP, par exemple une limitation de débit ou du nombre de tentatives.
    J’ai parcouru rapidement le code et je n’ai rien trouvé de tel.
    Le scénario que j’imagine, c’est quelqu’un qui ouvre l’interface de saisie TOTP dans le navigateur, lance les outils de développement, puis essaie en boucle tous les codes TOTP possibles.

    • Il y a bien une défense contre le bruteforce des codes TOTP. Chaque authentification a une limite du nombre de tentatives que l’utilisateur peut effectuer ; au-delà, le compte est verrouillé et un administrateur doit le déverrouiller.
      L’idée est aussi de pousser l’utilisateur à se demander pourquoi l’appareil essaie de forcer l’authentification. Une telle situation peut indiquer une compromission de l’endpoint.
    • C’est probablement ici : https://github.com/NHAS/wag/blob/cdbdbec3393fa86bf6c823117c8...
    • Je ne connais pas les détails de cette implémentation, mais en général, si quelqu’un dispose déjà des informations de connexion nécessaires pour atteindre l’étape TOTP, c’est-à-dire le nom d’utilisateur et le mot de passe, alors cet utilisateur est déjà compromis.
  • Ça ressemble beaucoup à Headscale ou Tailscale. C’est bien de voir des alternatives pour gérer des réseaux WireGuard.
    Je me demande s’il existe un comparatif permettant de comprendre jusqu’où les fonctionnalités se recoupent, ce qui a été ajouté, ce qui est différent, et ce qui ne sera pas implémenté à l’avenir.

    • C’est clairement similaire dans le sens où cela utilise WireGuard.
      Je n’ai pas mis de comparaison directe dans la documentation, mais ce n’est pas vraiment la direction que je veux prendre pour le moment. Ce projet répond à mes besoins et il est assez amusant.
      Wag convient plutôt à une architecture hub-and-spoke avec des frontières nettes, plutôt qu’à un maillage façon Tailscale où tout peut se joindre et où les règles définissent l’overlay.
      Wag comme Tailscale ajoutent tous deux une intégration SSO et, de fait, une 2FA pour protéger les utilisateurs.
      Les deux ont une méthode d’enregistrement et une interface web d’administration, mais je suis un développeur solo qui n’aime pas le développement web, donc Tailscale sera sûrement beaucoup plus poli.
      Ce que je n’implémenterai clairement pas, c’est l’interception ou le proxy TLS pour rediriger les utilisateurs après une déconnexion de session. La raison principale est que le faire en eBPF est un peu trop lourd pour moi pour l’instant, et que je ne veux pas utiliser les composants DNAT/SNAT qu’il faudrait probablement écrire pour que cela fonctionne.
  • Uniquement IPv4, vraiment ? Les sites qui choisissent WireGuard pourraient très bien avoir une configuration plus moderne et utiliser beaucoup d’ULA auto-hébergées.

    • Je prévois d’ajouter la prise en charge d’IPv6 prochainement, et j’envisage aussi de mapper les adresses IPv4 des utilisateurs dans un espace IPv6 privé afin de réduire le risque de conflit avec leur vrai réseau local.
      Je me demande si tu avais quelque chose de particulier en tête en mentionnant les ULA.
    • Je me demande quel est ici l’avantage des ULA que tu as en tête.