VPN Wireguard full mesh OSPF sur Mikrotik v7.18

💡
Toutes les configurations sont commit sur mon github : https://github.com/Nathan0510/Blog

Encore un VPN ?

Oui mais à la différence du VXLAN, c'est un L3VPN. C'est un VPN récent dans le monde du réseau (2015). Il tend à remplacer les OpenVPN, IPsec, SSL.

Et la raison est vite trouvée. C'est beaucoup trop simple à mettre en place ! Il encapsule tout le trafic dans de l'UDP chiffré et se base sur les clés privées/publiques pour monter les tunnels entre client et serveur.

Wireguard permet aussi d'être autonome sur l'interconnexion de ses sites ! Adieu le MPLS et sa dépendance à un opérateur unique ?

Les deux derniers épisodes étaient dédiés au VXLAN et à sa mise en application dans des cas clients. Aujourd'hui, on va voir comment monter un full mesh wireguard en statique et dynamique via OSPF.

On va s'appuyer sur cette "infra". 3 CPE mikrotik où le switch réprésente Internet.

Configuration

Tout d'abord, on configure les IPs sur les CPE :

#CAEN
/ip address
add address=100.127.0.1/24 interface=ether1 network=100.127.0.0
add address=192.168.1.1/24 interface=ether2 network=192.168.1.0

#Saint-Brieuc
/ip address
add address=100.127.0.2/24 interface=ether1 network=100.127.0.0
add address=192.168.2.1/24 interface=ether2 network=192.168.2.0

#Cherbourg
/ip address
add address=100.127.0.3/24 interface=ether1 network=100.127.0.0
add address=192.168.3.1/24 interface=ether2 network=192.168.3.0

Puis on crée une interface wireguard sur les CPE:

/interface wireguard
add listen-port=12345 mtu=1420 name=wg

Par défaut, la MTU est de 1420 octets car elle convient à n'importe quelle architecture (PPPoE, IPv4, IPv6, etc).

Dans l'introduction, je vous ai dit que wireguard se base sur les échanges de clés. Il faut bien récupérer la clé publique :

[admin@Caen] > /interface/wireguard/print
Flags: X - disabled; R - running
 0  R name="wg" mtu=1420 listen-port=12345
      private-key="eGBZ8vGwXQyCoduCuFlfU7bZrPLuwatVAKajuI+D/GE="
      public-key="lfsrTdiO7i95UaqlrbV1yPhQh6RQYMDOWmj+OAGZljw=" 

