Création — Nicolas THOREZ 2022/08/03 08:44
Un VPN (Virtual Private Network) est, comme son nom l'indique, un réseau privé virtuel. Il s'agit d'une connexion entre 2 points distants (têtes de pont) créant un liaison (tunnel ou pont) et permettant à des ordinateurs distant de partager des informations et des services comme s'ils étaient sur le même réseau privé. Le tunnel étant généralement chiffré et son accès étant assujetti à une authentification spécifique (AD, LDAP, certificat, PAM, etc…), le VPN permet de sécuriser l'accès à des services n'ayant pas d'autres systèmes de sécurisation ou de donner un accès distant à des services n'ayant pas de moyen de publication sécurisée.
Niveau VPN, on trouve 2 types de tunnels :
OpenVPN existe en tant que serveur et en tant que client et utilise le protocole SSL.
root. La plus grande prudence est donc requise.IPTables (Procédure d'installation trouvable ici)./etc/sysctl.conf :
sed -i 's/#net.ipv4.ip_forward=1/net.ipv4.ip_forward=1/' /etc/sysctl.conf sysctl -p
apt update && apt install -y openvpn easy-rsa
OpenVPN a besoin d'un certificat serveur et d'une autorité permettant de valider les certificats clients.
cd /usr/share/easy-rsa/ ./easyrsa init-pki --keysize=4096 --digest=sha512
./easyrsa --keysize=4096 --digest=sha512 build-ca nopass
server par le nom de notre serveur) :
./easyrsa --keysize=4096 --digest=sha512 build-server-full server nopass
./easyrsa --keysize=4096 --digest=sha512 gen-dh
openvpn --genkey secret ./pki/ta.key
OpenVPN ainsi qu'un raccourci pour la commande principale :
ln -sf /usr/share/easy-rsa /etc/openvpn/easy-rsa ln -sf /usr/share/easy-rsa/easyrsa /bin/easyrsa
cp /usr/share/doc/openvpn/examples/sample-config-files/server.conf /etc/openvpn/
/etc/openvpn/server.conf et on modifie/active les paramètres suivants :1194.udp.tun.easyrsa/ca.crteasyrsa/pki/issued/server.crt (server devant être remplacé par le nom choisi précédemment).easyrsa/pki/private/server.key (server devant être remplacé par le nom choisi précédemment).easyrsa/pki/dh.pem..1./etc/openvpn/ccd (on évitera le dossier client qui correspond plutôt au configuration d'un client openvpn qui se connecter sur un autre serveur et non aux informations des clients se connectant à ce serveur).server/ta.key.AES-256-GCM.OpenVPN après initialisation. On choisira nobody.nogroup.OpenVPN.3.
mkdir /etc/openvpn/ccd
Si le VPN doit déployer des routes communes à tous les utilisateurs, il est préférable de les ajouter dans la configuration du serveur en ajoutant pour chaque route une entrée de type :
push "route address mask"
Exemple :
push "route 8.8.8.8 255.255.255.255"
Si chaque utilisateur du VPN doivent utiliser un serveur DNS spécifique, on peut là aussi l'ajouter directement dans la configuration serveur avec une entrée de type (on remplace address par l'adresse IP du serveur DNS à utiliser) :
push "dhcp-option DNS address"
De plus, si ce serveur DNS doit résoudre des domaines privés, il est nécessaire d'en informer les clients en ajoutant dans la configuration serveur la ligne suivantes :
push "dhcp-option DOMAIN ~."
IPTables, il nous faut ajouter les règles nécessaires. Dans les exemples suivants, il faudra remplacer les valeurs :OpenVPN/etc/iptables.d/40-openvpn dont le contenu est :
*filter # Allow OpenVPN connections -A INPUT -p udp --dport 1194 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT COMMIT
/etc/iptables.d/60-postrouting dont le contenu est :
#================# # Partie serveur # #================# *nat # Source-NAT pour toutes les connexions entrantes vers OpenVPN -A POSTROUTING -o ens192 -s 172.16.0.0/24 -j SNAT --to-source 10.0.0.1 COMMIT #==========================================# # Partie clients pour chaque route commune # #==========================================# *filter # Autorisation à créer selon chaque route commune sous la forme : # -I FORWARD -i tun0 -o ens192 -s 172.16.0.0/24 -d 10.1.1.1 -j ACCEPT -m comment --comment "DNAT vers serv1" # -I FORWARD -i ens192 -o tun0 -s 10.1.1.1 -d 172.16.0.0/24 -j ACCEPT -m comment --comment "SNAT depuis serv1" #========================================================================================# # Finalisation (doit toujours se trouver à la fin, après les règles de tous les clients) # #========================================================================================# # On drop tous les flux qui ne sont pas explicitement autorisés -A FORWARD -s 172.16.0.0/24 -d 10.0.0.0/8 -j DROP COMMIT
service iptables restart
service openvpn@server start
Source : GitHub
Source : GitHub
Pour ajouter l'interface de gestion, il est nécessaire d'ajouter les paramètres nécessaires dans la configuration serveur (voir au dessus). Ensuite :
cd /tmp wget https://github.com/flant/ovpn-admin/releases/download/2.0.1/ovpn-admin-linux-amd64.tar.gz tar -xvf ovpn-admin-linux-amd64.tar.gz mv ovpn-admin /etc/openvpn/
/etc/openvpn/ccd.tpl :
{{- if (ne .ClientAddress "dynamic") }}
ifconfig-push {{ .ClientAddress }} 255.255.255.0
{{- end }}
{{- range $route := .CustomRoutes }}
push "route {{ $route.Address }} {{ $route.Mask }}" # {{ $route.Description }}
{{- end }}
/etc/openvpn/client.conf.tpl
# Configuration automatique via ovpn-admin
client
dev tun
dev-node ClientVPN
{{- range $server := .Hosts }}
proto {{ $server.Protocol }}
remote {{ $server.Host }} {{ $server.Port }}
{{- end }}
nobind
persist-key
persist-tun
comp-lzo
verb 4
# uncomment below lines for use with Google 2FA
#auth-user-pass
cipher AES-256-GCM
key-direction 1
tls-client
remote-cert-tls server
auth-nocache
explicit-exit-notify 1
reneg-sec 86400
# uncomment below lines for use with linux
#script-security 2
# if you use resolved
#up /etc/openvpn/update-resolv-conf
#down /etc/openvpn/update-resolv-conf
# if you use systemd-resolved first install openvpn-systemd-resolved package
#up /etc/openvpn/update-systemd-resolved
#down /etc/openvpn/update-systemd-resolved
<cert>
{{ .Cert -}}
</cert>
<key>
{{ .Key -}}
</key>
<ca>
{{ .CA -}}
</ca>
<tls-auth>
{{ .TLS -}}
</tls-auth>
/etc/openvpn/launch_ovpn_admin.sh :
#!/bin/bash
# Variables
OVPN_LISTEN_HOST=127.0.0.1 # Adresse de l'hôte
OVPN_LISTEN_PORT=8088 # Port de l'hôte
OVPN_NETWORK=172.16.0.0/24 # Plage réseau des clients OpenVPN
OVPN_SERVER=1.2.3.4:1194:udp # Adresse, port et protocole d'écoute pour OpenVPN
OVPN_MGMT=127.0.0.1:8989 # Adresse et port de l'interface de gestion OpenVPN (pour les appels API)
OVPN_METRICS_PATH="/metrics" # URL pour les métriques (pour Grafana)
EASYRSA_PATH="/etc/openvpn/easyrsa" # Racine pour easy-RSA
OVPN_INDEX_PATH="/etc/openvpn/easyrsa/pki/index.txt" # Chemin de la base de données pour les certificats gérés
OVPN_CCD_PATH="/etc/openvpn/ccd" # Stockage des configurations clientes
OVPN_TEMPLATES_CC_PATH="/etc/openvpn/client.conf.tpl" # Chemin du modèle de configuration cliente
OVPN_TEMPLATES_CCD_PATH="/etc/openvpn/ccd.tpl" # Chemin du modèle de routage client
LOG_LEVEL="debug" # Niveau de log
/etc/openvpn/ovpn-admin \
--listen.host=$OVPN_LISTEN_HOST \
--listen.port=$OVPN_LISTEN_PORT \
--log.level=$LOG_LEVEL \
--easyrsa.path=$EASYRSA_PATH \
--easyrsa.index-path=$OVPN_INDEX_PATH \
--ovpn.network=$OVPN_NETWORK \
--ovpn.server=$OVPN_SERVER \
--metrics.path=$OVPN_METRICS_PATH \
--ccd \
--ccd.path=$OVPN_CCD_PATH \
--templates.ccd-path=$OVPN_TEMPLATES_CCD_PATH \
--templates.clientconfig-path=$OVPN_TEMPLATES_CC_PATH &
chmod +x /etc/openvpn/launch_ovpn_admin.sh
echo "# Daemon de gestion des clients OpenVPN" > /etc/cron.d/ovpn-admin echo '*/10 * * * * root [ "$(pidof -x ovpn-admin)" ] || /etc/openvpn/launch_ovpn_admin.sh &' >> /etc/cron.d/ovpn-admin
/etc/openvpn/ovpn_connect.sh :
#!/bin/bash
#########################################################################
# #
# Script de création des règles IPTables à la connexion d'un client #
# #
#########################################################################
#-----------#
# Variables #
#-----------#
# Chemin des configurations clientes
CCD_DIR="/etc/openvpn/ccd"
# Interface de sortie du serveur
IF_OVPN="ens160"
#-----------------------------------------------#
# Memento des variables automatiques de OpenVPN #
#-----------------------------------------------#
# $common_name Identifiant du client (fichier de configuration, certificat, etc...)
# $ifconfig_pool_remote_ip Adresse IP affecté au client par OpenVPN
# $dev Interface réseau du tunnel OpenVPN
#------------#
# Traitement #
#------------#
# Traitement si il y a une configuration cliente
if [ -f $CCD_DIR/$common_name ]; then
# Configuration existante, on extrait les routes à établir
grep "^push \"route" $CCD_DIR/$common_name | tr -d '"' | \
# Boucle de création des règles
while read LINE; do
# Extraction de l'adresse
ADDRESS=$(echo $LINE | cut -f3 -d" ")
# Extraction du masque
NETMASK=$(echo $LINE | cut -f4 -d" ")
# Mise en forme des commentaires
COMMENT=$(echo $LINE | cut -d"#" -f2)
DNAT_COMMENT="$common_name DNAT vers $COMMENT"
SNAT_COMMENT="$common_name SNAT vers $COMMENT"
# Ajout de la règle de DNAT
sudo /sbin/iptables -I FORWARD -i $dev -o $IF_OVPN -s $ifconfig_pool_remote_ip/32 -d $ADDRESS/$NETMASK -j ACCEPT -m comment --comment "$DNAT_COMMENT"
# Ajout de la règle de SNAT
sudo /sbin/iptables -I FORWARD -i $IF_OVPN -o $dev -s $ADDRESS/$NETMASK -d $ifconfig_pool_remote_ip/32 -j ACCEPT -m comment --comment "$SNAT_COMMENT"
done
fi
exit 0
/etc/openvpn/ovpn_disconnect.sh :
#!/bin/bash
############################################################################
# #
# Script de suppression des règles IPTables à la déconnexion du client #
# #
############################################################################
#-----------------------------------------------#
# Memento des variables automatiques de OpenVPN #
#-----------------------------------------------#
# $common_name Identifiant du client (fichier de configuration, certificat, etc...)
# $ifconfig_pool_remote_ip Adresse IP affecté au client par OpenVPN
# $dev Interface réseau du tunnel OpenVPN
#------------#
# Traitement #
#------------#
# On vérifie la présence de règles pour le client
MAX=$(sudo /sbin/iptables -nL FORWARD --line-numbers | grep -E "[[:blank:]]$common_name[[:blank:]]" | wc -l)
if [[ $MAX -gt 0 ]]; then
# On supprime toutes les règles de FORWARD contenant l'identifiant de l'utilisateur dans les commentaires
for ((i=1;i<=$MAX;i++)); do
# On récupère le numéro de la règle à supprimer
RULE=$(sudo /sbin/iptables -nL FORWARD --line-numbers | grep -m 1 -E "[[:blank:]]$common_name[[:blank:]]" | awk '{print $1}')
# On supprimme la règle
sudo /sbin/iptables -D FORWARD $RULE
done
fi
exit 0
chmod +x /etc/openvpn/ovpn_connect.sh chmod +x /etc/openvpn/ovpn_disconnect.sh
L'interface est désormais disponible mais elle est accessible par n'importe qui. On va donc installer un proxy Apache devant pour ajouter une authentification de base. Du coup :
apt install -y apache2
/etc/apache2/sites-available/ovpn-admin.conf :
<VirtualHost *:443>
ServerAdmin mon.adresse@mail.tld
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
ProxyPass / http://127.0.0.1:8088/
ProxyPassReverse / http://127.0.0.1:8088/
ProxyRequests Off
<Location />
AuthType Basic
AuthName "Restricted Area"
AuthUserFile "/etc/apache2/password.file"
Require valid-user
</Location>
SSLEngine On
SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem
SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key
</VirtualHost>
htpasswd -c /etc/apache2/password.file ovpn-admin
ssl, proxy et proxy_http :
a2enmod ssl a2enmod proxy a2enmod proxy_http
a2ensite ovpn-admin.conf
Apache :
service apache2 restart
L'interface est maintenant disponible après authentification à l'adresse https://adresse_du_serveur :
Pour activer le 2FA de Google, il faut au préalable ajouter le plugin dans la configuration serveur (voir plus haut). Ensuite :
apt install -y libqrencode4 libpam-google-authenticator
/etc/openvpn/create-2fa.sh :
#!/bin/bash
# Variables
SCRIPT_PATH="/etc/openvpn"
CCD="$SCRIPT_PATH/ccd"
# Usage
get-help() {
echo "Usage : ./create-2fa.sh user"
echo " user doit être un nom d'utilisateur tel qu'il apparaît dans les configurations clientes de OpenVPN, dans le dossier ccd."
exit 1
}
# Test présence utilisateur
if [ -z "$1" ]; then
get-help
elif [ ! -f $CCD/$1 ]; then
get-help
fi
# Utilisateur existant, création du dossier
useradd $1 -m -s /bin/bash
# Création du google authenticator
su -c "google-authenticator -t -f -d -r 3 -R 30 -w 17 --label=\"OpenVPN ${1}\"" $1
# Mise à jour des droits
chmod 400 /home/${1}/.google_authenticator
chmod 700 /home/${1}
chmod +x /etc/openvpn/create-2fa.sh
/lib/systemd/system/openvpn@.service et on le recharge :
sed -i 's/ProtectHome=true/ProtectHome=false/g' /lib/systemd/system/openvpn@.service systemctl daemon-reload
/etc/pam.d/openvpn :
cp /etc/pam.d/common-account /etc/pam.d/openvpn
auth required pam_google_authenticator.so authtok_prompt=pin
service openvpn@server restart
Pour créer un 2FA pour un utilisateur, il suffit de lancer le script /etc/openvpn/create-2fa.sh user où user est le nom de l'utilisateur tel qu'il apparaît dans le dossier /etc/openvpn/ccd/ et/ou dans l'interface d'administration ovpn-admin. Le script crée le compte utilisateur local affiche un QRcode qu'il faudra scanner depuis l'application mobile Google Authenticator. Il demande alors un code de validation pour terminer la création.
Pour la suite, lorsque l'utilisateur se connecte au VPN, il lui sera demander un code fourni par l'application mobile pour pouvoir se connecter.
client par l'identifiant du client, NOMPrenom par exemple) :
cd /usr/share/easy-rsa ./easyrsa --keysize=4096 --digest=sha512 build-client-full client nopass
%USERPROFILE%/openvpn/config du poste client, client.ovpn dont le contenu est :ClientVPN par le nom de l'interface réseau virtuel (Interface TAP-9)
client dev tun dev-node ClientVPN proto udp remote 1.2.3.4 1194 nobind persist-key persist-tun comp-lzo verb 4 # uncomment below lines for use with Google 2FA #auth-user-pass cipher AES-256-GCM key-direction 1 tls-client remote-cert-tls server auth-nocache explicit-exit-notify 1 reneg-sec 86400 # keys ca chemin_vers_le_fichier_ca.crt cert chemin_vers_le_fichier_client.crt key chemin_vers_le_fichier_client.key tls-auth chemin_vers_le_fichier_ta.key 1
/etc/openvpn/ du poste client, client.conf dont le contenu est :
client dev tun proto udp remote 1.2.3.4 1194 nobind persist-key persist-tun comp-lzo verb 4 # uncomment below lines for use with Google 2FA #auth-user-pass data-cipher AES-256-GCM key-direction 1 tls-client remote-cert-tls server auth-nocache explicit-exit-notify 1 reneg-sec 86400 # uncomment below lines for use with linux script-security 2 # if you use resolved #up /etc/openvpn/update-resolv-conf #down /etc/openvpn/update-resolv-conf # if you use systemd-resolved first install openvpn-systemd-resolved package #up /etc/openvpn/update-systemd-resolved #down /etc/openvpn/update-systemd-resolved # keys ca chemin_vers_le_fichier_ca.crt cert chemin_vers_le_fichier_client.crt key chemin_vers_le_fichier_client.key tls-auth chemin_vers_le_fichier_ta.key 1
/etc/openvpn/ccd/ (on remplace client par le nom choisi précédemment) :
nano /etc/openvpn/ccd/client
# Configuration pour le client "client" ifconfig-push 172.16.0.5 176.16.0.6 push-reset push "dhcp-option DNS 10.0.0.1" push "dhcp-option DOMAIN ~." push "route 10.0.1.1 255.255.255.255" push "route 10.0.1.2 225.255.255.255"
/etc/iptables.d/60-postrouting, les règles IPTables permettant le routage des flux. Dans cette exemple :
... # Autorisation pour client -I FORWARD -i tun0 -o ens192 -s 172.16.0.5 -d 10.0.1.1 -p tcp --dport 80 -j ACCEPT -I FORWARD -i tun0 -o ens192 -s 172.16.0.5 -d 10.0.1.1 -p tcp --dport 443 -j ACCEPT -I FORWARD -i ens192 -o tun0 -s 10.0.1.1 -d 172.16.0.49 -j ACCEPT -I FORWARD -i tun0 -o ens192 -s 172.16.0.5 -d 10.0.1.2 -p tcp --dport 22 -j ACCEPT -I FORWARD -i ens192 -o tun0 -s 10.0.1.2 -d 172.16.0.49 -j ACCEPT ...
IPTables :
service iptables restart
Add user :
Create :
Edit routes :
Save :
Add. Une fois toutes les routes ajoutées, on sauvegarde en cliquant sur Save :
Download config :