Comment mettre en place un vpn redondant sur site distant dont les clients doivent avoir une adresse IP VPN fixe ?


Voila un challenge qu'il m'a été demandé de réaliser et le tout évidemment à moindre coût.

Ce genre de demande est assez singulier, mais peut-être utile lorsqu'il faut récupérer des données sur des appareils connectés en 3G ou adsl (IP dynamique).

 

1) Introduction - Le réseau actuel :

 

Une petit image valant mieux qu'un grand discours :

 

Résumé :

 Réseau 1 : 192.168.1.0/24

 Réseau 2 : 192.168.100.0/24

 Réseau de liaison réseau 1 - réseau 2 : 192.168.2.0/24

 Serveur de VPN dans le réseau 1 : 192.168.1.50

 Serveur de VPN dans le réseau 2 : 192.168.100.50

 Clients VPN dans le réseau 10.10.0.0/24

 

2) Présentation des outils utilisés et de la conception théorique du projet :

Outils :

- Deux serveur debian 7 ( passé en instable / jessie ). Depuis je suis passé sur Ubuntu car celui-ci fournit des versions plus récentes des programmes utilisés ( corosync et pacemaker )

- Openvpn : Je ne vous le présente plus. Il sera utilisé ici pour créer un vpn en mode routé.

- Quagga : Derrière ce nom bizarre se cache l'implémentation sous Linux des protocoles de routing tels que rip,ospf,bgp.

- Pacemaker/corosync : Il s'agit d'une suite qui implémente le clustering et la HA sous Linux.

- Une bonne base en administration Linux et réseau.

 

Méthodologie :

Comment tout ça va fonctionner ensemble ?

"Facile", Openvpn sera démarré sur un des serveurs.

Quagga s'occupera du routage en OSPF entre les routeurs et les deux serveur VPN.

Et finalement, Pacemaker/Corosync s'occupera de gérer le lancement d'openvpn sur les serveurs et de démarrer le vpn sur le deuxième serveur en cas de problème au niveau du premier serveur (rupture de connexion, plantage du serveur, etc.)

Ça parait simple comme-ça. Passons donc à la pratique.

 

3) Openvpn

A) Installation et génération des clés

Connectez vous en root sur votre premier serveur :

apt-get install openvpncd

/usr/share/doc/openvpn/examples/easy-rsa/2.0/

Editez le fichier vars pour le personnaliser selon votre organisation et appliquez-le  :

nano varssource

./vars

Générer les clés  :

./build-ca

./build-dh

./build-key-server srv1

./build-key client1

./build-key client2

Adaptez les nom srv1 et client1 pour refléter votre organisation et générez une clé par client VPN.

Copiez les clés générées dans le dossier d'openvpn :

mkdir /etc/openvpn/keys

