VPN Wireguard Hub&Spoke sur Mikrotik v.7.18

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

Architecture

A la différence d'un full mesh et de ses (n-1)*n tunnels, une topologie en Hub&Spoke ne va nécessiter que n tunnels (où n est le nombre de spokes).

Ca ressemble à ça :

Où chaque spoke (routeur, firewall chez le client) monte un tunnel avec le hub. L'interconnexion des sites clients se fait donc sur le HUB. On aime bien de l'Hub&Spoke dans une topologie SDWAN par exemple. Sur Fortinet, un HUB peut être un VDOM ou une FortiVM !

Allez, on s'y colle sur mikrotik avec du wireguard dans cette architecture :

Le but final est de rediriger tout le trafic internet des spokes vers le hub. On pourra ainsi faire du filtrage intersite par exemple ! (le routeur interco sert de routeur qui interconnecte tous les sites clients. Internet dans la vraie vie 😄)

Configuration

💡
Je ne vais montrer que la configuration de Caen et du Hub. Pour les autres spokes, il suffit de changer le plan IP

Je ne vais pas réexpliquer toute la configuration du wireguard et de l'OSPF. Cela a été vu dans l'épisode précédent.

Le plan d'adressage :

Routeur Interco IP interface Wg LAN
Caen 100.127.1.0/31 100.126.0.1/24 192.168.1.0/24
Saint-Brieuc 100.127.2.0/31 100.126.0.2/24 192.168.2.0/24
Cherbourg 100.127.3.0/31 100.126.0.3/24 192.168.3.0/24
HUB 100.127.4.0/31 100.126.0.254/24 100.100.100.0/24

Allez, on s'active !

#CAEN
/ip address
add address=100.127.1.1/31 interface=ether1 network=100.127.1.0
add address=192.168.1.1/24 interface=ether2 network=192.168.1.0
add address=100.126.0.1/24 interface=wg network=100.126.0.0

/ip route
add dst-address=0.0.0.0/0 gateway=100.127.1.0
add dst-address=100.100.100.0/24 gateway=wg


#HUB
/ip address
add address=100.127.4.1/31 interface=ether1 network=100.127.4.0
add address=100.100.100.1/24 interface=ether2 network=100.100.100.0
add address=100.126.0.254/24 interface=wg network=100.126.0.0
add address=109.205.66.1/30 comment=To_Internet interface=ether4 network=109.205.66.0

/ip route
add dst-address=100.127.0.0/16 gateway=100.127.4.0
add dst-address=0.0.0.0/0 add gateway=109.205.66.2
add dst-address=192.168.1.0/24 gateway=100.127.4.0
add dst-address=192.168.2.0/24 gateway=100.127.4.0
add dst-address=192.168.3.0/24 gateway=100.127.4.0