La clé publique (et privée) sont différentes pour chaque CPE (et pour chaque équipement réseau d'un point de vue global). Ici, la clé publique est lfsrTdiO7i95UaqlrbV1yPhQh6RQYMDOWmj+OAGZljw=. Elle va nous servir juste après !

On attribue une IP à l'interface wg (seul le dernier digit change sur les CPE) :

/ip address
add address=100.126.0.1/24 interface=wg network=100.126.0.0

Pour faire un full mesh, il faut (n-1)*n tunnels (où n est le nombre de CPE). Soit on choisit de mettre toutes les interfaces wireguard dans le même niveau 2 soit on crée une interco IP pour chaque tunnel (donc (3-1)*3=6 interfaces) ! Et bien sûr, en tant que bon administrateur réseau, je suis fainéant ! J'ai donc opté pour un grand niveau 2.

Ensuite, on s'attaque à la configuration des tunnels :

/interface wireguard peers
add allowed-address=100.126.0.3/32,192.168.3.0/24 endpoint-address=100.127.0.3 endpoint-port=12345 interface=wg name=To_Cherbourg public-key="9XO9LK2WU/dfs0VlIEUWfEBOssax59LlovboFUQxAwA="
add allowed-address=100.126.0.2/32,192.168.2.0/24 endpoint-address=100.127.0.2 endpoint-port=12345 interface=wg name=To_St-Brieuc public-key="gWCmmAR+h+7F0OnqnoMkt0D/Z1HJM0rim4hNlcLgeE8="
  1. Allowed-address : Subnet du site distant auquel le trafic entrant pour ce peer est autorisé et vers lequel le trafic sortant pour ce peer est dirigé
  2. Endpoint-address : IP WAN du CPE
  3. Endpoint-port : Port d'écoute du process wireguard distant
  4. Interface : Interface wireguard qu'on a crée
  5. Name : Une petite description du peer ne tue pas !
  6. Public-key : La clé publique du CPE distant

Pour les allowed-address, on est obligé de renseigner l'IP de l'interface wg du site distant pour que ce dernier soit autorisé à monter le peer.

Et surtout, il ne faut pas oublier les routes !

#CAEN
/ip route
add dst-address=192.168.3.0/24 gateway=wg
add dst-address=192.168.2.0/24 gateway=wg

Un petit ping pour tester tout ça ?

[admin@Caen] > /ping 192.168.2.1 count=1
  SEQ HOST                                     SIZE TTL TIME       STATUS
    0 192.168.2.1                                56  64 2ms277us
    sent=1 received=1 packet-loss=0% min-rtt=2ms277us avg-rtt=2ms277us
   max-rtt=2ms277us

[admin@Caen] > /ping 192.168.3.1 count=1
  SEQ HOST                                     SIZE TTL TIME       STATUS
    0 192.168.3.1                                56  64 2ms634us
    sent=1 received=1 packet-loss=0% min-rtt=2ms634us avg-rtt=2ms634us
   max-rtt=2ms634us

On a donc crée un tunnel full mesh entre tout nos sites distants ! Plutôt pas mal nan ? Cela permet de ne plus commander tout les liens chez le même opérateur et d'être autonome et indépendant sur l'interconnexion de nos différentes agences.

Mais le routage statique n'est pas du tout stylé ! Trop de gestion, trop naze. On va faire du routage dynamique avec de l'OSPF (et on va s'apercevoir des limites de l'OSPF dans une archi full mesh).

OSPF

💡
Cet épisode ne tend pas à expliquer l'OSPF.
💡
La configuration ci dessous se fait sur le CPE de Caen. Il faut adapter les IPs sur les autres CPE.

On commence par crée une instance OSPF avec comme router-id, l'IP de l'interface wg :

/routing ospf instance
add disabled=no name=full-mesh router-id=100.126.0.1

On attribue une aire OSPF à cette instance qu'on nomme area-wg :

/routing ospf area
add disabled=no instance=full-mesh name=area-wg

Ensuite, on place l'interface wg et on annonce le subnet :

routing/ospf/interface-template
add area=area-wg disabled=no networks=192.168.1.0/24
add area=area-wg disabled=no interfaces=wg type=ptp

Et c'est tout ?

Bah, visiblement non puisque aucun neighbor de UP :

[admin@Caen] /routing/ospf> neighbor/print
Flags: V - virtual; D - dynamic

Et c'est tout con (mais fallait y penser, j'ai mis un moment !). OSPF utilise une adresse multicast pour échanger les informations ! Et ce fameux subnet n'était pas dans les allowed-address ....

Allez, on l'autorise dans les allowed-address des peers :

/interface wireguard peers
add allowed-address=224.0.0.0/24,100.126.0.3/32,192.168.3.0/24 endpoint-address=100.127.0.3 endpoint-port=12345 interface=wg name=To_Cherbourg public-key="9XO9LK2WU/dfs0VlIEUWfEBOssax59LlovboFUQxAwA="
add allowed-address=224.0.0.0/24,100.126.0.2/32,192.168.2.0/24 endpoint-address=100.127.0.2 endpoint-port=12345 interface=wg name=To_St-Brieuc public-key="gWCmmAR+h+7F0OnqnoMkt0D/Z1HJM0rim4hNlcLgeE8=" 

Bon et maintenant ?

[admin@Caen] /routing/ospf/neighbor> print
Flags: V - virtual; D - dynamic
 0  D instance=full-mesh area=area-wg address=100.126.0.2 priority=128
      router-id=100.126.0.2 dr=100.126.0.3 bdr=100.126.0.1 state="Full"
      state-changes=6 adjacency=31m7s timeout=33s

Je n'ai qu'un seul neighbor de UP ☹️

Il faut se rappeler de la définition du allowed-address : Subnet du site distant auquel le trafic entrant pour ce peer est autorisé et vers lequel le trafic sortant pour ce peer est dirigé.

Donc si on ajoute 224.0.0.0/24 dans les allowed-address d'un peer, TOUT le trafic est "routé" sur ce tunnel. Cela veut dire qu'on ne peut pas ajouter le même subnet dans deux peers différents !

Comment va-t-on faire ?

Au lieu que les neighbors montent automatiquement, on va les renseigner à la main.

Allez, on retire le 224.0.0.0/24 dans les allowed-address :

