OpenBSD c’est bien, mangez en, enfin, installez le.
Je serai presque devenu barbu.
Passons aux choses sérieuses:
Les contraintes:
- Passrelle redondante (carp)
- Firewall performant (pf)
- Connexion WAN redondante (ifstated)
- Gestion de VPN (IPSEC et/ou SSL) (racoon, openvpn)
- Alerte par mail en cas de défaillance d’un ISP (postfix)
- Partage de la table d’etat des connexions entre les 2 machines (pfsync)
Nous commençons par l’installation d’OpenBSD sur 2 machines de test (avant mise en prod sur des serveurs dignes de ce nom).
Ces machines sont des dc7700 de chez hp.
Un bug dans la gestion ACPI empeche une installation par défaut d’OpenBSD (comme linux d’ailleurs).
Au boot, nous allons donc désactiver l’acpi
boot -c
>disable acpi
>quit
Nous pouvons installer OpenBSD sans problème …. enfin presque… il est nécessaire de choisir un miroir http ou ftp pour ne pas faire échouer l’installation car le CD-Rom n’est pas très bien pris en charge.
Au reboot, à la fin de l’installation, il ne faut pas oublier de désactiver, à nouveau, l’acpi
Une fois la machine bootée nous modifions le kernel pour que cette modification soit prise en compte lors du boot
# config -e -o bsd.new /bsd
>disable acpi
>quit
#cp bsd.new /bsd && reboot
Il faudra procéder à une installation identique sur la 2eme machine.
Ces 2 machines s’appelleront fw-001 et fw-002
Les adresses ip seront:
fw-001:
192.168.0.192 pour em0
192.168.0.140 pour carp0
212.0.0.3 pour carp1
213.0.0.3 pour carp2
212.0.0.1 pour fxp0 (ISP1)
213.0.0.1 pour ste0 (ISP2)
fw-002:
192.168.0.193 pour em0
192.168.0.140 pour carp0
212.0.0.3 pour carp1
213.0.0.3 pour carp2
212.0.0.2 pour fxp0 (ISP1)
213.0.0.2 pour ste0 (ISP2)
Configurons les interfaces de fw-001:
Contenu de /etc/hostname.carp0
inet 192.168.0.140 255.255.255.0 192.168.0.255 vhid 1 carpdev em0 pass youpilesamis
Contenu de /etc/hostname.carp1
inet 212.0.0.3 255.255.255.0 212.0.0.255 vhid 2 carpdev fxp0 pass youpilesamiswan
Contenu de /etc/hostname.carp2
inet 213..0.0.3 255.255.255.0 213.0.0.255 vhid 3 carpdev ste0 pass youpilesamisnm
Contenu de /etc/hostname.fxp0
inet 212.0.0.1 255.255.255.0 212.0.0.255 description WAN-001
! route add default 212.0.0.254 -mpath
Contenu de /etc/hostname.em0
inet 192.168.0.192 255.255.255.0 192.168.0.255 description LAN-001
Contenu de /etc/hostname.pfsync0
up syncdev ste2
Contenu de /etc/hostname.ste0
inet 213.0.0.1 255.255.255.0 213.0.0.255 description WAN-001
! route add default 213.0.0.254 -mpath
Configurons les interfaces de fw-002:
Contenu de /etc/hostname.carp0
inet 192.168.0.140 255.255.255.0 192.168.0.255 vhid 1 carpdev em0 advskew 100 pass youpilesamis
Contenu de /etc/hostname.carp1
inet 212.0.0.3 255.255.255.0 212.0.0.255 vhid 2 carpdev fxp0 advskew 100 pass youpilesamiswan
Contenu de /etc/hostname.carp2
inet 213..0.0.3 255.255.255.0 213.0.0.255 vhid 3 carpdev ste0 advskew 100 pass youpilesamisnm
Contenu de /etc/hostname.fxp0
inet 212.0.0.2 255.255.255.0 212.0.0.255 description WAN-002
! route add default 212.0.0.254 -mpath
Contenu de /etc/hostname.em0
inet 192.168.0.193 255.255.255.0 192.168.0.255 description LAN-002
Contenu de /etc/hostname.pfsync0
up syncdev ste2
Contenu de /etc/hostname.ste0
inet 213.0.0.2 255.255.255.0 213.0.0.255 description WAN-002
! route add default 213.0.0.254 -mpath
Note: Il est imperatif de laisser /etc/mygate vide afin de ne pas avoir une seule et unique route vers le WAN.
Il est temps de lancer les connexions réseau:
#sh /etc/netstart
Nous pouvons pinguer l’exterieur, mais les machines de l’exterieur ne peuvent pas pinguer notre passerelle de manière fiable (probleme de reverse path).
Nous allons donc créer une conf pf afin de regler ce problème:
#Variables
#192.168.0.1 -> 254
lan_net = "192.168.0.0/24"
#Interfaces LAN + 2WAN
int_if = "em0"
ext_if1 = "fxp0"
ext_if2 = "ste0"
#Gateway wan 1
ext_gw1 = "212.0.0.254"
#Interface de synchro carp
sync_carp = "ste2"
#Loopback
loopback_if = "lo0"
#Adresses carp (flottantes)
ext_carp1 = "212.0.0.3"
ext_carp2 = "213.0.0.3"
ext_gw2 = "213.0.0.254"
admin_net = "{ VOS IP DES MACHINES POUVANT FAIRE DU SSH }"
admin_ports = "{ 22, 1022 }"
#DNS de mon LAN
dns_servers = "{ 192.168.0.1/32, 192.168.0.2/31 }"
#Ne rien filtere ni sur lo0 ni sur l'interface de synchro (cable croisé)
set skip on {$loopback_if, $sync_carp}
#On normalise les paquets entrants par le WAN (1+2)
scrub log on {$ext_if1, $ext_if2} all random-id min-ttl 254 max-mss 1452 reassemble tcp fragment reassemble
#On autorise les machines du LAN à sortir sur internet en NAT (Attention cette pratique est déconseillée pour des machines Windows)
nat on $ext_if1 from $lan_net to any -> $ext_carp1
nat on $ext_if2 from $lan_net to any -> $ext_carp2
#Policy par défaut
#On bloque tout ce qui n'a pas été autorisé
block in log from any to any
block out log from any to any
#On autorise pfsync et carp à communiquer sur les interfaces voulues
pass quick on { $sync_carp } proto pfsync keep state (no-sync)
pass on { $ext_if1 $ext_if2 $int_if } proto carp keep state
#Pour transmettre les paquets de la passerelle au LAN
pass out on $int_if from any to $lan_net
#Paquets pour la passerelle
pass in quick on $int_if from $lan_net to $int_if
#Sortie sur wan1, puis wan2, puis wan1, ...
#NAT -> Sortie
# en TCP
pass in on $int_if route-to \
{ ($ext_if1 $ext_gw1), ($ext_if2 $ext_gw2) } round-robin \
proto tcp from $lan_net to any flags S/SA modulate state
# en UDP + ICMP
pass in on $int_if route-to \
{ ($ext_if1 $ext_gw1), ($ext_if2 $ext_gw2) } round-robin \
proto { udp, icmp } from $lan_net to any keep state
# On autorise les requetes DNS et les connexions de la passerelle vers le LAN
pass out quick on $int_if inet proto { tcp, udp } to $dns_servers port domain keep state
pass out quick on $int_if inet proto tcp to $lan_net port ssh keep state
# Permet de pinguer la passerelle de l'exterieur sur ses 2 interfaces et avoir un chemin de retour cohérent
pass in on $ext_if1 reply-to ($ext_if1 $ext_gw1) inet proto icmp icmp-type {echoreq, echorep} keep state
pass in on $ext_if2 reply-to ($ext_if2 $ext_gw2) inet proto icmp icmp-type {echoreq, echorep} keep state
#Administration distante (SSH)
pass in on $ext_if1 reply-to ($ext_if1 $ext_gw1) inet proto tcp from $admin_net port $admin_ports keep state
pass in on $ext_if2 reply-to ($ext_if2 $ext_gw2) inet proto tcp from $admin_net port $admin_ports keep state
# Regles de sortie de la passerelle
pass out on $ext_if1 proto icmp keep state
pass out on $ext_if2 proto icmp keep state
pass out on $ext_if1 proto {tcp, udp} keep state
pass out on $ext_if2 proto {tcp, udp} keep state
Une fois ce fichier créé, il faut activer pf:
#pfctl -f /etc/pf.conf && pfctl -e
Il faudra répliquer ces opération sur la 2eme machine.
Il est important de modifier certaines valeurs de /etc/sysctl.conf
net.inet.ip.forwarding=1
net.inet.carp.allow=1 # Allow the firewall to accept CARP packets
net.inet.ip.multipath=1 # MultiPath
net.inet.carp.preempt=1 # 1=Enable carp(4) preemption
…et /etc/rc.conf.local
netd=NO
pf=YES
pflog_enable=YES
Une fois ces opérations faites et les machines rebootées, tout doit fonctionner.
C’est bien beau tout ça, mais si une connexion WAN “tombe” nous routons toujours en round robin vers les 2 connexions.
Il faut donc détecter cette défaillance.
Nous utiliserons pour cela le demon ifstated
Contenu de /etc/ifstated.conf
ext1_connectivity = '( "ping -q -c 1 -w 1 myexternal_host > /dev/null" every 3)'
ext2_connectivity = '( "ping -q -c 1 -w 1 my2ndexternal_host > /dev/null" every 3)'
state ext1ok_ext2ok {
init {
run "logger C1OK C2OK"
run "route delete default 212.0.0.254 -mpath"
run "route delete default 213.0.0.254 -mpath"
run "route add default 212.0.0.254 -mpath"
run "route add default 213.0.0.254 -mpath"
run "cd /etc/pf && ln -fs pf.conf_ok_ok pf_state.conf"
run "cd /etc/pf && ln -fs pf_nat_state.conf_ok_ok pf_nat_state.conf"
run "pfctl -f /etc/pf.conf"
}
if $ext1_connectivity && ! $ext2_connectivity {
set-state ext1ok_ext2nok
}
if ! $ext1_connectivity && $ext2_connectivity {
set-state ext1nok_ext2ok
}
if ! $ext1_connectivity && ! $ext2_connectivity {
set-state ext1nok_ext2nok
}
}
state ext1ok_ext2nok {
init {
run "logger C OK -- C N-OK"
run "route delete default 212.0.0.254 -mpath"
run "route delete default 213.0.0.254 -mpath"
run "route add default 212.0.0.254 -mpath"
run "cd /etc/pf && ln -fs pf.conf_ok_nok pf_state.conf"
run "cd /etc/pf && ln -fs pf_nat_state.conf_ok_nok pf_nat_state.conf"
run "pfctl -f /etc/pf.conf"
}
if $ext1_connectivity && $ext2_connectivity {
set-state ext1ok_ext2ok
}
if ! $ext1_connectivity && $ext2_connectivity {
set-state ext1nok_ext2ok
}
if ! $ext1_connectivity && ! $ext2_connectivity {
set-state ext1nok_ext2nok
}
}
state ext1nok_ext2ok {
init {
run "logger Completel C NOK -- C OK"
run "route delete default 212.0.0.254 -mpath"
run "route delete default 213.0.0.254 -mpath"
run "route add default 213.0.0.254 -mpath"
run "cd /etc/pf && ln -fs pf.conf_nok_ok pf_state.conf"
run "cd /etc/pf && ln -fs pf_nat_state.conf_nok_ok pf_nat_state.conf"
run "pfctl -f /etc/pf.conf"
}
if $ext1_connectivity && $ext2_connectivity {
set-state ext1ok_ext2ok
}
if $ext1_connectivity && ! $ext2_connectivity {
set-state ext1ok_ext2nok
}
if ! $ext1_connectivity && ! $ext2_connectivity {
set-state ext1nok_ext2nok
}
}
state ext1nok_ext2nok {
init {
run "logger N-OK -- N-OK"
run "route delete default 212.0.0.254 -mpath"
run "route delete default 213.0.0.254 -mpath"
run "route add default 212.0.0.254 -mpath"
run "route add default 213.0.0.254 -mpath"
run "cd /etc/pf && ln -fs pf.conf_nok_nok pf_state.conf"
run "cd /etc/pf && ln -fs pf_nat_state.conf_nok_nok pf_nat_state.conf"
run "pfctl -f /etc/pf.conf"
}
if $ext1_connectivity && $ext2_connectivity{
set-state ext1ok_ext2ok
}
if $ext1_connectivity && ! $ext2_connectivity {
set-state ext1ok_ext2nok
}
if ! $ext1_connectivity && $ext2_connectivity {
set-state ext1nok_ext2ok
}
}
Les 4 blocs state ext… correspondent aux 4 états possibles des 2 connexions:
- Up + Up
- Up + Down
- Down + Up
- Down + Down
Nous avons donc maintenant une passerelle redondante faisant de la NAT du CARP, du PFSYNC (synchronisation des tables du firewall).
Reste à ajouter les VPN, un proxy pour les postes du LAN