[Tuto] Monter son VPN perso avec OpenVPN, bis

sécurité 23 nov. 2017

Bis repetita placent, comme dirait l’autre.

Je reçois pas mal de questions par rapport à la configuration que je fournissais en… 2014… concernant OpenVPN. Si le tutoriel fonctionne toujours, il n’est clairement pas optimisé pour 2017 ! 😉

On va donc voir ce qu’il en est, l’histoire d’avoir un VPN maison un minimum fiable et à jour. C’est parti.

 

Je vous passe l’introduction usuelle sur « mais c’est quoi OpenVPN ? », vous n’êtes probablement pas arrivés ici par hasard. Je vais juste rappeler que c’est une solution libre et gratuite qui permet de faire transiter votre trafic dans un tunnel chiffré, entre votre machine (ordinateur, téléphone…) et son point de sortie.

Qu’on soit bien clair quand même : je parle ici de créer un VPN « perso », donc pour sécuriser les échanges entre votre device et un point de sortie situé chez vous ou dans votre entreprise. En gros, pour que quand vous êtes sur un réseau public (type FreeWiFi, réseau de médiathèque, Starbucks et autres conneries hôtelières), une autre personne sur le réseau ne s’amuse pas à écouter, intercepter, modifier… vos échanges. En plus, ça vous permet d’aller piocher dans votre NAS sans ouvrir directement celui-ci sur l’extérieur. Et ça, c’est cool.

Ce n’est PAS une solution pour vous rendre anonyme sur le web : si le tunnel VPN sort chez vous, votre fournisseur d’accès verra passer une partie du trafic, comme si vous étiez chez vous. Si c’est pour un VPN d’entreprise, alors la connexion semblera provenir de votre entreprise pour les sites que vous visitez. Dans ce cas-là, n’oubliez pas que vous êtes soumis(e) à la charte informatique de votre employeur (s’il vous interdit d’aller regarder des vidéos de chat sur PeerTube au bureau, ça s’étend fort probablement au VPN).

C’est peut-être bête de rappeler ça, mais la confusion règne dans pas mal de questions que je reçois. Donc oui, un VPN, ce n’est pas TOR. Faut l’savoir.

 

 

Pré-requis

Au risque de vous surprendre, on va installer OpenVPN. Toutes les commandes à suivre sont, sauf avis contraire, à exécuter en tant que ‘root’ (via sudo, sudo -s…).

Les manips sont effectuées ici sur un Raspberry Pi 2, sous Raspbian (donc les commandes sont valables pour tout ce qui est Debian, Ubuntu et dérivées type Mint <3 ). Pensez à adapter si vous utilisez une autre distro.

apt update
apt dist-upgrade -y
apt install -y iptables-persistent openvpn easy-rsa
echo 1 > /proc/sys/net/ipv4/ip_forward

Quelques explications. Les deux premières lignes, vous connaissez déjà, c’est juste pour être sûr que vous aurez un système à jour et aussi que les paquets qu’on va installer seront bien les plus récents disponibles.