La configuration wireguard : (on pense bien à faire attention aux clés surtout !

#CAEN
/interface wireguard
add listen-port=12345 mtu=1420 name=wg
  
/interface wireguard peers
add allowed-address=0.0.0.0/0 endpoint-address=100.127.4.1 endpoint-port=12345 interface=wg name=To_Hub public-key="QBsAuNYMeIUeIaYtC0dmB9bKzSDfIhXcdWfxxrlWKUc="


#HUB
/interface wireguard
add listen-port=12345 mtu=1420 name=wg
  
/interface wireguard peers
add allowed-address=100.126.0.3/32,192.168.3.0/24 endpoint-address=100.127.3.1 endpoint-port=12345 interface=wg name=To_Cherbourg public-key="06KDt9Fn+PZeKCHjQ/6tX+q4sUlLlQq+BPkgCRd+mD0="
add allowed-address=100.126.0.1/32,192.168.1.0/24 endpoint-address=100.127.1.1 endpoint-port=12345 interface=wg name=To_Caen public-key="Heyq3ufeU7/AIPHADrRVGYO444sD92YN/KDg7VvYFmU="
add allowed-address=100.126.0.2/32,192.168.2.0/24 endpoint-address= 100.127.2.1 endpoint-port=12345 interface=wg name=To_St-brieuc public-key="XCBDlmLxt5kEZ9NcEufjf9P8T0Vr8APE7AkAS05K0So="

Regardez bien les allowed-address sur le spoke ! 0.0.0.0/0

Plus besoin de renseigner les allowed-address. On met 0.0.0.0/0 et tout le trafic avec un route vers le tunnel wireguard sera autorisé à traverser !!!

Côté hub, pas grand chose de particulier. On est obligé de renseigner les LANs des spokes sinon doublon d'allowed-address et wireguard n'aime pas trop ça 😦

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

Communication opérationnelle ! Maintenant place à l'OSPF.

#CAEN
/routing ospf instance
add disabled=no name=Hub&Spoke router-id=100.126.0.1
/routing ospf area
add disabled=no instance=Hub&Spoke name=area-wg
/routing ospf interface-template
add area=area-wg disabled=no interfaces=wg type=nbma
add area=area-wg disabled=no networks=192.168.1.0/24
/routing ospf static-neighbor
add address=100.126.0.254%wg area=area-wg disabled=no


#HUB
/routing ospf instance
add disabled=no name=Hub&Spoke router-id=100.126.0.254
/routing ospf area
add disabled=no instance=Hub&Spoke name=area-wg
/routing ospf interface-template
add area=area-wg disabled=no interfaces=wg type=nbma
add area=area-wg disabled=no networks=100.100.100.0/24
/routing ospf static-neighbor
add address=100.126.0.1%wg area=area-wg disabled=no
add address=100.126.0.2%wg area=area-wg disabled=no
add address=100.126.0.3%wg area=area-wg disabled=no

On est toujours obligé de faire des peer static étant donné que l'OSPF utilise une adresse multicast pour ses échanges ! On devrait rajouter ce subnet dans les allowed-address de tout les peers wireguard sur le HUB mais c'est impossible !

Côté Spoke, on fait un neighbor uniquement avec le HUB et sur ce dernier, avec tous les SPOKES.

#CAEN
[admin@Caen] /ip/route> pr
Flags: D - DYNAMIC; A - ACTIVE; c - CONNECT, s - STATIC, o - OSPF
Columns: DST-ADDRESS, GATEWAY, DISTANCE
#     DST-ADDRESS       GATEWAY           DISTANCE
0  As 0.0.0.0/0         100.127.1.0              1
  DAo 100.100.100.0/24  100.126.0.254%wg       110
  DAc 100.126.0.0/24    wg                       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
  DAc 100.127.1.0/31    ether1                   0


#HUB
[admin@Hub] /ip/route> pr
Flags: D - DYNAMIC; A - ACTIVE; c - CONNECT, s - STATIC, o - OSPF
Columns: DST-ADDRESS, GATEWAY, DISTANCE
#     DST-ADDRESS       GATEWAY         DISTANCE
0  As 0.0.0.0/0         109.205.66.2           1
1  As 100.127.0.0/16    100.127.4.0            1
  DAc 100.100.100.0/24  ether2                 0
  DAc 100.126.0.0/24    wg                     0
  DAo 192.168.1.0/24    100.126.0.1%wg       110
  DAo 192.168.2.0/24    100.126.0.2%wg       110
  DAo 192.168.3.0/24    100.126.0.3%wg       110
  DAc 109.205.66.0/30   ether4                 0
  DAc 100.127.4.0/31    ether1                 0

Le HUB apprend bien les routes des différents spokes et les rannonce à tous les SPOKES.

#HUB
[admin@Caen] > /ping 192.168.2.1 src-address=192.168.1.1 count=1
  SEQ HOST                                     SIZE TTL TIME       STATUS
    0 192.168.2.1                                56  63 4ms15us
    sent=1 received=1 packet-loss=0% min-rtt=4ms15us avg-rtt=4ms15us max-rtt=4ms15us

[admin@Caen] > /ping 192.168.3.1 src-address=192.168.1.1 count=1
  SEQ HOST                                     SIZE TTL TIME       STATUS
    0 192.168.3.1                                56  63 4ms150us
    sent=1 received=1 packet-loss=0% min-rtt=4ms150us avg-rtt=4ms150us max-rtt=4ms150us

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

Le spoke de Caen arrive bien à communiquer avec les spokes de Saint-Brieuc, de Cherbourg et en prime, le LAN derrière le HUB (cela peut être une zone hosting par exemple !).

On a donc configuré un Hub&Spoke wireguard sur Mikrotik ! Plus simple que le full mesh n'est ce pas ?

C'est tellement court que je vais rallonger un peu l'épisode 😄

Mais où sort le flux internet des spokes ?

Très bonne question !

Et la réponse semble évidente, par la default route des spokes. On appelle cela le local breakout. Les tunnels permettent de faire transiter uniquement les communications intersites et la sortie internet se fait en local.

Franchement, quitte à faire de l'Hub&Spoke, ca sera pas encore plus stylé de faire passer le trafic Internet par le HUB ? Comme ça, plus qu'un seul point de sortie et d'entrée ! Stylax ?

Bon on s'y met !

Tout d'abord, il faut comprendre le routage sur les spokes :

#CAEN
[admin@Caen] /ip/route> pr
Flags: D - DYNAMIC; A - ACTIVE; c - CONNECT, s - STATIC, o - OSPF
Columns: DST-ADDRESS, GATEWAY, DISTANCE
#     DST-ADDRESS       GATEWAY           DISTANCE
0  As 0.0.0.0/0         100.127.1.0              1
  DAo 100.100.100.0/24  100.126.0.254%wg       110
  DAc 100.126.0.0/24    wg                       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
  DAc 100.127.1.0/31    ether1                   0

La default route est sur l'interface ether1. On souhaite qu'elle soit sur l'interface wg.

On va donc l'annoncer dans l'OSPF :

#HUB
[admin@Hub] /routing/ospf> /routing ospf instance
[admin@Hub] /routing/ospf/instance> pr
Flags: X - disabled, I - inactive
 0   name="Hub&Spoke" version=2 vrf=main router-id=100.126.0.254
[admin@Hub] /routing/ospf/instance> set 0 originate-default=if-installed

[admin@Hub] /routing/ospf/instance> export
/routing ospf instance
add disabled=no name=Hub&Spoke originate-default=if-installed router-id=100.126.0.254

Avec le originate-default=if-installed, le HUB va annoncer la default route SI ET SEULEMENT SI il la connait !

[admin@Caen] /ip/route> pr
Flags: D - DYNAMIC; A - ACTIVE; c - CONNECT, s - STATIC, o - OSPF
Columns: DST-ADDRESS, GATEWAY, DISTANCE
#     DST-ADDRESS       GATEWAY           DISTANCE
0  As 0.0.0.0/0         100.127.1.0              1
  D o 0.0.0.0/0         100.126.0.254%wg       110
  DAo 100.100.100.0/24  100.126.0.254%wg       110
  DAc 100.126.0.0/24    wg                       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
  DAc 100.127.1.0/31    ether1                   0

La default route est bien annoncée mais pas prioritaire car la route statique a une distance administrative de 1 (donc plus basse que 110). Comment bypass ça ?

Tout d'abord, on va rajouter l'IP du HUB en /32 et on supprime la defaut route statique :

#CAEN
/ip route
add dst-address=100.127.4.1 gateway=100.127.1.0

[admin@Caen] /ip/route> pr
Flags: D - DYNAMIC; A - ACTIVE; c - CONNECT, s - STATIC, o - OSPF
Columns: DST-ADDRESS, GATEWAY, DISTANCE
#     DST-ADDRESS       GATEWAY           DISTANCE
  DAo 0.0.0.0/0         100.126.0.254%wg       110
  DAo 100.100.100.0/24  100.126.0.254%wg       110
  DAc 100.126.0.0/24    wg                       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
  DAc 100.127.1.0/31    ether1                   0
0  As 100.127.4.1/32    100.127.1.0              1

Le tunnel est toujours monté et la communication toujours autant fonctionnelle :

#CAEN
[admin@Caen] > /ping 192.168.3.1 src-address=192.168.1.1 count=1
  SEQ HOST                                     SIZE TTL TIME       STATUS
    0 192.168.3.1                                56  63 3ms981us
    sent=1 received=1 packet-loss=0% min-rtt=3ms981us avg-rtt=3ms981us max-rtt=3ms981us

Par contre, si pour x ou y raisons, le HUB perd sa route internet (généralement, dans un backbone opérateur, la route est apprise en BGP), le SPOKE perd lui aussi sa default route !

Pour corriger cela, on rajoute une default route en statique mais une AD > 110 !

#CAEN
/ip route
add dst-address=0.0.0.0/0 gateway=100.127.1.0 distance=111 

[admin@Caen] /ip/route> pr
Flags: D - DYNAMIC; A - ACTIVE; c - CONNECT, s - STATIC, o - OSPF
Columns: DST-ADDRESS, GATEWAY, DISTANCE
#     DST-ADDRESS       GATEWAY           DISTANCE
  DAo 0.0.0.0/0         100.126.0.254%wg       110
0   s 0.0.0.0/0         100.127.1.0            111
  DAo 100.100.100.0/24  100.126.0.254%wg       110
  DAc 100.126.0.0/24    wg                       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
  DAc 100.127.1.0/31    ether1                   0
1  As 100.127.4.1/32    100.127.1.0              1

C'est toujours la default route apprise en OSPF qui est active.

Admettons le HUB tombe :

#HUB
/ip/route
set 0 disabled=yes

#CAEN
[admin@Caen] /ip/route> pr
Flags: D - DYNAMIC; A - ACTIVE; c - CONNECT, s - STATIC, o - OSPF
Columns: DST-ADDRESS, GATEWAY, DISTANCE
#     DST-ADDRESS       GATEWAY           DISTANCE
0  As 0.0.0.0/0         100.127.1.0            111
  DAo 100.100.100.0/24  100.126.0.254%wg       110
  DAc 100.126.0.0/24    wg                       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
  DAc 100.127.1.0/31    ether1                   0
1  As 100.127.4.1/32    100.127.1.0              1

On disabled la default route sur le HUB (on aurait pu aussi shut l'interface WAN du HUB) et on s'aperçoit que la route par défaut est bien celle apprise en statique donc le trafic internet passera en local 😄

Bon et pour finir, l'accès Internet par le HUB :

#HUB
/ip firewall address-list
add address=192.168.1.0/24 comment=LAN-CAEN list=LAN
add address=192.168.2.0/24 comment=LAN-ST_BRIEUC list=LAN
add address=192.168.3.0/24 comment=LAN-CHERBOURG list=LAN
add address=100.100.100.0/24 comment=LAn-HOSTING list=LAN

/ip firewall nat
add action=masquerade chain=srcnat out-interface=ether4 src-address-list=LAN
#HUB
[admin@Caen] > /ping 8.8.8.8 src-address=192.168.1.1 count=1
  SEQ HOST                                     SIZE TTL TIME       STATUS
    0 8.8.8.8                                    56  63 3ms58us
    sent=1 received=1 packet-loss=0% min-rtt=3ms58us avg-rtt=3ms58us max-rtt=3ms58us


#HUB
[admin@Hub] > /tool/sniffer/quick ip-protocol=icmp
Columns: INTERFACE, TIME, NUM, DIR, SRC-MAC, DST-MAC, SRC-ADDRESS
INTERFACE  TIME   NUM  DIR  SRC-MAC            DST-MAC            SRC-ADDRESS
wg         2.225    1  <-                                         192.168.1.1
ether4     2.225    2  ->   50:00:00:14:00:03  50:00:00:13:00:03  109.205.66.1
ether4     2.225    3  <-   50:00:00:13:00:03  50:00:00:14:00:03  8.8.8.8
wg         2.226    4  ->                                         8.8.8.8

Le trafic Internet passe bien par le HUB !!!! Et si le HUB plante, le trafic passe en local breakout.

Avant de se quitter, un peu de filtrage intersite ?

Avant :

[admin@Caen] > /ping 192.168.2.1 src-address=192.168.1.1 count=1
  SEQ HOST                                     SIZE TTL TIME       STATUS
    0 192.168.2.1                                56  63 4ms15us
    sent=1 received=1 packet-loss=0% min-rtt=4ms15us avg-rtt=4ms15us max-rtt=4ms15us

Mise en place de l'ACL :

#HUB
/ip firewall address-list
add address=192.168.1.0/24 comment=LAN-CAEN list=LAN-CAEN
add address=192.168.2.0/24 comment=LAN-ST_BRIEUC list=LAN-ST_BRIEUC

/ip firewall filter
add action=drop chain=forward dst-address-list=LAN-ST_BRIEUC src-address-list=LAN-CAEN

Après :

[admin@Caen] > /ping 192.168.2.1 src-address=192.168.1.1 count=1
  SEQ HOST                                     SIZE TTL TIME       STATUS
    0 192.168.2.1                                                  timeout
    sent=1 received=0 packet-loss=100%

La communication est bien deny 😃

Suite ?

J'ai décidé de me focus un peu sur la partie demande cliente et donc de la configuration des CPE.

Et au lieu de faire l'habituel (MPLS, IPsec), j'ai voulu faire comprendre que les DSI ne sont plus obligées de faire confiance à l'opérateur pour interconnecter leurs sites. Un wireguard sur chaque spoke avec un mikrotik virtuel chez OVH suffit amplement et fera économiser plusieurs milliers d'euros.

Le VXLAN et le Wireguard étaient les deux seuls sujets que j'avais en tête. Peut-être que j'en trouverai d'autres après.

On a fait une petite passe sur la partie cliente. Maintenant, reprenons notre infrastructure backbone. Prochain épisode : migration des LNS en IOS-XR ! (ou en mikrotik si j'arrive à faire fonctionner ce foutu radius sur RouterOS).