Serveur OpenVPN

dim. 01 sept. 2013 by Marmotte

Un serveur OpenVPN permet à des machines d'établir un lien chiffré avec le serveur. Il peut permettre d'accéder à un réseau privé situé derrière le serveur. Il peut aussi être utilisé pour faire passer tout le traffic du client par ce lien, dans le cas où le client utilise une connexion publique non sécurisée, par exemple.

Cas spécifique d'un container LXC

Si le serveur OpenVPN est dans un container LXC, il faut lui autoriser l'accès à l'interface tun. Dans le fichier de configuration de la machine LXC, /var/lib/lxc/<container-name>/config, il faut ajouter cette ligne :

# tun
lxc.cgroup.devices.allow = c 10:200 rwm

Cette modification demande un redémarrage du container pour prendre effet.

Note : Si le paquet openvpn a été installé avant que l'interface tun ne soit autorisée dans le container, il faut reconfigurer le paquet.

$ sudo dpkg-reconfigure openvpn

Installation

Sous Debian, il suffit d'installer les paquets openssl et openvpn.

$ sudo apt-get install --no-install-recommends openssl openvpn

Note : Depuis Debian jessie, les scripts de génération des certificats ont été déplacés dans le paquet easy-rsa, qu'il faut donc installer en supplément.

Génération des certificats

Les certificats et les fichiers de travail seront placés dans le répertoire /etc/openvpn/<NetworkName>/. Il faut donc créer ce répertoire.

$ sudo mkdir /etc/openvpn/<NetworkName>

J'utilise les outils easy-rsa/2.0 fournis dans la documentation du paquet Debian pour générer les certificats et clés utilisés par le VPN. Afin de ne pas travailler sur les fichiers originaux, et permettre de mettre facilement en place plusieurs instances d'OpenVPN, je copie les scripts de gestion des clés dans un répertoire spécifique.

$ sudo cp -r /usr/share/doc/openvpn/examples/easy-rsa/2.0 /etc/openvpn/<NetworkName>/easy-rsa

Note : Sous Debian jessie, les scripts de génération des certificats sont dans le répertoire /usr/share/easy-rsa au lieu de /usr/share/doc/openvpn/examples/easy-rsa/2.0.

Pour la suite de la génération des certificats, on doit se placer dans le répertoire où se trouvent les scripts, puisqu'ils travaillent avec des chemins relatifs.

$ cd /etc/openvpn/<NetworkName>/easy-rsa

il faut d'abord modifier les valeurs du fichier /etc/openvpn/<NetworkName>/easy-rsa/vars, pour les adapter au réseau créé.

export KEY_COUNTRY="FR"
export KEY_PROVINCE="FR"
export KEY_CITY="Paris"
export KEY_ORG="Marmotte"
export KEY_EMAIL="marmotte@server"

Il faut ensuite charger les valeurs de ce fichier dans l'environnement.

$ . vars

Le script clean-all nettoie l'environnement, et ajoute les éventuels répertoires manquants. Il est donc conseillé de commencer par l'exécuter afin d'être certain que le répertoire de travail est conforme.

$ sudo -E ./clean-all

Le premier certificat qu'il faut est générer est le certificat d'autorité. Il servira à signer tous les autres certificats créés par la suite.

$ sudo -E ./build-ca

Il faut ensuite générer le certificat qui sera utilisé par le serveur. Le paramètre donné est le nom du certificat du serveur.

$ sudo -E ./build-key-server <ServerCertName>

Nous générons ensuite une clé DH. Cette clé permet de chiffrer la phase d'échange de clés entre le client et le serveur, avant de passer la main au chiffrement du VPN lui même, une fois la connexion établie.

$ sudo -E ./build-dh

Il est aussi possible d'utiliser une clé TLS. Cette clé permet d'authentifier les paquets envoyés par les clients au serveur VPN. Les paquets n'ayant pas la bonne signature seront simplement ignorés, permettant de limiter la possibilité de flood ou détection du serveur VPN.

$ sudo -E openvpn --genkey --secret keys/ta.key

Génération des certificats des clients

Les certificats clients sont générés de la même manière que celui du serveur, mais avec le script build-key. Comme pour le certificat du serveur, le paramètre permet de définir le nom qui sera donné au certificat.

$ cd /etc/openvpn/<NetworkName>/easy-rsa
$ . vars
$ sudo -E ./build-key <ClientCertName>

Note : La dernière opération doit être exécutée autant de fois qu'il y a de clients.

Configuration générale

OpenVPN propose un fichier de configuration par défaut, qui contient déjà la plupart des directives utiles. Le plus simple est donc de se baser sur ce fichier de configuration pour créer celui de notre serveur.

$ sudo cp /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz /etc/openvpn/<NetworkName>.conf.gz
$ sudo gunzip /etc/openvpn/<NetworkName>.conf.gz

