lalahop

VPN unipersonnel avec une IP failover en sortie sur un dédié OVH

L'idée du jour est d'utiliser un serveur dédié chez OVH, qui sert déjà à autre chose, pour se monter un petit VPN sans prétention. Quand je dis sans prétention c'est que je prévois ça pour un usage personnel (unipersonnel) et que je ne destine pas ce VPN à l'échange de flux hautement confidentiels (sinon ça ne finirait pas chez OVH ...). Donc si vous cherchez une config blindée haute sécurité, ce n'est pas le bon billet, désolé.

Le but de ce VPN est de me permettre d'être sur Internet quand je veux faire des tests ou autre (exemple parmi d'autres : nmap mon serveur pour vérifier qu'il n'y a rien de plus qui est ouvert sur l'extérieur que ce que je veux). Quand je dis « être sur Internet », je veux dire : être capable d'émettre et de recevoir tous les contenus et toutes les applications de mon choix sans aucune discrimination ... Ho ! La définition de la neutralité du net ! Donc éviter un filtrage de ports à la con, éviter un filtrage du type "ne peut entrer sur le réseau que ce qui fait suite à une demande de l'intérieur" (en gros : impossible d'héberger des services). C'est rageant d'être perturbé par notre FAI (Fournisseur d'Accès à son Intranet dans le cas présent) quand on veut observer quelque chose ou monter un service.

Attention toutefois : le tunnel sort chez OVH et il faut savoir qu'OVH n'a pas un impératif de neutralité. Des usages y sont clairement interdits ou soumis à autorisation préalable comme, par exemple mais pas seulement, héberger un proxy ou un nœud TOR ou utiliser des logiciels de P2P. OVH duplique aussi tous les mails sortants pour analyse temps-réel anti-spam ... Donc si vous cherchez un vrai accès à Internet, même grâce à un VPN, je vous conseille plutôt les FAI associatifs de la Fédération FDN qui offrent une telle garantie par design, sans fluctuation ni d'exceptions.

En supplément, "depuis Internet", je souhaite que mon client VPN soit vu avec une IP distincte de celle attribuée à mon dédié. Il faut donc utiliser une IP failover et faire en sorte que le trafic sorte et entre de notre dédié par cette IP.

Table des matières

Sources

Je clos le suspens de suite : ce billet est une arnaque ! On trouve les morceaux de config OpenVPN à peu près partout : OpenVPN sur le Wiki Debian.org, le man d'OpenVPN est bien fait et le petit morceau de conf pour sortir du VPN avec une IP failover est aussi documenté un peu partout : Utiliser un VPN avec une IP failover chez kdecherf (git)-[blog] %. Pour ceux qui cherchent comment monter un serveur VPN sur leur dédié OVH sans utiliser une IP failover : il suffit de faire un SNAT sur l'IP principale du serveur ou, au pire, un masquerade sur ce qui sort par eth0.

Néanmoins, parce que je vous aime bien, je vais vous donner ma config.

Trêve de blabla, on commence !

Au niveau d'OVH, c'est très simple : il suffit de commander une IP failover, de la payer et d'attendre un peu qu'elle soit active. Rien de plus. Pas besoin de définir une MAC virtuelle, rien.

Point to point et chiffrement symétrique

Dans un premier temps, on va utiliser une topologie point à point avec un chiffrement symétrique.

On installe OpenVPN sur le serveur et sur le client :

apt-get install openvpn

Pour l'instant, je ne veux pas qu'OpenVPN démarre tout seul au boot donc je lance la commande suivante sur le client et sur le serveur :

update-rc.d -f openvpn remove

On crée la config côté serveur (dans /etc/openvpn/server.conf par exemple) :

proto udp
port 1194
dev tun
 
mode p2p
 
cipher AES-256-CBC
secret /etc/openvpn/vpn-static.key
 
comp-lzo
 
verb 3
 
persist-key
persist-tun
ping 30
ping-exit 90
 
user openvpn
group openvpn
 
ifconfig 198.18.0.1 198.18.0.2
script-security 2
up /etc/openvpn/up.sh
plugin /usr/lib/openvpn/openvpn-down-root.so /etc/openvpn/down.sh