cp keys/* /etc/openvpn/keys/

 

B) Fichier de configuration :

Serveurs :

port 1194
proto udp
dev tun
ca keys/ca.crt
cert keys/srv1.crt
key keys/srv1.key  # This file should be kept secret
dh keys/dh1024.pem
server 10.10.0.0 255.255.255.0
topology subnet
push "route 192.168.0.0 255.255.0.0"
client-config-dir ccd
client-to-client
keepalive 10 120
comp-lzo
persist-key
persist-tun
status openvpn-status.log
verb 3

Clients :

client
dev tun
proto udp
remote adresse-externe-srv1 1194
remote adresse-externe-srv2 1194
resolv-retry infinite
nobind
persist-key
persist-tun
ca keys/ca.crt
cert keys/Client1.crt
key keys/Client1.key
comp-lzo
verb 3
keepalive 10 120

Il s'agit d'une configuration assez classique.

Créez le dossier ccd avec un fichier par clients pour leur assigner leur adresse IP :

cd /etc/openvpn/

mkdir ccd

nano ccd/Client1

Le nom du fichier doit être le nom donné au certificat.

Contenu du fichier :

ifconfig-push 10.10.0.11 255.255.255.0

Voila donc notre VPN configuré sur un serveur.

Copiez la configuration à l'identique sur le deuxième serveur ( Faites une archive du dossier /etc/openvpn et transférer la sur le deuxième serveur par scp ).

4) Quagga

1) Installation :

Installez quagga à l'aide d'apt :

apt-get install quagga

Quagga est un paquet qui regroupe plusieurs petits daemons qui permettent d'émuler un routeur.

Ils se configurent avec un syntaxe semblable aux routeurs cisco. Mais chaque daemon se configure séparément !

Ils sont accessible en telnet sur le localhost !

2) Configuration :

La première chose a faire est d'activer les daemons utiles :

nano /etc/quagga/daemons

Mettre yes à zebbra et ospfd

Ici deux solutions s'adressent à vous : configurer en mode console, ou adapter les config ci-dessous et relancer quagga.

Le mode console s'accède en telnet ex : telnet localhost zebra pour zebra et telnet localhost ospfd pour ospf

Config Zebra : zebra.conf

! -*- zebra -*-
!
! zebra sample configuration file
!
! $Id: zebra.conf.sample,v 1.1 2002/12/13 20:15:30 paul Exp $
!
hostname SRV1
password unmotsdepasse
enable password unmotsdepasse
!
! Interface's description.
!
!interface lo
! description test of desc.
!
!interface sit0
! multicast

!
! Static default route sample.
!
!ip route 0.0.0.0/0 203.181.89.241
!

!log file /var/log/quagga/zebra.log


Zebra doit être configuré un minimum car c'est lui qui dirige les autres daemons.

Config Ospfd : ospfd.conf

!
! Zebra configuration saved from vty
!   2013/09/30 15:32:06
!
hostname SRV1
password unmotsdepasse
enable password unmotsdepasse
log stdout
!
!
!
interface eth0
 ip ospf authentication message-digest
 ip ospf message-digest-key 1 md5 clé-md5-en-clair
!
interface eth1
!
interface lo
!
interface tun0
!
router ospf
 redistribute connected
 network 10.10.0.0/24 area 0.0.0.0
 network 192.168.1.0/24 area 0.0.0.0
 area 0.0.0.0 authentication message-digest
 neighbor ip-router1
!
line vty
!

Le but de cet article n'étant pas d'expliquer le fonctionnement d'ospf et sa configuration dans les divers équipement réseaux existant, je vous laisse chercher sur le net pour de plus amples informations.

La même configuration doit être faite sur le deuxième serveur en adaptant le commande "network".

Vous devez également configurer les différents routeurs de vos réseaux pour correspondre à cette configuration.

En effet ospf doit être configuré au minimum sur les routeurs entre les deux serveurs.

Redémarrer le service quagga pour être sur que vos changement aient été pris en considération :

/etc/init.d/quagga restart

 

3) Les test :

Comme premier test, lancez le VPN sur le srv1.

Vous devez voir en quelques secondes une route vers ce serveur pour le réseau 10.10.0.0/24 apparaitre dans les différent routeurs où vous avez configuré l'ospf.

Maintenant coupez openvpn sur ce serveur et démarrez le sur l'autre. La route devrait se mettre à jour et rediriger vers l'autre serveur maintenant.

 

Si tout est bon, refaites le même test mais avec un client connecté.

Si vous rencontrez des problème de communication au niveau du client malgré qu'il soit bien connecté, vérifiez que vos router ne fasse pas du filtrage de session tcp.

En effet, comme le schéma ci dessous le montre, un paquet tcp partant du réseau interne va passer par la gateway sans retourner par celle-ci au retour. Du coup, si la gateway filtre les session, elle va trouver la situation anormale et couper la session.

Schéma :

 

 

5) Pacemaker/Corosync :

1) Introduction :

Pacemaker et Corosync permettent de contrôler et coordonner des ressources sur différents serveurs.

Corosync se charge de la communication entre les serveurs.

Pacemaker se charge de décider sur quel serveur est démarré une ressource configurée.

 

2) Notes techniques :

J'ai du passer mes serveurs Debian en Jessie suite a des problèmes de désynchronisations inexpliquées entre mes serveurs qui aboutissait à un démarrage d'openvpn sur les deux serveurs en simultanés.

Depuis je n'ai plus de problème, mais c'est à confirmer.

Il faut noter également que la suite Pacemaker/Corosync permet de monter un vrai cluster qui switch en une seconde une ressource d'un serveur à l'autre, de couper une serveur qui cause problème avec un système d'élection, etc.

Dans notre projet, nous allons simplifier cette utilisation à vérifier l'état d'openvpn et l'état de la connexion.

Je pense que ça couvre 99% de cas rencontré lors de l'utilisation d'openvpn.

 

3) Installation :

Installation des paquets :

apt-get install corosync pacemaker

 

4) Configuration de corosync :

Corosync a été conçu à la base pour fonctionner en multicast. Hors en site distant dans deux réseaux différents, cette configuration serait impossible sans artifice.

Heureusement pour nous, une version en udp a été implémentée.

Il est aussi important d'assigner en dur dans le fichier hosts les nom des machines sur les deux serveurs car Corosync et Pacemaker utilisent ces noms pour reconnaitre les serveurs (résultat de la commande uname -n) :

Fichier /etc/hosts :

Adresse-Ip-Srv1            Srv1
Adresse-Ip-Srv2            Srv2

La configuration est assez simple : Il faut déclarer les serveurs et le fait que nous allons utiliser Pacemaker.

Fichier /etc/corosync/corosync.conf

compatibility: whitetank
totem {
        version: 2
        # How long before declaring a token lost (ms)
        token: 3000
        # How many token retransmits before forming a new configuration
        token_retransmits_before_loss_const: 10
        # How long to wait for join messages in the membership protocol (ms)
        join: 240
        # How long to wait for consensus to be achieved before starting a new round of membership configuration (ms)
        consensus: 3600
        # Turn off the virtual synchrony filter
        vsftype: none
        # Number of messages that may be sent by one processor on receipt of the token
        max_messages: 20
        # Limit generated nodeids to 31-bits (positive signed integers)
        clear_node_high_bit: yes
        # Disable encryption
        secauth: off
        # How many threads to use for encryption/decryption
        threads: 0
        # Optionally assign a fixed node id (integer)
        nodeid: 1111
        # This specifies the mode of redundant ring, which may be none, active, or passive.
        rrp_mode: none
        interface {
                member {
                        memberaddr: Adresse Ip Serveur 1
                }
                member {
                        memberaddr: Adresse Ip Serveur 2
                }
        # The following values need to be set based on your environment
                ringnumber: 0
                bindnetaddr: Adresse Ip Serveur 1
                mcastport: 5405
        }
        transport: udpu
}

amf {
        mode: disabled
}

service {
        # Load the Pacemaker Cluster Resource Manager
        ver:       0
        name:      pacemaker
}

aisexec {
        user:   root
        group:  root
}

logging {
        fileline: off
        to_stderr: yes
        to_logfile: yes
        logfile: /var/log/corosync/corosync.log
        to_syslog: yes
        syslog_facility: daemon

        debug: off
        timestamp: on
        logger_subsys {
                subsys: AMF
                debug: off
                tags: enter|leave|trace1|trace2|trace3|trace4|trace6
        }
}


Pour le deuxième serveur, il suffit de changer les adresses et le nodeid (en rouge).

Une fois le fichier de configuration prêt, relancer le service sur les deux serveurs :

/etc/init.d/corosync restart

5) Configuration de Pacemaker :

Il faut commencer par démarrer le service car la configuration s'effectue avec l'outil crm.

Pacemaker se charge de répliquer la configuration sur les serveurs.

/etc/init.d/pacemaker start

Il faut commencer par désactiver les options de clustering :

crm configure property stonith-enabled=false

crm configure property no-quorum-policy=ignore

Il faut ensuite configurer les ressources que nous allons utiliser :

Openvpn et un ping vers des serveur distant, ce qui va permettre de tester l'état de la connexion :

Définition de la ressource openvpn :

crm configure primitive openvpn lsb:openvpn op monitor interval="30s"

Définition de la ressource ping :

crm configure primitive p_ping ocf:pacemaker:ping \
        params host_list="8.8.8.8 4.2.2.2" multiplier="100" dampen="5s" \
        op monitor interval="60" timeout="60" \
        op start interval="0" timeout="60" \
        op stop interval="0" timeout="60"
crm configure clone c_ping p_ping

Vous pouvez évidement adaptez les cible du ping.

Le multiplier est utilisé pour donner un poids décisionnel à la ressource.

La commande clone permet de répliquer cette ressource sur les serveurs. En effet, le ping doit tourner en simultané sur les deux serveur pour éviter que le ressource migre vers un serveur hors connexion.

Nous allons ensuite obliger Pacemaker a démarrer openvpn sur un serveur ou le ping est bon.

crm configure location OpenVpnCluster openvpn \
        rule $id="OpenVpnCluster-rule" -inf: not_defined pingd or pingd lte 0

Si vous voulez fixer openvpn sur un serveur préféré :

crm configure location PrefVpnAir openvpn \
        rule $id="PrefVpnAir-rule" 50: #uname eq Srv1

Avec cette commande openvpn sera démarré sur le Srv1 si le ping est bon sur celui-ci. Si le ping tombe, openvpn est démarré sur Srv2. Une fois la situation rentrée dans l'ordre openvpn revient sur Srv1.

Pour éviter les cas de "split brain", il faut mettre en place un système de stonith. Ici j'utilise le système par ssh qui n'est pas recommandé mais suffit pour 99% des cas ou le split brain intervient lors d'une coupure de connexion.

primitive st-ssh stonith:external/ssh \
        params hostlist="vpn-air col-air-vpn"

Il faut avoir echangé les clés ssh entre les deux serveurs pour que ça fonctionne.

 

Voici notre configuration simplifiée terminée. Pour de plus amples information sur Pacemaker et sa configuration, je vous renvoie vers la doc officielle.

6) Vérification :

La commande crm_mon permet de contrôler l'état des ressources et de Pacemaker. ex:

============
Last updated: Tue Nov 26 18:31:39 2013
Last change: Thu Nov 21 09:58:59 2013 via crmd on Srv1
Stack: openais
Current DC: Srv1 - partition with quorum
Version: 1.1.7-ee0730e13d124c3d58f00016c3376a1de5323cff
2 Nodes configured, 2 expected votes
3 Resources configured.
============

Online: [ Srv1 Srv2 ]

 Clone Set: c_ping [p_ping]
     Started: [ Srv1 Srv2 ]
openvpn (lsb:openvpn):  Started Srv1

Redémarrer le Srv1 et regarder celui-ci passer offline et openvpn démarrer sur Srv2.

7) Conclusion

Voici la fin du tutoriel.

En théorie votre VPN redondant devrait être pleinement fonctionnel.

J'espère avoir été assez clair et concis.

Je suis évidemment ouvert à toutes vos remarques, suggestions, questions.

Console de débogage Joomla!

Session

Profil d'information

Occupation de la mémoire

Requêtes de base de données