La ligne 3 installe OpenVPN, easy-rsa (on s’en servira pour configurer votre serveur plus simplement) et iptables-persistent (plus cool pour gérer des règles iptable qui survivront au redémarrage. Dans la version précédente du tuto on utilisait un script bash qui se lançait avec openvpn, là c’est différent et plus pratique (à mon sens). Les 2 fonctionnent, donc à vous de choisir, au pire !

La dernière ligne, c’est pour autoriser le passage des paquets IP entre 2 réseaux (celui du VPN et votre réseau interne). Sans ça, rien ne fonctionnera 😉

 

Finalisons cette étape en ouvrant avec votre éditeur favori le fichier /etc/sysctl.conf et en y ajoutant la ligne suivante :

net.ipv4.ip_forward = 1

 

Règles IPTables

On a pas installé iptables pour rien, alors mettons les mains dans le cambouis digital numérique. Ici on va considérer que vous utilisez les ports par défaut (22 pour SSH et 1194 pour OpenVPN), mais je vous invite fortement à en choisir d’autres. On va garder les mêmes plages d’IP « internes » que dans la version initiale du tutoriel, si ça peut éviter de casser d’autres choses que vous auriez déjà mises en place a posteriori.

Éditons maintenant le fichier /etc/iptables/rules.v4 et remplacez tout son contenu par le suivant :

*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
# Forward the VPN traffic to eth0
-A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE

COMMIT

*filter

# Allow all loopback (lo) traffic and reject anything
# to localhost that does not originate from lo.
-A INPUT -i lo -j ACCEPT
-A INPUT ! -i lo -s 127.0.0.0/8 -j REJECT
-A OUTPUT -o lo -j ACCEPT

# Allow ping and ICMP error returns.
-A INPUT -p icmp -m state --state NEW --icmp-type 8 -j ACCEPT
-A INPUT -p icmp -m state --state ESTABLISHED,RELATED -j ACCEPT
-A OUTPUT -p icmp -j ACCEPT

# Allow SSH.
-A INPUT -i eth0 -p tcp -m state --state NEW,ESTABLISHED --dport 22 -j ACCEPT
-A OUTPUT -o eth0 -p tcp -m state --state ESTABLISHED --sport 22 -j ACCEPT

# Allow UDP traffic on port 1194.
-A INPUT -i eth0 -p udp -m state --state NEW,ESTABLISHED --dport 1194 -j ACCEPT
-A OUTPUT -o eth0 -p udp -m state --state ESTABLISHED --sport 1194 -j ACCEPT

# Allow DNS resolution and limited HTTP/S on eth0.
# Necessary for updating the server and timekeeping.
-A INPUT -i eth0 -p udp -m state --state ESTABLISHED --sport 53 -j ACCEPT
-A OUTPUT -o eth0 -p udp -m state --state NEW,ESTABLISHED --dport 53 -j ACCEPT
-A INPUT -i eth0 -p tcp -m state --state ESTABLISHED --sport 80 -j ACCEPT
-A INPUT -i eth0 -p tcp -m state --state ESTABLISHED --sport 443 -j ACCEPT
-A OUTPUT -o eth0 -p tcp -m state --state NEW,ESTABLISHED --dport 80 -j ACCEPT
-A OUTPUT -o eth0 -p tcp -m state --state NEW,ESTABLISHED --dport 443 -j ACCEPT

# Allow traffic on the TUN interface so OpenVPN can communicate with eth0.
-A INPUT -i tun0 -j ACCEPT
-A OUTPUT -o tun0 -j ACCEPT

# Log any packets which don't fit the rules above.
# (optional but useful)
-A INPUT -m limit --limit 3/min -j LOG --log-prefix "iptables_INPUT_denied: " --log-level 4
-A FORWARD -m limit --limit 3/min -j LOG --log-prefix "iptables_FORWARD_denied: " --log-level 4
-A OUTPUT -m limit --limit 3/min -j LOG --log-prefix "iptables_OUTPUT_denied: " --log-level 4

# then reject them.
-A INPUT -j REJECT
# -A FORWARD -j REJECT
-A OUTPUT -j REJECT

COMMIT

On va désactiver IPv6 par la suite, donc autant rejeter tout le trafic. Pour cela, on édite /etc/iptables/rules.v6 comme pour le précédent, pour y mettre :

 

*filter

-A INPUT -j REJECT
-A FORWARD -j REJECT
-A OUTPUT -j REJECT

COMMIT

 

On applique ces règles de suite :

iptables-restore < /etc/iptables/rules.v4
ip6tables-restore < /etc/iptables/rules.v6

Et on vérifie avec un coup de sudo iptables -L qui devrait vous confirmer tout ça.

 

 

Désactivation de IPv6 dans le système

J’avais teasé plus haut : hop, on est comme ça, on vire IPv6.

Éditons posément le fichier /etc/sysctl.d/99-sysctl.conf pour y ajouter les lignes suivantes :

net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
net.ipv6.conf.eth0.disable_ipv6 = 1

On charge ces nouvelles instruction via la commande :

sysctl -p

 

Vous devez également commenter/supprimer la ligne qui cause IPv6 dans le fichier /etc/hosts.

 

Configuration du serveur OpenVPN

On entre dans la partie sérieuse du game.

Pour info, le fichier de configuration « par défaut » de OpenVPN se situe là : /etc/openvpn/server.conf (du classique, hein). On va partir d’une conf de base à jour pour notre serveur, et non du fichier du tutoriel précédent. Pour ça, exécutez les commandes qui vont bien :

gunzip -c /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz > /etc/openvpn/server.conf
make-cadir /etc/openvpn/easy-rsa && cd /etc/openvpn/easy-rsa/
ln -s openssl-1.0.0.cnf openssl.cnf
mkdir keys
chmod 700 keys/

Là en gros, on a chopé le fichier de configuration « exemple » fourni par OpenVPN pour le placer là où le serveur va le chercher. On a demandé à ce que easy-rsa utilise un dossier spécifique et on s’y est placé, puis on a configuré l’utilisation de openssl. Enfin, on a créé le dossier de stockage des clés, et on l’a restreint un peu en accès. Voilà.

 

Chemins d’accès

Éditons /etc/openvpn/server.conf pour lui dire de chercher les certificats et clés au bon endroit :

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/dh4096.pem

 

Création du PEM de Diffie-Hellman

Un énième fichier à éditer : /etc/openvpn/easy-rsa/vars qui contient des variables (à adapter) utilisées pour générer les certificats :

export KEY_COUNTRY="FR"
export KEY_PROVINCE="FR"
export KEY_CITY="Troyes"
export KEY_ORG="Open-Freax"
export KEY_EMAIL="trash@open-freax.fr"
export KEY_OU="VPN Maison"

On va pouvoir sourcer ces variables :

cd /etc/openvpn/easy-rsa && source ./vars
./clean-all

Attention que le « clean-all » va nettoyer les résidus d’anciennes configurations : si y’a des fichiers à conserver, gardez-les ailleurs !

 

On se lance et on génère le pem qui sera utilisé (4096 bits cette fois, et non plus 2096 –ça peut prendre quelques minutes) [d’après la doc de OpenSSL, genpkey -genparam remplace dhparam, d’où adaptation ici] :

openssl genpkey -genparam -algorithm DH -out /etc/openvpn/server/dhp4096.pem -pkeyopt dh_paramgen_prime_len:4096

 

 

Durcissement de la configuration

C’est la partie essentielle du tuto. On va renforcer la sécurité de notre serveur, l’histoire que Jean-script ne vienne pas gratter à la porte tous les 4 matins.

 

Signature HMAC pendant la poignée de main TLS

Dans le fichier /etc/openvpn/server.conf, modifiez la configuration TLS comme suit :

tls-auth /etc/openvpn/easy-rsa/keys/ta.key 0

et générez la clé HMAC :

openvpn --genkey --secret /etc/openvpn/easy-rsa/keys/ta.key

(au moins une étape qui n’a pas changé depuis 2014 😉 )

 

Utilisateur ovpn

Là, on n’est clairement pas dans le négligeable. Je m’explique : par défaut, le démon OpenVPN tourne en tant que… root. Je vous pas pas de dessin sur ce qui pourrait se produire en cas de pépin/intrusion. Dans l’exemple de configuration, vous avez pu voir qu’on peut également le lancer en tant qu’utilisateur nobody, doté de bien moins de privilèges, mais qui pose un autre souci : il est utilisé par d’autres services comme des tâches CRON, Apache+mod_php, des partages NFS… Idem, en cas d’intrusion, il serait bon de limiter les dégâts.

On va donc configurer OpenVPN pour s’exécuter comme un utilisateur spécifique, dédié à ça. On le restreint au max dans son coin, sans privilèges particuliers, comme un oppressé. 😀 (rhooo ça va, on peut rigoler quand même)

Exécutez donc les commandes suivantes :

adduser --system --shell /usr/sbin/nologin --no-create-home ovpn
groupadd ovpn
usermod -g ovpn ovpn

(On ajoute l’utilisateur « ovpn », sans lui créer de dossier dans /home (pas besoin) et sans autoriser son login (ça sert à rien). On crée ensuite un groupe du même nom et on y ajoute notre nouvel utilisateur)

 

Adaptez dans /etc/openvpn/server.conf les lignes user et group pour utiliser « ovpn ».

 

Algorithmes autorisés

Rendons nous encore une fois dans /etc/openvpn/server.conf pour y spécifier quels algorithmes seront supportés via OpenSSL par notre serveur. Une bonne partie de la robustesse du chiffrement de notre tunnel réside ici.

On y place donc la liste de ce que l’on souhaite supporter :

auth SHA512    # This needs to be in client.ovpn too though.
tls-version-min 1.2
tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-256-CBC-SHA:TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA:TLS-DHE-RSA-WITH-AES-128-CBC-SHA:TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA
ncp-ciphers AES-256-GCM:AES-256-CBC

 

Certificat et bi-clés

Côté serveur

On utilise évidemment easy-rsa (on l’a installé pour ça).

cd /etc/openvpn/easy-rsa
./build-ca
./build-key-server server

 

Côté client

cd /etc/openvpn/easy-rsa && source ./vars && ./build-key client1

Pensez, si besoin, à remplacer « client1 » par un nom plus approprié.

 

 

 

Distribution aux clients

Méthode 1 : à la main

Plusieurs fichiers sont à fournir au client lors de sa configuration :

  • client.ovpn, qui contient la configuration associée à notre serveur
  • client1.cert (propre à chaque client)
  • client1.key (propre à chaque client également)
  • CA.pem (partagé entre le client et le serveur)
  • ta.key (idem)

La conf client adaptée au serveur que nous créons ici est la suivante (remplacez <your IP> par l’IP de votre serveur, évidemment) :

# No cryptography options are specified here because we want
# the VPN server to push those settings to clients rather than
# allow clients to dictate their crypto.

client
dev tun
persist-key
persist-tun
proto udp
nobind
user ovpn
group ovpn
remote-cert-tls server
auth SHA512
verb 3

# Remote server's IP address and port. IP is
# preferable over hostname so as not to rely
# on DNS lookups.
remote <your IP address> 1194

# To successfully import this profile, you
# want the client device's CA certificate copy,
# client certificate and key, and HMAC signature
# all in the same location as this .ovpn file.
ca ca.crt
cert client1.crt
key client1.key
tls-auth ta.key 1

 

Méthode 2 : on génère un .ovpn qui contient tout

Méthode inspirée de l’ancien tutoriel. créez un fichier Default.txt dans le dossier /etc/openvpn/easy-rsa/keys et placez-y les lignes suivantes, en adaptant la ligne remote avec votre IP serveur :

client
dev tun
persist-key
persist-tun
proto udp
nobind
user ovpn
group ovpn
remote-cert-tls server
auth SHA512
verb 3
remote <your_IP> 1194

 

Et créez un fichier MakeOVPN.sh contenant ces lignes :

#!/bin/bash 
# Script de génération client.ovpn
# Tutoriel complet : https://open-freax.fr/tuto-monter-son-vpn-perso-avec-openvpn-bis
# Déclaration des variables par défaut
DEFAULT="Default.txt" 
FILEEXT=".ovpn" 
CRT=".cert" 
KEY=".key" 
CA="ca.pem" 
TA="ta.key" 
 
# Demande du nom du client
echo "Entrez le nom d'un client existant :"
read NAME 
 
 
# On vérifie que la clé publique associé au nom du client existe 
if [ ! -f $NAME$CRT ]; then 
 echo "[ERREUR] Clé publique non trouvée : $NAME$CRT" 
 exit 
fi 
echo "Clé publique trouvée : $NAME$CR" 
 
 
# On vérifie qu'une clé privée existe pour ce client 
if [ ! -f $NAME$KEY ]; then 
 echo "[ERREUR] Clé privée non trouvée : $NAME$KEY" 
 exit 
fi 
echo "Clé privée trouvée : $NAME$KEY"

# On vérifie l'existence de la clé CA 
if [ ! -f $CA ]; then 
 echo "[ERREUR]: Clé publique CA non trouvée : $CA" 
 exit 
fi 
echo "Clé publique CA trouvée : $CA" 

# On vérifie l'existence de la clé tls-auth 
if [ ! -f $TA ]; then 
 echo "[ERREUR]: Clé privée tls-auth non trouvée : $TA" 
 exit 
fi 
echo "Clé privée tls-auth trouvée : $TA" 
 
# Prêt à générer le fichier de configuration
# On commence par insérer le fichier de base
cat $DEFAULT > $NAME$FILEEXT 
 
# On ajoute la clé publique du CA 
echo "<ca>" >> $NAME$FILEEXT 
cat $CA >> $NAME$FILEEXT 
echo "</ca>" >> $NAME$FILEEXT

# On ajoute la clé publique du client 
echo "<cert>" >> $NAME$FILEEXT 
cat $NAME$CRT | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' >> $NAME$FILEEXT 
echo "</cert>" >> $NAME$FILEEXT 
 
# On ajoute la clé privée du client
echo "<key>" >> $NAME$FILEEXT 
cat $NAME$KEY >> $NAME$FILEEXT 
echo "</key>" >> $NAME$FILEEXT 
 
# Enfin, on ajoute la clé tls-auth 
echo "<tls-auth>" >> $NAME$FILEEXT 
cat $TA >> $NAME$FILEEXT 
echo "</tls-auth>" >> $NAME$FILEEXT 
 
echo "Terminé ! $NAME$FILEEXT généré avec succès."

 

Rendez-le exécutable si besoin (chmod +x) et utilisez-le via la commande ./MakeOVPN.sh client1 (en remplaçant « client1 » par les noms de vos clients).

Le script va vous générer un client1.ovpn qui contient tout le nécessaire pour configurer ledit client 😉

Allez, profitez bien de votre VPN les amis !

 

 

Fichier server.conf

En cas de besoin, de bug, de doute… voici le fichier de configuration « de référence » que j’ai sur ma machine :

dev tun
persist-key
persist-tun
topology subnet
port 1194
proto udp
keepalive 10 120

# Location of certificate authority's cert.
ca /etc/openvpn/server/ca.crt

# Location of VPN server's TLS cert.
cert /etc/openvpn/server/server.crt

# Location of server's TLS key
key /etc/openvpn/server/server.key

# Location of DH parameter file.
dh /etc/openvpn/server/dhp4096.pem

# The VPN's address block starts here.
server 10.8.0.0 255.255.255.0

explicit-exit-notify 1

# Drop root privileges and switch to the `ovpn` user after startup.
user ovpn

# OpenVPN process is exclusive member of ovpn group.
group ovpn

# Cryptography options. We force these onto clients by
# setting them here and not in client.ovpn. See
# `openvpn --show-tls`, `openvpn --show-ciphers` and
#`openvpn --show-digests` for all supported options.
tls-auth /etc/openvpn/server/ta.key 0
auth SHA512    # This needs to be in client.ovpn too though.
tls-version-min 1.2
tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-256-CBC-SHA:TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA:TLS-DHE-RSA-WITH-AES-128-CBC-SHA:TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA
ncp-ciphers AES-256-GCM:AES-256-CBCncp-ciphers AES-256-GCM:AES-256-CBC

# Logging options.
ifconfig-pool-persist ipp.txt
status openvpn-status.log
log /var/log/openvpn.log
verb 3

Mots clés