Quelques remarques :

  • Pour le choix tun/tap (route/bridge) : comme je n'ai pas besoin des fonctionnalités des tap (broadcast, donc possibilité d'utiliser NetBios/SMB, possibilité d'utiliser d'autres protocoles de couches 3, ... voir : What is the difference between bridging and routing? sur OpenVPN.net et Bridging vs. routing sur OpenVPN community), j'ai choisi le mode router/tun pour profiter de l'avantage d'avoir moins d'overhead.
  • Pour l'adressage du serveur et du client, j'ai pris le bloc 198.18.0.0/30 qui est englobé dans 198.18.0.0/15 qui est un préfixe réservé à l'IANA pour les tests et qui n'est donc pas annoncé globalement. L'idée est d'éviter une éventuelle collision. Comme ce préfixe est méconnu et que les réseaux auxquels je me connecte sont adressés soit en public soit avec les préfixes du RFC 1918, je suis sûr d'être tranquille. Notez qu'il serait peut-être plus pertinent de prendre un préfixe /30 dans 10.0.0.0/8. La probabilité de se connecter à un réseau existant utilisant ce bloc me paraît faible.
  • « plugin /usr/lib/openvpn/openvpn-down-root.so » permet de lancer le script de fin avec les droits root alors même qu'OpenVPN a, comme on le lui a demandé, perdu, dès la fin de l'initialisation, les droits root pour ceux de l'utilisateur openvpn et du groupe openvpn.

On crée la config côté client (dans /etc/openvpn/client.conf, par exemple) :

proto udp
remote <IP PRINCIPALE DU SERVEUR> 1194
dev tun
 
cipher AES-256-CBC
secret /etc/openvpn/vpn-static.key
 
comp-lzo
 
verb 3
 
persist-key
persist-tun
ping 30
ping-exit 90
explicit-exit-notify
 
user openvpn
group openvpn
 
ifconfig 198.18.0.2 198.18.0.1
route-gateway 198.18.0.1
redirect-gateway def1

Sur le serveur, on crée les deux scripts. D'abord /etc/openvpn/up.sh :

#!/bin/bash
 
ifconfig br0:1 <IP FAILOVER> netmask 255.255.255.255 broadcast <IP FAILOVER>
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A POSTROUTING -s 198.18.0.0/30 ! -d 198.18.0.0/30 -j SNAT --to-source <IP FAILOVER>
iptables -t nat -A PREROUTING -d <IP FAILOVER> -j DNAT --to-destination 198.18.0.2

Puis le script /etc/openvpn/down.sh :

#!/bin/bash
 
echo 0 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -D POSTROUTING -s 198.18.0.0/30 ! -d 198.18.0.0/30 -j SNAT --to-source <IP FAILOVER>
iptables -t nat -D PREROUTING -d <IP FAILOVER> -j DNAT --to-destination 198.18.0.2
ifconfig br0:1 down

Quelques remarques :

  • J'ai configuré l'alias sur br0 car j'utilise un bridge pour attribuer des IP failover à mes conteneurs LXC (voir Utiliser LXC sur un Kimsufi). Si vous n'avez pas de VM ni de conteneurs LXC ou autre montage du même type, alors il faudra faire l'alias sur eth0.
  • Mapper 198.18.0.2 à l'IP failover suffit amplement. Néanmoins, j'ai voulu jouer la prudence au cas où le serveur émettrait avec 198.18.0.1 car je ne suis pas sur mon réseau mais sur celui d'OVH. Ce scénario ne devrait jamais se produire mais bon ... Au moins comme ça, ça sortira avec l'IP failover. Si je ne vois rien passer, OVH m'indiquera un problème avec cette IP et je saurai alors que le problème vient du VPN sans passer 5h à essayer de comprendre. Indiquer un /30 est par facilité : on pourrait utiliser les ip set pour indiquer les 2 adresses IP précises.
  • Le DNAT n'est clairement pas obligatoire. C'est pour le fun ... Si l'on veut héberger des services derrière ce VPN ...
  • Pour ceux qui cherchent comment monter un serveur VPN sur leur dédié OVH sans utiliser une IP failover, seule la première règle iptables change :
    iptables -t nat -D POSTROUTING -s 198.18.0.0/30 ! -d 198.18.0.0/30 -j SNAT --to-source <IP PRINCIPALE DU SERVEUR>

    Forcement, vous ne pouvez alors pas faire de DNAT complet mais uniquement pour certains ports que vous voulez rediriger vers votre client VPN.

  • Enfin, selon votre configuration, il faudra autoriser le transfert de paquet depuis/vers le VPN. Cela se fait dans chaîne FORWARD. 😉