Dans la configuration, il faudra au moins modifier ces éléments :

  • Le chemin des certificats et clés aux lignes ca, cert, key et dh

    ca <NetworkName>/easy-rsa/keys/ca.crt
    cert <NetworkName>/easy-rsa/keys/<ServerCertName>.crt
    key <NetworkName>/easy-rsa/keys/<ServerCertName>.key  # This file should be kept secret
    dh <NetworkName>/easy-rsa/keys/dh1024.pem
    
  • Éventuellement modifier l'adresse IP et le masque du réseau VPN à la ligne server

  • Décommenter la ligne tls-auth et modifier le chemin de la clé

    tls-auth <NetworkName>/easy-rsa/keys/ta.key 0 # This file is secret
    
  • Décommenter les lignes user et group, pour limiter les droits du processus OpenVPN

  • Décommenter et adapter la ligne log-append pour avoir un log persistant

    log-append  /var/log/openvpn/<NetworkName>.log
    

    Attention : Il faut bien penser à créer le répertoire /var/log/openvpn/ et à configurer une rotation des fichiers de log.

  • Dans le cas d'un accès via un NAT, bien vérifier le protocole utilisé (TCP ou UDP) dans les règles de NAT donnant accès au serveur VPN

Il ne reste plus qu'à tester la configuration.

$ sudo openvpn /etc/openvpn/<NetworkName>.conf

Si le serveur se lance bien, vous pouvez l'arrêter, et le lancer comme service.

$ sudo service openvpn start <NetworkName>

Configurations supplémentaires

Utiliser le serveur VPN comme passerelle par défaut

Lorsqu'on se connecte sur une connexon publique non sécurisée, toutes les données transmises par l'ordinateur passent en clair sur le réseau. Ces données peuvent donc être capturées par n'importe quelle autre machine connectée au réseau, et parfois même par des machines non connectées au réseau.

Dans ce cas, il est très intéressant d'utiliser le serveur VPN comme passerelle par défaut. Ainsi, toutes les communications de l'ordinateur passeront à travers le VPN, et seront donc chiffrées, au moins jusqu'au serveur VPN.

Pour que le serveur VPN s'annonce comme passerelle par défaut à ses clients, il suffit de décommenter la route redirect-gateway.

push "redirect-gateway def1 bypass-dhcp"

Note : Cette modification ne sera prise en compte qu'après avoir relancé le serveur VPN, et les connexions des clients au serveur.

Permettre aux clients VPN de dialoguer avec un LAN présent derrière le serveur VPN

Activer l'ip forwarding sur le serveur. Dans un nouveau fichier /etc/sysctl.d/vpn.conf, ajouter cette ligne :

net.ipv4.ip_forward = 1

Note : Pour activer cette règle à chaud, sans redémarrer le serveur, il faut recharger la configuration du kernel.

$ sudo sysctl --system

Ajouter la route vers le LAN dans la configuration du serveur VPN pour qu'il se déclare comme passerelle auprès des clients VPN.

push "route 10.0.0.0 255.255.255.0"

Note : Dans cet exemple, 10.0.0.0 est l'adresse du LAN à atteindre et 255.255.255.0 le masque de ce réseau

Ajouter la route retour aux machines qui doivent être accessibles via le VPN. Il est préférable, si possible, de donner la route aux machines du réseau via un serveur DHCP (option classless-static-route dans Dnsmasq).

$ sudo ip route add 10.8.0.0/24 via 10.0.0.1

Note : Dans cet exemple, 10.8.0.0/24 est l'adresse de réseau et masque du réseau VPN et 10.0.0.1 l'adresse IP de la passerelle du LAN vers le VPN

Révocation d'un certificat

Lorsque l'un des clients ne doit plus pouvoir se connecter au VPN, ou qu'un certificat a été compromis, il faut le révoquer. Ainsi, ce certificat ne permettra plus d'accéder au réseau.

Comme pour la génération de certificats, il faut commencer par charger le fichiers vars.

$ cd /etc/openvpn/<NetworkName>/easy-rsa
$ . vars

Il faut ensuite utiliser le script revoke-full, en lui donnant le nom du certificat à révoquer.

$ sudo -E ./revoke-full <ClientCertName>

Ce script génère, ou met à jour, un fichier nommé crl.pem (Certificate Revocation List). La première fois qu'on révoque un certificat, il faut donc ajouter une directive dans le fichier de configuration du serveur pour lui indiquer de vérifier cette liste.

crl-verify <NetworkName>/easy-rsa/keys/crl.pem

Attention : Si vous avez décidé de déplacer le répertoire contenant les clés et certificats, pour simplifier les chemins dans le fichier de configuration, vérifiez bien le chemin du fichier crl.pem. Si le serveur OpenVPN ne trouve pas ce fichier, il ne l'utilisera pas, et les certificats révoqués pourront donc continuer de se connecter.

Il faut ensuite relancer le serveur VPN, et le certificat révoqué sera alors devenu inutile.

$ sudo service openvpn restart <NetworkName>

Note : Si vous utilisez les directives user et group, vérifiez que le serveur a bien la posibilité de lire le fichier crl.pem.