Ce billet relate la mise en œuvre d'un pare-feu redondant en utilisant OpenBSD, Packet Filter, CARP et pfsync.
Même si cette mise en œuvre se situe dans un cadre scolaire (« bouh c'est nul, on ne fait pas comme ça en vrai ! » diront certains), je pense qu'elle vaut la peine d'être partagée. La partie installation d'OpenBSD est un peu bête mais quand c'est exigé ... L'installation d'un pare-feu redondant n'était qu'une partie d'un travail plus vaste, cela explique certaines choses (adressage IP, CPE, ...).
Ce travail a été réalisé avec Hamza Hmama et Frédéric Deveaux.
Il y a déjà une masse de tutoriels concernant une telle mise en œuvre sur le web. Celui-ci se démarquera en montrant, de manière assez précise, comment valider le bon fonctionnement du pare-feu.
Table des matières
- Table des matières
- Présentation détaillée
- Mise en œuvre
- Installation d'OpenBSD
- Configuration réseau
- Configuration des interfaces réseau de FW1
- Configuration des interfaces réseau de FW2
- Configuration de la route par défaut sur FW1 et FW2
- Activation de l'IP forwarding sur FW1 et FW2
- Configuration de l'interface réseau du CPE
- Ajout d'une route sur le CPE
- Configuration de l'interface de notre serveur de test
- CARP
- Configuration de Packet Filter
- pfsync
- Valider le bon fonctionnement de notre pare-feu redondant
- Sources
Présentation détaillée
L'objectif est de déployer un pare-feu hautement disponible pour protéger des serveurs publics qui se situent dans une DMZ.
Le firewall est un service indispensable dans un réseau pour assurer la sécurité des connexions entrantes et sortantes. Utiliser un firewall redondant permet de diminuer énormément le risque que celui-ci soit hors service. En effet, il faut que toutes les machines physiques qui composent le cluster du firewall soient hors service (panne, maintenance, ...) à un instant précis, ce qui est moins probable qu'une seule machine.
Quelques exemples de déploiements d'une solution de ce type en entrée de gros sites : université de Rennes 1 (500 Mbps en entrée) et École normale supérieure. Voir : présentation « OpenBSD/Packet-Filter retour d'expérience » par Patrick LAMAIZIERE aux JRES 2013.
Pour ce faire, nous allons utiliser deux PC, sur lesquelles nous allons installer OpenBSD et configurer CARP et pfsync.
CARP est un protocole réseau qui autorise plusieurs machines à se partager un groupe d'IP dites virtuelles. Cela permet la haute disponibilité : pour que le service ne soit plus accessible, il faut que l'intégralité des machines qui se partagent le groupe d'IP soit hors service. CARP peut aussi servir à faire du partage de charge entre plusieurs machines (mode actif/actif (voir 4.2.2) en utilisant plusieurs groupes de redondance qui se partagent une même VIP). Nous n'utiliserons pas cette fonctionnalité mais resterons en mode actif/attente). CARP est l'équivalent du protocole propriétaire HSRP de Cisco et du protocole VRRP publié à l'IETF.
Pfsync permet de synchroniser les états de Packet Filter entre toutes les machines du cluster. Ainsi, une connexion qui a commencé en passant par FW1 n'est pas interrompue quand FW1 tombe (panne) et que FW2 prend la main.
Il n'existe aucun outil pour effectuer la synchronisation des règles du pare-feu entre les différentes machines du cluster. Un simple transfert sécurisé (scp) du jeu de règles puis un chargement des règles sur chaque machine avec ssh suffit amplement et s'automatise avec un simple script shell. Des scripts shell plus complets peuvent être trouvés sur le web. Exemple : Script to sync pf rules for CARP fws .
L'équivalent GNU/Linux serait keepalived (démon VRRP) ou ucarp (implémentation de CARP pour GNU/Linux) et conntrackd (équivalent pfsync). Exemple de mise en pratique : Firewall HA with conntrackd and keepalived.
Voici un schéma de l'infrastructure que nous allons déployer :
Nous utilisons un préfixe d'interconnexion /30 entre FW1 et FW2 pour le trafic pfsync. Le CPE est tout bêtement un PC qui exécute Dynamips. Derrière lui se trouve le réseau des utilisateurs.
Mise en œuvre
Il existe plusieurs manières de faire à chaque étape, plusieurs valeurs sont possibles pour chaque paramètre, ... Référez-vous à la documentation OpenBSD pour plus d'informations.
Installation d'OpenBSD
D'abord, on crée un médium d'installation. Malgré le fait d'avoir suivi plusieurs tutoriels disponibles sur le web (sauf ceux impliquant l'utilisation d'une machine virtuelle et/ou une première installation sur la clé elle-même, manque de temps), nous n'avons pas réussis à obtenir une clé USB bootable d'installation d'OpenBSD. Dans ce cas, il faut récupérer et graver l'ISO du CD d'installation de la dernière version stable d'OpenBSD. À l'heure actuelle, elle est disponible à cette URL : ftp://ftp.fr.openbsd.org/pub/OpenBSD/5.4/amd64/install54.iso.
Ensuite, il faut installer OpenBSD sur FW1 et FW2. On peut aussi effectuer une seule installation puis cloner le disque dur sur la deuxième machine, via le réseau, en utilisant Clonezilla. Ci-dessous, la procédure d'installation d'OpenBSD :
- Il faut aller dans le BIOS pour configurer le boot à partir du CD d'installation. Ce réglage dépend du type de BIOS, de la version, ... Dans notre cas, pour accéder à l'interface de configuration, il faut appuyer sur la touche « Suppr » du clavier au début de la procédure de démarrage du PC. Il faut ensuite se déplacer dans « Advanced BIOS Features » puis positionner la valeur « USB-CDROM » pour le paramètre « First Boot Device ». Il faut vérifier que le paramètre « Second Boot Device » est bien configuré à la valeur « Hard Disk ». Enfin, il faut revenir au menu principal à l'aide de la touche « Echap » et choisir « Save & Exit Setup ». Au reboot automatique, la machine démarrera sur le CD d'installation OpenBSD.
- À l'invite « boot> », il faut appuyer sur la touche « Entrée » du clavier.
- « (I)nstall, (U)pgrade or (S)hell? » : Choisir « Install » en tapant « I » et « Entrée ».
- « Choose your keyboard layout » : taper « fr » et « Entrée ».
- « System hostname? » : taper « FW1 » ou « FW2 » et « Entrée ».
- Configuration réseau :
- « Which one do you wish to configure? » : « done » et « Entrée ».
- « DNS domain name? » : accepter la proposition par défaut en appuyant sur « Entrée ».
- « DNS nameservers? » : accepter la proposition par défaut en appuyant sur « Entrée ».
- « Password for root account? » : taper le mot de passe de votre choix (ici : « toor ») et « Entrée ». « again » : retaper votre mot de passe et « Entrée ».
- « Start sshd by default? » : accepter la proposition par défaut (yes) en appuyant sur « Entrée ».
- « Start ntpd by default? » : accepter la proposition par défaut (no) en appuyant sur « Entrée ». La synchronisation de l'horloge est importante, notamment pour la cohérence des logs mais comme notre maquette n'est pas connectée à Internet, nous ne pouvons accéder à aucun serveur de temps.
- « Do you expect to run the X Window System ? » : « no » et « Entrée ».
- « Setup a user? » : accepter la proposition par défaut (no) en appuyant sur « Entrée ».
- Configuration des disques durs/partitionnement :
- « Which disk is the root disk? » : accepter la proposition par défaut en appuyant sur « Entrée ».
- « Use DUIDs in fstab? » : accepter la proposition par défaut (yes) en appuyant sur « Entrée ».
- « Whole disk or edit the MBR? » : accepter la proposition par défaut (whole) en appuyant sur « Entrée ».
- « (A)uto layout, (E)dit auto layout, or create (C)ustome layout? » : accepter la proposition par défaut (auto layout) en appuyant sur « Entrée ».
- Source de l'installation :
- « Location of sets? » : accepter la proposition par défaut (cd) en appuyant sur « Entrée ».
- « Which one contains the install media? » : accepter la proposition par défaut (cd0) en appuyant sur « Entrée ».
- « Pathname to the sets? » : accepter la proposition par défaut (5.4/amd64) en appuyant sur « Entrée ».
- « Set name(s)? » : accepter la proposition par défaut (done) en appuyant sur « Entrée ».
- L'installation s'effectue ...
- « Location of sets » : nous ne voulons rien installer de plus donc accepter la proposition par défaut (done) en appuyant sur « Entrée ».
- « What timezone are you in? » : taper « Europe/Paris » puis « Entrée ».
- Taper « reboot » puis « Entrée ».
Configuration réseau
Configuration des interfaces réseau de FW1
echo "inet 170.16.3.129 255.255.255.248 NONE" > /etc/hostname.em0 echo "inet 170.16.3.193 255.255.255.192 NONE" > /etc/hostname.em1 echo "inet 192.168.1.1 255.255.255.252 NONE" > /etc/hostname.em2 |
Configuration des interfaces réseau de FW2
echo "inet 170.16.3.130 255.255.255.248 NONE" > /etc/hostname.em0 echo "inet 170.16.3.194 255.255.255.192 NONE" > /etc/hostname.em1 echo "inet 192.168.1.2 255.255.255.252 NONE" > /etc/hostname.em2 |
Configuration de la route par défaut sur FW1 et FW2
On configure une route par défaut via le CPE :
echo "170.16.3.132" > /etc/mygate |
Activation de l'IP forwarding sur FW1 et FW2
On active l'ip forwarding en décommentant la ligne « net.inet.ip.forwarding=1 » dans le fichier /etc/sysctl.conf.
Configuration de l'interface réseau du CPE
conf t int fastEthernet 0/3 ip address 170.16.3.132 255.255.255.248 no sh |
Ajout d'une route sur le CPE
Sur le CPE, on ajoute une route pour joindre le réseau des serveurs (170.16.3.192/26) via les FW
conf t ip route 170.16.3.192 255.255.255.192 170.16.3.131 |
Configuration de l'interface de notre serveur de test
Pour cela, on ajoute les lignes suivantes au fichier /etc/network/interfaces :
iface eth0 inet static address 170.16.3.196 netmask 26 gateway 170.16.3.195 |
CARP
Configuration des paramètres généraux de CARP sur FW1 et FW2
Pour cela, il faut rajouter les lignes suivantes dans le fichier /etc/sysctl.conf :
net.inet.carp.allow=1 net.inet.carp.preempt=1 |
« net.inet.carp.allow=1 » permet d'accepter les paquets du protocole CARP qui arrivent par le réseau.
« net.inet.carp.preempt=1 » permet d'optimiser l'élection du maître dans un groupe de redondance. Cela permet également de basculer toutes les interfaces d'un même groupe de redondance sur un même hôte en même temps.
Configuration des deux interfaces CARP sur FW1
echo "inet 170.16.3.131 255.255.255.248 170.16.3.135 vhid 1 carpdev em0 advskew 1 pass toor" > /etc/hostname.carp0 echo "inet 170.16.3.195 255.255.255.192 170.16.3.255 vhid 2 carpdev em1 advskew 1 pass toor" > /etc/hostname.carp1 |
« vidh X » : Virtual Host ID. C'est un numéro unique par réseau qui permet d'identifier un groupe de redondance CARP sur ce réseau. Les valeurs possibles sont comprises dans l'intervalle [1,255].
« carpdev
« advskew X » permet d'introduire un biais pour forcer le choix lors de l'élection du maître du groupe de redondance. Plus la valeur de ce paramètre est élevée, moindre sont les chances de cet hôte de devenir le maître. Dans notre cas, c'est utile pour que les deux IP virtuelles (une sur le réseau d'interconnexion, l'autre sur le réseau des serveurs) soient attribuées au même hôte.
« pass <mot_de_passe> » est le mot de passe à utiliser lors de la communication avec les autres machines du même groupe de redondance. Évidemment, ce mot de passe doit être identifique sur toutes les machines d'un même groupe de redondance.
Configuration des interfaces CARP sur FW2
echo "inet 170.16.3.131 255.255.255.248 170.16.3.135 vhid 1 carpdev em0 advskew 100 pass toor" > /etc/hostname.carp0 echo "inet 170.16.3.195 255.255.255.192 170.16.3.255 vhid 2 carpdev em1 advskew 100 pass toor" > /etc/hostname.carp1 |
Configuration de Packet Filter
Règles de filtrage
On crée notre propre jeu de règles de filtrage minimaliste puis on l'insère dans le fichier /etc/pf.conf (en supprimant l'existant) de FW1 et FW2 afin qu'il soit appliqué automatiquement à chaque démarrage des deux machines :
# On bloque tout sauf ce qui passe sur la loopback block set skip on lo # CARP pass on { em0 em1 } proto carp keep state # SSH depuis le réseau utilisateur vers les serveurs pass in on em0 inet proto tcp from 170.16.3.0/24 to 170.16.3.196 port 22 keep state # ICMP partout pass inet proto icmp from any to any keep state |
pfsync
Configuration de l'interface pfsync sur FW1
echo "up syncpeer 192.168.1.2 syncdev em2" > /etc/hostname.pfsync0 |
Par défaut, les mises à jour des états se font en multicast. Le paramètre « syncpeer » permet de faire les mises à jour d'état en unicast avec uniquement l'hôte spécifié.
« syncdev
Il faut noter que pfsync est assez gourmand en fonction de l'usage et donc du type de trafic qui passe par le pare-feu redondant, c'est pour cela qu'on conseille un lien réseau dédié à pfsync. Dans l'exemple de l'université de Rennes 1 cité plus haut, ils ont une majorité de trafic web. Rappel : pour une même page web, il faut établir XX connexions pour récupérer le contenu (js (comme jquery) stocké ailleurs, polices stockées ailleurs, pubs, ...). Cela génère des états au niveau des firewall et donc, du trafic pfsync pour échanger ces états. En pointe, ils observent 150 Mbps de trafic sur leur lien dédié pfsync.
Configuration de l'interface pfsync sur FW2
echo "up syncpeer 192.168.1.1 syncdev em2" > /etc/hostname.pfsync0 |
On autorise le protocole pfsync dans Packet Filter, sur FW1 et FW2
Pour cela, on ajoute la règle suivante aux fichiers /etc/pf.conf :
# pfsync pass on em2 proto pfsync keep state |
Valider le bon fonctionnement de notre pare-feu redondant
Il suffit de rebooter toutes les machines (FW1, FW2, serveur de test) pour que la configuration soit appliquée. Ou, de manière plus pragmatique, on peut appliquer les changements à chaud. Sur FW1 et FW2 :
# Recharger le réseau sh /etc/netstart # IP forwarding et CARP sysctl -w net.inet.ip.forwarding=1 sysctl -w net.inet.carp.allow=1 sysctl -w net.inet.carp.preempt=1 # Charger le jeu de règles dans PF et activer PF pfctl -f /etc/pf.conf pfctl -e |
Sur la machine de test :
ifup eth0
|
On peut ensuite vérifier que tout fonctionne comme attendu.
Connectivité
On vérifie que le réseau est fonctionnel en faisant passer un ping depuis une machine de test dans le réseau des utilisateurs vers notre serveur de test :
toto@client: # ping 170.16.3.196 PING 170.16.3.196 (170.16.3.196) 56(84) bytes of data. 64 bytes from 170.16.3.196: icmp_req=1 ttl=63 time=1.99 ms 64 bytes from 170.16.3.196: icmp_req=2 ttl=63 time=1.45 ms 64 bytes from 170.16.3.196: icmp_req=3 ttl=63 time=1.16 ms 64 bytes from 170.16.3.196: icmp_req=4 ttl=63 time=1.45 ms |
CARP
On constate que CARP est fonctionnel en regardant la sortie de l'outil ifconfig.
Sur FW1 :
# ifconfig carp carp0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500 lladdr 00:00:5e:00:01:01 priority: 0 carp: MASTER carpdev em0 vhid 1 advbase 1 advskew 1 groups: carp status: master inet6 fe80::200:5eff:fe00:101%carp0 prefixlen 64 scopeid 0x6 inet 170.16.3.131 netmask 0xfffffff8 broadcast 170.16.3.135 carp1: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500 lladdr 00:00:5e:00:01:02 priority: 0 carp: MASTER carpdev em1 vhid 2 advbase 1 advskew 1 groups: carp status: master inet6 fe80::200:5eff:fe00:102%carp1 prefixlen 64 scopeid 0x7 inet 170.16.3.195 netmask 0xffffffc0 broadcast 170.16.3.255 |
On constate que FW1 est bien le maître des deux groupes de redondances (« carp: MASTER »).
Sur FW2 :
# ifconfig carp carp0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500 lladdr 00:00:5e:00:01:01 priority: 0 carp: BACKUP carpdev em0 vhid 1 advbase 1 advskew 100 groups: carp status: backup inet6 fe80::200:5eff:fe00:101%carp0 prefixlen 64 scopeid 0x6 inet 170.16.3.131 netmask 0xfffffff8 broadcast 170.16.3.135 carp1: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500 lladdr 00:00:5e:00:01:02 priority: 0 carp: BACKUP carpdev em1 vhid 2 advbase 1 advskew 100 groups: carp status: backup inet6 fe80::200:5eff:fe00:102%carp1 prefixlen 64 scopeid 0x7 inet 170.16.3.195 netmask 0xffffffc0 broadcast 170.16.3.255 |
On constate que FW2 est bien en backup sur les deux groupes de redondances (« carp: BACKUP »).
Une capture réseau depuis FW2 nous montre que FW1 est le maître sur l'IP virtuelle 170.16.3.131 et qu'en conséquence, il diffuse des messages « CARP advertisement » à fréquence régulière (ici : 1 seconde, paramétrable en changeant la valeur du paramètre « advbase ») :
# tcpdump -tttttvvni em0 tcpdump: listening on em0, link-type EN10MB 1.019374 carp 170.16.3.129 > 224.0.0.18: CARPv2-advertise 36: vhid=1 advbase=1 advskew=1 demote=0 (DF) [tos 0x10] (ttl 255, id 10529, len 56) 2.040085 carp 170.16.3.129 > 224.0.0.18: CARPv2-advertise 36: vhid=1 advbase=1 advskew=1 demote=0 (DF) [tos 0x10] (ttl 255, id 19703, len 56) 3.060098 carp 170.16.3.129 > 224.0.0.18: CARPv2-advertise 36: vhid=1 advbase=1 advskew=1 demote=0 (DF) [tos 0x10] (ttl 255, id 41787, len 56) 4.080206 carp 170.16.3.129 > 224.0.0.18: CARPv2-advertise 36: vhid=1 advbase=1 advskew=1 demote=0 (DF) [tos 0x10] (ttl 255, id 55471, len 56) |
Si nous coupons l'interface carp0 sur FW1, celui-ci cesse d'émettre, les FW restants émettent des advertisement, une nouvelle élection a lieu entre les FW restants (dans notre cas : uniquement FW2) et FW2 devient le nouveau maître pour l'IP virtuelle 170.16.3.131 :
# tcpdump -tttttvvni em0 tcpdump: listening on em0, link-type EN10MB 5.099795 carp 170.16.3.129 > 224.0.0.18: CARPv2-advertise 36: vhid=1 advbase=1 advskew=1 demote=0 (DF) [tos 0x10] (ttl 255, id 16645, len 56) 6.119458 carp 170.16.3.129 > 224.0.0.18: CARPv2-advertise 36: vhid=1 advbase=1 advskew=1 demote=0 (DF) [tos 0x10] (ttl 255, id 20322, len 56) 7.4294686187 carp 170.16.3.129 > 224.0.0.18: CARPv2-advertise 36: vhid=1 advbase=255 advskew=255 demote=0 (DF) [tos 0x10] (ttl 255, id 33756, len 56) 7.4294688491 carp 170.16.3.130 > 224.0.0.18: CARPv2-advertise 36: vhid=1 advbase=1 advskew=100 demote=0 (DF) [tos 0x10] (ttl 255, id 22655, len 56) 8.129407 carp 170.16.3.130 > 224.0.0.18: CARPv2-advertise 36: vhid=1 advbase=1 advskew=100 demote=0 (DF) [tos 0x10] (ttl 255, id 31522, len 56) 10.4294507802 carp 170.16.3.130 > 224.0.0.18: CARPv2-advertise 36: vhid=1 advbase=1 advskew=100 demote=0 (DF) [tos 0x10] (ttl 255, id 35522, len 56) 11.4294916715 carp 170.16.3.130 > 224.0.0.18: CARPv2-advertise 36: vhid=1 advbase=1 advskew=100 demote=0 (DF) [tos 0x10] (ttl 255, id 35096, len 56) 12.359366 carp 170.16.3.130 > 224.0.0.18: CARPv2-advertise 36: vhid=1 advbase=1 advskew=100 demote=0 (DF) [tos 0x10] (ttl 255, id 63215, len 56) 14.4294736635 carp 170.16.3.130 > 224.0.0.18: CARPv2-advertise 36: vhid=1 advbase=1 advskew=100 demote=0 (DF) [tos 0x10] (ttl 255, id 17132, len 56) 15.179471 carp 170.16.3.130 > 224.0.0.18: CARPv2-advertise 36: vhid=1 advbase=1 advskew=100 demote=0 (DF) [tos 0x10] (ttl 255, id 32836, len 56) |
Les logs (/var/log/messages) de FW2 nous montrent également la transition :
fw2 /bsd: carp0: state transition: BACKUP -> MASTER fw2 /bsd: carp1: state transition: BACKUP -> MASTER |
Quand FW1 est remis en état, il reprend la main et, dans les logs de FW2, nous lisons :
fw2 /bsd: carp1: state transition: MASTER -> BACKUP fw2 /bsd: carp0: state transition: MASTER -> BACKUP |
Pfsync
On vérifie que les interfaces pfsync sont up.
Sur FW1 :
# ifconfig pfsync0 pfsync0: flags=41<UP,RUNNING> mtu 1500 priority: 0 pfsync: syncdev: em2 syncpeer: 192.168.1.2 maxupd: 128 defer: off groups: carp pfsync |
Note : « defer » est un paramètre qui peut être positionné à la valeur « on » pour faire en sorte qu'une connexion n'est réellement acceptée que si le pair pfsync a acquitté la modification de la table des états ou que le délai d'attente pour cet acquittement a expiré. Cela permet une plus grande cohérence entre les pare-feu et est indispensable lorsque plus d'un pare-feu doit s'occuper activement des paquets (typiquement : répartition de la charge).
Sur FW2 :
# ifconfig pfsync0 pfsync0: flags=41<UP,RUNNING> mtu 1500 priority: 0 pfsync: syncdev: em2 syncpeer: 192.168.1.1 maxupd: 128 defer: off groups: carp pfsync |
On constate aussi l'existence d'un trafic réseau pfsync sur le lien d'interconnexion entre les deux pare-feux :
# tcpdump -tttttvvni em2 tcpdump: listening on em2, link-type EN10MB 0.007794 192.168.1.1 > 192.168.1.2: PFSYNCv6 len 276 act UPD ST COMP count 3 ... (DF) [tos 0x10] (ttl 255, id 38708, len 296) 0.410334 192.168.1.2 > 192.168.1.1: PFSYNCv6 len 276 act UPD ST COMP count 3 ... (DF) [tos 0x10] (ttl 255, id 22377, len 296) 0.410597 192.168.1.2 > 192.168.1.1: PFSYNCv6 len 108 act UPD ST COMP count 1 ... (DF) [tos 0x10] (ttl 255, id 51022, len 128) 0.410692 192.168.1.2 > 192.168.1.1: PFSYNCv6 len 108 act UPD ST COMP count 1 ... (DF) [tos 0x10] (ttl 255, id 40898, len 128) 0.410730 192.168.1.1 > 192.168.1.2: PFSYNCv6 len 276 act UPD ST COMP count 3 ... (DF) [tos 0x10] (ttl 255, id 65488, len 296) 0.410774 192.168.1.2 > 192.168.1.1: PFSYNCv6 len 108 act UPD ST COMP count 1 ... (DF) [tos 0x10] (ttl 255, id 24885, len 128) |
Enfin, en établissant une session SSH depuis le réseau des utilisateurs vers notre serveur de test, alors que FW1 est le maître sur les deux interfaces CARP, nous constatons que les tables d'états des deux pare-feux sont synchronisées.
Sur FW1 :
# pfctl -ss all carp 170.16.3.129 -> 224.0.0.18 SINGLE:NO_TRAFFIC all carp 170.16.3.193 -> 224.0.0.18 SINGLE:NO_TRAFFIC all pfsync 192.168.1.1 -> 192.168.1.2 MULTIPLE:MULTIPLE all carp 224.0.0.18 <- 170.16.3.129 NO_TRAFFIC:SINGLE all carp 224.0.0.18 <- 170.16.3.193 NO_TRAFFIC:SINGLE all tcp 170.16.3.196:22 <- 170.16.3.132:33607 ESTABLISHED:ESTABLISHED all tcp 170.16.3.132:33607 -> 170.16.3.196:22 ESTABLISHED:ESTABLISHED |
Sur FW2 :
# pfctl -ss all carp 170.16.3.129 -> 224.0.0.18 SINGLE:NO_TRAFFIC all carp 170.16.3.193 -> 224.0.0.18 SINGLE:NO_TRAFFIC all pfsync 192.168.1.2 <- 192.168.1.1 MULTIPLE:MULTIPLE all carp 224.0.0.18 <- 170.16.3.129 NO_TRAFFIC:SINGLE all carp 224.0.0.18 <- 170.16.3.193 NO_TRAFFIC:SINGLE all tcp 170.16.3.196:22 <- 170.16.3.42:33607 ESTABLISHED:ESTABLISHED all tcp 170.16.3.42:33607 -> 170.16.3.196:22 ESTABLISHED:ESTABLISHED |
Si l'on coupe brutalement les interfaces réseau de FW1 (ou FW1 lui-même), on constate que FW2 prend le relais et que la session SSH n'est pas interrompue car les états des deux pare-feux sont cohérents et synchronisés.
Sources
- La série « Anatomie d’une architecture » chez guiguiabloc et plus particulièrement le 4e volet qui traite de CARP et pfsync.
- Le tutoriel « PF: Haute-disponibilité des pare-feu avec CARP et pfsync » dans la documentation officielle OpenBSD qui permet d'avoir connaissance de tous les paramètres disponibles et de leur signification.
- La documentation officielle de Packet Filter pour créer notre jeu de règles de filtrage.