On rend ces scripts exécutables :

chmod u+x /etc/openvpn/up.sh /etc/openvpn/down.sh

On crée l'utilisateur openvpn :

adduser openvpn --disabled-login --no-create-home --shell /bin/false

Sur le serveur ou sur le client, on génère la clé cryptographique :

openvpn --genkey --secret /etc/openvpn/vpn-static.key

Il faudra la transférer à l'autre partie via scp puis vérifier les droits : root:root 400.

Enfin, selon votre configuration, il faudra autoriser OpenVPN dans votre firewall, en entrée et en sortie. Aussi bien sur le client que sur le serveur.

Il est l'heure de tester (sur le client et le serveur) :

service openvpn restart

Normalement, le client doit pouvoir pinguer 198.18.0.1 et sortir sur Internet par le VPN. L'adresse IP "vue depuis Internet" doit être l'IP failover.

Pour ceux que ça intéresse, voici les configurations équivalentes mais en utilisant des tap. Pour le serveur :

proto udp
port 1194
dev tap
 
cipher AES-256-CBC
secret /etc/openvpn/vpn-static.key
 
comp-lzo
 
verb 3

persist-key
persist-tun
ping 30
ping-exit 90
 
user openvpn
group openvpn
 
ifconfig 198.18.0.1 255.255.255.252
script-security 2
up /etc/openvpn/up.sh
plugin /usr/lib/openvpn/openvpn-down-root.so "/etc/openvpn/down.sh"

Pour le client :

proto udp
remote <IP PRINCIPALE DU SERVEUR> 1194
dev tap
 
cipher AES-256-CBC
secret /etc/openvpn/vpn-static.key
 
comp-lzo
 
verb 3
 
persist-key
persist-tun
ping 30
ping-exit 90
explicit-exit-notify
 
user openvpn
group openvpn
 
ifconfig 198.18.0.2 255.255.255.252
route-gateway 198.18.0.1
redirect-gateway def1

Point to point et chiffrement asymétrique

L'inconvénient principal du chiffrement symétrique est qu'il ne permet pas le perfect forward secrecy. Bien que, comme je l'ai déjà dit, mon VPN me servira principalement à faire des tests et ne transmettra pas mes secrets les plus noirs, je me dis qu'il peut être intéressant de faire une topologie p2p avec du chiffrement asymétrique, for ze fun.

Attention à ne pas mal interpréter mes propos : le chiffrement du tunnel reste symétrique. Simplement, lors de l'initialisation, le client et le serveur échangent une clé temporaire pour réaliser le chiffrement symétrique du tunnel. C'est cet échange initial qui se fait en utilisant la cryptographie asymétrique.

Pour cette partie, on va suivre d'encore plus près le tutoriel du wiki Debian.org. Reportez-vous à la partie « TLS-enabled VPN ». La génération du matériel cryptographique est identique : seules les configurations d'OpenVPN sont différentes.

Voici la configuration du serveur :

proto udp
port 1194
dev tun
 
mode p2p
tls-server
 
ca      /etc/openvpn/easy-rsa/keys/ca.crt
cert    /etc/openvpn/easy-rsa/keys/server.crt
key     /etc/openvpn/easy-rsa/keys/server.key
dh      /etc/openvpn/easy-rsa/keys/dh1024.pem
 
comp-lzo
 
verb 3
 
persist-key
persist-tun
ping 30
ping-exit 90
 
user openvpn
group openvpn
 
ifconfig 198.18.0.1 198.18.0.2
script-security 2
up /etc/openvpn/up.sh
plugin /usr/lib/openvpn/openvpn-down-root.so /etc/openvpn/down.sh

ÉDIT du 12/01/2014 à 13h10 : Il faudra prévoir la révocation des certificats clients. C'est toujours utile en cas de perte ou de compromission, surtout si vous distribuez des accès (oui oui, le titre du billet cause d'un VPN unipersonnel mais bon) ... Fin de l'édit

La configuration du client :

proto udp
remote <IP PRINCIPALE DU SERVEUR> 1194
dev tun
 