/interface wireguard peers
add allowed-address=100.126.0.3/32,192.168.3.0/24 endpoint-address=100.127.0.3 endpoint-port=12345 interface=wg name=To_Cherbourg public-key="9XO9LK2WU/dfs0VlIEUWfEBOssax59LlovboFUQxAwA="
add allowed-address=100.126.0.2/32,192.168.2.0/24 endpoint-address=100.127.0.2 endpoint-port=12345 interface=wg name=To_St-Brieuc public-key="gWCmmAR+h+7F0OnqnoMkt0D/Z1HJM0rim4hNlcLgeE8="  

On passe l'interface wg en type NBMA :

[admin@Caen] /routing/ospf/interface-template> print
Flags: X - disabled, I - inactive
 0   area=area-wg interfaces=wg instance-id=0 type=ptp retransmit-interval=5s
     transmit-delay=1s hello-interval=10s dead-interval=40s priority=128
     cost=1

 1   area=area-wg instance-id=0 networks=192.168.1.0/24 type=broadcast
     retransmit-interval=5s transmit-delay=1s hello-interval=10s
     dead-interval=40s priority=128 cost=1
  
[admin@Caen] /routing/ospf/interface-template> set 0 type=nbma
  
[admin@Caen] /routing/ospf/interface-template> print where interfaces=wg
Flags: X - disabled, I - inactive
 0   area=area-wg interfaces=wg instance-id=0 type=nbma retransmit-interval=5s
     transmit-delay=1s hello-interval=10s dead-interval=40s priority=128
     cost=1

Ensuite, on configure les neighbors :

/routing ospf static-neighbor
add address=100.126.0.2%wg area=area-wg disabled=no
add address=100.126.0.3%wg area=area-wg disabled=no

Il faut penser à rajouter le %wg !

Enfin fonctionnel ?

[admin@Caen] /routing/ospf/neighbor> print
Flags: V - virtual; D - dynamic
 0  D instance=full-mesh area=area-wg address=100.126.0.2 priority=128
      router-id=100.126.0.2 dr=100.126.0.3 bdr=100.126.0.1 state="Full"
      state-changes=6 adjacency=44m1s timeout=39s

 1  D instance=full-mesh area=area-wg address=100.126.0.3 priority=128
      router-id=100.126.0.3 dr=100.126.0.3 bdr=100.126.0.1 state="Full"
      state-changes=6 adjacency=45m21s timeout=39s

Les neighbors sont UP. Et maintenant, la table de routage ?

[admin@Caen] /ip/route> print
Flags: D - DYNAMIC; A - ACTIVE; c - CONNECT, o - OSPF
Columns: DST-ADDRESS, GATEWAY, DISTANCE
    DST-ADDRESS     GATEWAY         DISTANCE
DAc 100.126.0.0/24  wg                     0
DAc 100.127.0.0/24  ether1                 0
DAc 192.168.1.0/24  ether2                 0
DAo 192.168.2.0/24  100.126.0.2%wg       110
DAo 192.168.3.0/24  100.126.0.3%wg       110 

Les routes sont bien apprises avec une AD de 110.

[admin@Caen] > /ping 192.168.2.1 count=1
  SEQ HOST                                     SIZE TTL TIME       STATUS
    0 192.168.2.1                                56  64 2ms711us
    sent=1 received=1 packet-loss=0% min-rtt=2ms711us avg-rtt=2ms711us
   max-rtt=2ms711us

[admin@Caen] > /ping 192.168.3.1 count=1
  SEQ HOST                                     SIZE TTL TIME       STATUS
    0 192.168.3.1                                56  64 2ms669us
    sent=1 received=1 packet-loss=0% min-rtt=2ms669us avg-rtt=2ms669us
   max-rtt=2ms669us

La communication est fonctionnelle !

Et après ?

Le choix d'un full mesh est discutable surtout quand on doit configurer chaque tunnel à la main (ou même via générateur de configuration). Les CPE se font lourds et les neighbors en static en OSPF ...

A contrario de l'IPsec où les CPE peuvent monter de façon dynamique des tunnels entre eux (DMVPN phase 3 pour Cisco, ADVPN pour Fortinet).

Un full mesh est clairement à éviter ! Une autre architecture intéressante serait en Hub&Spoke. On peut très bien penser à un mikrotik virtuel (CHR) hébergé chez OVH ou dans n'importe quel nuage !

Tous les spokes vont monter un peer avec le hub et dans les allowed-address, on va enfin mettre 0.0.0.0/0 !!! (ou la RFC 1918 par exemple).

Allez, on a le sujet du prochain épisode !

Je termine sur un mot de fin : N'est ce pas paradoxal de chercher la paix tout en préparant la guerre ?