WireGuard : découverte d'un VPN moderne, simple et multiplateforme

Les VPN (ou réseaux privés virtuels en français) sont des outils très pratiques, qui permettent d'interconnecter deux réseaux, de sécuriser la connexion entre deux machines, de sécuriser sa connexion à internet lorsque l'on se connecte dans des lieux publics ou encore de contourner des restrictions d'accès géographiques. J'utilise actuellement OpenVPN, aussi bien pour mes besoins perso que professionnels. Il fonctionne bien, il est supporté sur pas mal de plateformes, mais est assez lourd à mettre en place et à administrer... C'est pourquoi je commence à lorgner du côté de WireGuard.

WireGuard est un (relativement) nouveau protocole de VPN, moderne, open source, et qui implémente ce qui se fait de mieux niveau cryptographie (en tout cas c'est ce qui nous est promis par ses développeurs). Il est plus simple à mettre en place que les solutions habituelles telles qu'OpenVPN ou IPSec, et il offrirait à priori de meilleures performances en termes de débit (toujours selon les développeurs, je n'ai pas réalisé de benchmark moi-même).

Si on entend pas mal parler de lui ces derniers temps, c'est en partie parce que Linus Torvalds l'a mergé dans le noyau Linux récemment (fin janvier 2020). WireGuard fait donc maintenant partie du noyau Linux et sera donc prochainement disponible en standard sur toutes les distributions (il est en réalité déjà disponible sur la plupart des distributions sous forme de module complémentaire). Mais WireGuard ne s'arrête bien sûr pas à Linux et des clients sont également disponibles pour Windows, MacOS, Android et iOS,... On peut également espérer une intégration rapide dans les différents équipements réseau.

Dans cet article je vais vous faire découvrir le fonctionnement de WireGuard en lui-même. On va donc rester sur un setup basic et se contenter de créer un tunnel entre deux machines (ou plus) sous Linux, en configurant tout entièrement à la main. Ça nous permettra de bien voir quels sont les principes de bases et à quel point c'est simple ! Les machines pourront donc communiquer entre elles, mais ce sera tout, on n'abordera pas le routing cette fois-ci.

J'écrirais par la suite un second article dans lequel j'aborderais l'utilisation de fichiers de configuration (indispensable pour les clients mobiles et Windows notamment), ainsi que l'utilisation de wg-quick, un outil qui nous simplifiera la configuration de WireGuard sous Linux.

Puis dans de futurs articles, je vous présenterais des configurations type, de A à Z (NAT, site-to-site,...), avec toutes les configurations de parfeu et le routing nécessaire. Tout un programme ! 😁️

Nos machines

Pour cette introduction, on va considérer les deux machines suivantes :

  • Une que l'on appellera le serveur, qui devra être joignable depuis la ou les autres machines (à vous de configurer le port forwarding sur vos routeurs NAT si besoin).
  • Et une autre que l'on appellera le client.
Schéma des deux machines

Note

NOTE : Ma décision d'appeler l'une des machines « serveur » et l'autre « client » est quelque peu arbitraire ici. Lorsque l'on ne connecte que deux machines entre elles, la configuration est en fait assez symétrique entre les deux machines.

Installation de WireGuard

WireGuard est généralement disponible dans les dépôts de la plupart des distributions Linux récentes. Pour l'installer sous Ubuntu (à partir de la version 19.10), il faut taper la commande suivante :

sudo apt install wireguard

Pour les autres distributions, je vous laisse consulter la page dédiée sur le site de Wireguard.

Génération des clefs

WireGuard utilise un couple clef publique / clef privée pour gérer l'authentification du serveur et des différents clients (un peu de la même manière que SSH). Dans notre cas, la machine serveur devra connaître la clef publique du client et le client devra connaître la clef publique du serveur. On va donc commencer par générer lesdites clefs.

On commence par générer la clef privée du serveur à l'aide de la commande suivante :

wg genkey > server-private.key

Puis on dérive la clef privée que l'on vient de générer pour obtenir la clef publique :

wg pubkey < server-private.key > server-public.key

On répète ensuite les mêmes opérations pour générer les clefs du client :

wg genkey > client-private.key
wg pubkey < client-private.key > client-public.key

Note

NOTE : Ici on génère les clefs n'importe où, dans n'importe quel dossier, mais en réalité il faudrait les générer dans un dossier accessible uniquement à notre utilisateur. D'ailleurs les commandes ci-dessus se plaindront si ce n'est pas le cas.

Ici il s'agit d'un exemple, donc on s'en fout un peu, mais faites attention à la sécurité de vos clefs si vous installez WireGuard en production ! 😉️

Configuration du « serveur »

Une fois en possession de nos clefs, on peut passer à la configuration de notre serveur. Pour commencer, on va créer l'interface réseau wg0 par laquelle sortira notre tunnel VPN :

sudo ip link add dev wg0 type wireguard

Note

NOTE : Si vous rencontrez l'erreur « Error: Unknown device type. », c'est que le module wireguard n'est pas chargé dans le noyau Linux. Ceci peut être dû au secure boot. Désactivez le secure boot et réessayez.

Puis on lui assigne une adresse IP (c'est l'adresse par laquelle on pourra contacter la machine à travers le VPN) :

sudo ip address add 10.8.8.254 dev wg0

Et enfin on active notre interface :

sudo ip link set dev wg0 up

Maintenant que l'interface est prête, on passe à la configuration de WireGuard en lui-même. À l'aide de la commande suivante on lui fournit sa clef privée, et on lui indique sur quel port écouter (51820) :

sudo wg set wg0 listen-port 51820 private-key ./server-private.key

Le serveur est prêt, il ne reste plus qu'à lui indiquer quels clients pourront s'y connecter. Pour ce faire, on va lui indiquer pour chaque client, sa clef publique, ainsi que l'adresse IP (ou la page d'adresses) qu'il pourra s'attribuer à l'intérieur du VPN :

sudo wg set wg0 peer <clef_publique_client> allowed-ips 10.8.8.1/32

Si jamais on veut retirer l'accès à un client, il suffit de taper la commande suivante :

sudo wg set wg0 peer <clef_publique_client> remove

Note

NOTE : Dans le cas de la clef privée, il fallait fournir le chemin du fichier (./serveur-private.key), mais dans le cas de la clef publique, il faut fournir directement la clef, soit le contenu du fichier que l'on a généré (par exemple GGOyACJtzkby5[...]28pDrFc0TXkkw=).

Si vous avez la clef publique du client stockée dans un fichier sur le serveur, vous pouvez également remplacer <clef_publique_client> par $(cat ./client-public.key) dans les commandes précédentes.

Configuration du « client »

La configuration du client est assez similaire à celle du serveur, je ne vais donc pas rentrer dans les détails.

On commence cette fois encore par créer et configurer l'interface réseau :

sudo ip link add dev wg0 type wireguard
sudo ip address add dev wg0 10.8.8.1/24
sudo ip link set up dev wg0

Puis on configure ensuite WireGuard en lui fournissant sa clef privée :

sudo wg set wg0 private-key ./client-private.key

Et enfin on lui fournit les informations nécessaires pour se connecter au serveur :

sudo wg set wg0 peer <clef_publique_serveur> allowed-ips 10.8.8.0/24 endpoint vpn.example.org:51820 persistent-keepalive 25

Note

NOTE : comme dans cet exemple je souhaite uniquement permettre aux machines connectées au VPN de communiquer entre elles, j'ai défini allowed-ips à 10.8.8.0/24. Si je voulais router du trafic à travers le vpn, je pourrais autoriser toutes les IPs en lui définissant sa valeur à 0.0.0.0/0. Notez toutefois qu'il faudrait quelques configurations supplémentaires sur le serveur et sur le client pour router correctement les paquets (mais là ce n'est plus une problématique propre à WireGuard, c'est du réseau classique sous Linux). 😉️

Note

NOTE² : l'option persistent-keepalive 25 n'est pas obligatoire, mais si vous ne la mettez pas, vous aurez des soucis du style « le serveur n'arrive pas à joindre le client tant que le client n'a pas pingé le serveur en premier » si votre machine client se trouve derrière un routeur NAT. Le keepalive force le client à communiquer à interval régulier (toutes les 25 secondes dans le cas présent) avec le serveur afin de maintenir la connexion ouverte au sein du routeur NAT.

Vérification du fonctionnement

Pour s'assurer que tout fonctionne, on peut utiliser la commande suivante pour vérifier l'état du VPN :

sudo wg show wg0

Si tout est bien configuré, on devrait avoir une réponse semblable à celle-ci :

interface: wg0
  public key: <clef_publique_client>
  private key: (hidden)
  listening port: <port_client>

peer: <clef_publique_serveur>
  endpoint: <ip_serveur>:51820
  allowed ips: 10.8.8.0/24
  latest handshake: 13 minutes, 37 seconds ago
  transfer: 8.18 MiB received, 158.43 MiB sent

La ligne importante ici c'est latest handshake, qui prouve que le tunnel à bien pu être établi.

À ce stade, on peut également tenter un ping entre les machines pour être sûr que tout va bien.

Conclusion

Comme on l'a vu, WireGuard est très simple à mettre en place et ne s'occupe que de son tunnel. On gère tout le reste avec les outils standards de notre OS.

Ce qui me plait tout particulièrement, c'est son fonctionnement « à la SSH », à base de clef publique / clef privée... au revoir la génération et la gestion de certificats SSL comme on le faisait avec OpenVPN.

Le seul « défaut » que l'on pourrait lui trouver, c'est que comme il ne gère pas lui-même l'échange de clef, c'est à nous de le faire... Mais il existe déjà des tas d'interfaces pour gérer cette problématique.

WireGuard répond en tout cas parfaitement à mes besoins et ne va pas tarder à remplacer OpenVPN et IPSec que j'utilisais alors quotidiennement. J'espère que cet article vous aura donné envie de l'essayer, et je vous retrouve d'ici une semaine ou deux pour un second article où l'on verra comment automatiser sa configuration pour qu'il soit vraiment pratique à utiliser. 😁️