tls-client
 
ca /etc/openvpn/easy-rsa/keys/ca.crt
cert /etc/openvpn/easy-rsa/keys/guigui.crt
key /etc/openvpn/easy-rsa/keys/guigui.key
 
comp-lzo
 
verb 3
 
persist-key
persist-tun
ping 30
ping-exit 90
explicit-exit-notify
 
user openvpn
group openvpn
 
ifconfig 198.18.0.2 198.18.0.1
route-gateway 198.18.0.1
redirect-gateway def1

Il est l'heure de tester (sur le client et le serveur) :

service openvpn restart

Normalement, le client doit toujours pouvoir pinguer 198.18.0.1 et sortir sur Internet par le VPN. L'adresse IP "vue depuis Internet" doit toujours être l'IP failover.

La même mais en mieux

Le résultat obtenu jusque-là est pas mal. Il manque un dernier truc : pour l'instant le script up est exécuté au démarrage d'OpenVPN, juste après la création de l'interface tun. Le down est exécuté à l'arrêt d'OpenVPN. J'aimerais que les scripts soient exécutés uniquement lorsque le client se connecte/déconnecte de mon VPN. Comme ça, le reste du temps je n'ai pas de la config qui ne sert à rien en train de tourner. Pas de forward, pas de NAT, l'IP failover ne répond pas aux requêtes, ...

Cela est possible en utilisant les directives client-connect/client-disconnect d'OpenVPN. Mais elles sont disponibles uniquement en mode serveur. Ce mode requiert l'utilisation d'un /29 au minimum donc on va avoir un peu de configuration à changer.

On s'occupe d'abord des configurations OpenVPN. Celle du serveur :

proto udp
port 1194
 
dev tun
 
mode server
max-clients 1
 
tls-server
ca      /etc/openvpn/easy-rsa/keys/ca.crt
cert    /etc/openvpn/easy-rsa/keys/server.crt
key     /etc/openvpn/easy-rsa/keys/server.key
dh      /etc/openvpn/easy-rsa/keys/dh1024.pem
 
comp-lzo
 
verb 3
 
persist-key
persist-tun
ping 30
ping-exit 90
 
user openvpn
group openvpn
 
ifconfig 198.18.0.1 198.18.0.2
ifconfig-pool 198.18.0.5 198.18.0.6
route 198.18.0.0 255.255.255.240
push "route 198.18.0.1"
 
script-security 2
client-connect "/usr/bin/sudo -u root /etc/openvpn/up.sh"
client-disconnect "/usr/bin/sudo -u root /etc/openvpn/down.sh"

La configuration du client :

proto udp
port 1194
 
dev tun
 
client
remote <IP PRINCIPALE DU SERVEUR> 1194
 
tls-client
ca /etc/openvpn/easy-rsa/keys/ca.crt
cert /etc/openvpn/easy-rsa/keys/guigui.crt
key /etc/openvpn/easy-rsa/keys/guigui.key
 
comp-lzo
 
verb 3
 
persist-key
persist-tun
ping 30
ping-exit 90
explicit-exit-notify
 
user openvpn
group openvpn
 
redirect-gateway def1

On remarque l'utilisation de sudo pour lancer les scripts à la connexion/déconnexion. En effet, lorsque le client se connectera ou se déconnectera, il y aura longtemps que le serveur OpenVPN aura perdu les droits root. Il faut donc rajouter une ligne au fichier /etc/sudoers :

openvpn		ALL=(root)	NOPASSWD:/etc/openvpn/up.sh,/etc/openvpn/down.sh

Les scripts d'up et de down changent aussi : on NAT le /29 et on redirige le DNAT sur la bonne IP :

#!/bin/bash
 
echo 0 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -D POSTROUTING -s 198.18.0.0/29 ! -d 198.18.0.0/29 -j SNAT --to-source <IP FAILOVER>
iptables -t nat -D PREROUTING -d <IP FAILOVER> -j DNAT --to-destination 198.18.0.6
ifconfig br0:1 down

Les mêmes modifications s'appliquent au script de déconnexion. Je vous laisse faire les changements. 🙂

Voilà, on arrive à la fin de ce que je voulais vous montrer.

  1. Bientôt propriétaire d’un dédié chez OVH, cet article tombe à pic.

    Je me pose cependant la question : Pourquoi un VPN nécessite l’IP failover ?

    • Lit l’article!
      « je souhaite que mon client VPN soit vu avec une IP distincte de celle attribuée à mon dédié. Il faut donc utiliser une IP failover et faire en sorte que le trafic sorte et entre de notre dédié par cette IP. »
      « Pour ceux qui cherchent comment monter un serveur VPN sur leur dédié OVH sans utiliser une IP failover : il suffit de faire un SNAT sur l’IP principale du serveur ou, au pire, un masquerade sur ce qui sort par eth0. »

  2. Tu n’es pas obligé d’en avoir une, juste si tu veux un Ip dedié à ça.

  3. Pour info, mon retour d’expérience chez OVH :

    – J’ai vu des bizarreries chez OVH récemment avec OpenVPN en UDP + (3G|OVH ADSL), réglé en utilisant TCP.

    – Il y a 2 ans, j’ai eu des problèmes avec un VPN UDP + IP FO. À l’époque pas trouvé de solution autre que d’abandonner l’IP FO.

    – J’ai eu le cas d’un user qui a lancé un gros SCP de serveur à serveur au dessus d’un VPN en UDP (ça a été fait par erreur/méconnaissance). L’un des serveurs a été bloqué sans préavis car « détection de hack sur votre serveur ».

    Donc ils ont des contraintes, il y a du filtrage.

  4. pour l’utilisation du cryptage asymétrique il fait utiliser le mode TCP. la configuration avec le mode udp ne marchera pas et ou ne sera pas fiable a cause des besoin de ce chiffrement. as tu réellement testé cette conf ?

    • « Attention à ne pas mal interpréter mes propos : le chiffrement du tunnel reste symétrique. Simplement, lors de l’initialisation, le client et le serveur échangent une clé temporaire pour réaliser le chiffrement symétrique du tunnel. C’est cet échange initial qui se fait en utilisant la cryptographie asymétrique. »

    • Petite note : en français, on dit « chiffrement », pas « cryptage ». Chaque fois que quelqu’un parle de cryptage, le grand Bortzmeyer tue un chaton mignon. Pensez-y.

      Oui, j’ai testé cette configuration. Elle est en production et est fonctionnelle.

      Il convient de relire le premier paragraphe de ce billet : « je ne destine pas ce VPN à l’échange de flux hautement confidentiels (sinon ça ne finirait pas chez OVH …). Donc si vous cherchez une config blindée haute sécurité, ce n’est pas le bon billet, désolé. ». J’ai prévenu : je ne suis pas un expert en sécurité informatique ! Si votre vie dépend d’un VPN (Syrie, échanges d’infos cruciales, …) n’utilisez pas bêtement ma configuration, elle n’est pas conçue pour ces usages ! Les usages que je destine à ce VPN sont clairement décrits au paragraphe 2.

      Pourrais-tu donner plus d’explications sur ce qui remettrait en cause la sécurité avec UDP ? Là, le seul élément que je vois est que le 3way-handshake de TCP permet une association source-destination réciproque, ce que ne permet pas le mode non-connecté d’UDP. Mais dans ce cas, si faiblesse il y a, cela concerne aussi le fonctionnement entier d’OpenVPN, pas seulement du chiffrement asymétrique avec OpenVPN. Je pense qu’OpenVPN gère ça (comme il doit prend en charge le séquencement qui est lui aussi absent d’UDP). La sécurité de l’asymétrique repose plus sur l’échange Diffie-Hellman éphémère et sur les certificats que sur le protocole de transport, à mon avis. D’autant plus qu’OpenVPN est quand même souvent conseillé d’être utilisé avec UDP pour éviter, entre autres, les problèmes du TCP over TCP. Mais si tu peux développer en quoi ma configuration en asymétrique serait faible, ça m’intéresse. 🙂

  5. Bon sang… J’ai passé 24h horribles à misérer… Quand tout ce qu’il me manquait, c’étaient deux petits iptables -t nat bien pensés pour faire exactement ce que je voulais…
    Merci merci merci ! Si seulement j’avais googlé le bon truc directement… Argh !

    Pour ma part, l’objectif est de faire un dédié depuis chez moi mais sans laisser mon IP publique visible, et bien ça va bientôt être le cas grâce à toi !