Mise en place du serveur VPN
On installe les paquets nécessaires pour la mise en place du service VPN :
# sudo apt install -y openvpn easy-rsa
On va maintenant générer des certificats de sécurité pour notre serveur VPN et pour les futurs clients qui se connecteront dessus en s'aidant de l'outil Easy-RSA dont on fait une copie du modèle de fichier de configuration :
# cd /usr/share/easy-rsa # sudo cp vars.example vars
On modifie ce nouveau fichier "/usr/share/easy-rsa/vars" ainsi (on verra plus tard ce qu'il en est du domaine "spou.local" qui apparait dans ce fichier):
... set_var EASYRSA_REQ_COUNTRY "FR" set_var EASYRSA_REQ_PROVINCE "Poulpe State" set_var EASYRSA_REQ_CITY "Poulpeville" set_var EASYRSA_REQ_ORG "Poulpe Corp." set_var EASYRSA_REQ_EMAIL "postmaster@spou.local" set_var EASYRSA_REQ_OU "Poulpe Corp. unit" ...
Avec les commandes ci-dessous, on va commencer par initialiser notre infrastructure PKI ("Public Key Infrastructure") qui va nous permettre dans un premier temps de générer le certificat de notre propre autorité de certification dédiée à notre serveur et nos clients VPN et qui va permettre ensuite de générer et signer justement le certificat pour le serveur VPN. On va copier ensuite les fichiers du certificat du serveur (ici on va en fait plutôt créer des liens symboliques) vers le dossier "/etc/openvpn". Enfin, on va produire deux fichiers de sécurité supplémentaires pour le serveur VPN et on va copier un modèle de fichier de configuration pour notre serveur VPN que l'on modifiera juste après :
# sudo ./easyrsa init-pki # sudo ./easyrsa build-ca nopass # sudo ./easyrsa gen-req server nopass # sudo ./easyrsa sign-req server server # sudo ln -s /usr/share/easy-rsa/pki/ca.crt /etc/openvpn/ca.crt # sudo ln -s /usr/share/easy-rsa/pki/issued/server.crt /etc/openvpn/server.crt # sudo ln -s /usr/share/easy-rsa/pki/private/server.key /etc/openvpn/server.key # sudo openssl dhparam -out /etc/openvpn/dh2048.pem 2048 # sudo openvpn --genkey secret /etc/openvpn/ta.key # sudo cp /usr/share/doc/openvpn/examples/sample-config-files/server.conf /etc/openvpn
On édite le fichier "/etc/openvpn/server.conf" comme ci-dessous, on va notamment faire en sorte de créer le réseau privé et virtuel 10.11.12.0/24 (ce qui veut dire que notre serveur aura comme adresse IP supplémentaire 10.11.12.1 et que les clients qui se connecteront à notre serveur VPN se verront attribuer une adresse IP qui commence par "10.11.12") et enfin, on va faire en sorte que les clients utilisent un serveur DNS local que nous installerons plus tard et qui permettra d'accéder à des noms de domaine privés et donc potentiellement à des sites web cachés :
... topology subnet ... server 10.11.12.0 255.255.255.0 ... push "redirect-gateway def1 bypass-dhcp" ... push "dhcp-option DNS 1O.11.12.1" ... comp-lzo ... user nobody group nogroup ...
On modifie le fichier "/etc/default/openvpn" ainsi afin que le serveur VPN démarre automatiquement au démarrage de notre système :
... AUTOSTART="all" ...
Et on redémarre les services adéquates :
# sudo systemctl daemon-reload # sudo systemctl restart openvpn
On veut que quand nos clients se connectent à notre serveur VPN, leur adresse IP publique (c'est à dire les IP que verrons apparaitre dans leurs logs les administrateurs des sites web externes que nos clients visiterons ensuite) soit remplacée par l'IP publique de notre serveur. Pour cela, on commence à activer la fonctionnalité "IP forwarding" de notre système en modifiant le fichier "/etc/sysctl.conf" ainsi :
... net.ipv4.ip_forward=1 ...
On applique ce changement :
# sudo sysctl -p
Il ne nous reste plus qu'à ajouter des règles au niveau du firewall logiciel nftables afin que tout le trafic qui passe par le réseau virtuel 10.11.12.0/24 et qui est dirigé vers l'extérieur passe en fait par l'interface réseau physique de notre serveur, à savoir l'interface "eth0" dans notre cas. Pour cela, on modifie le fichier "/etc/nftables.conf" de cette façon :
... table ip nat { chain postrouting { type nat hook postrouting priority srcnat; policy accept; ip saddr 10.11.12.0/24 oif "eth0" masquerade } }
On applique les changements grâce à cette commande (ATTENTION, cela va effacer les règles en cours ajoutées par Fail2ban mais celles-ci reviendront à la prochaine adresse IP bloquée ou au prochain redémarrage du système) :
# sudo nft --file /etc/nftables.conf
Création des clients VPN
On peut maintenant créer autant de clients VPN que l'on souhaite grâce à la série de commandes ci-dessous, dans cet exemple on va créer un client nommé "client01" (mais on peut choisir le nom que l'on veut). La commande "easyrsa gen-req ..." va permettre de créer un certificat VPN pour lequel le client devra saisir son identifiant (ici "client01") et un mot de passe lors de la connexion. Pour qu'il n'ait pas à saisir de mot de passe, il suffit d'ajouter le paramètre "nopass" au bout de la commande en question. On signe ensuite le certificat et on copie les fichiers nécessaires dans le dossier "/etc/openvpn/client/client01", que l'on a créé au préalable, dont un modèle de fichier de configuration :
# cd /usr/share/easy-rsa # sudo ./easyrsa gen-req client01 # sudo ./easyrsa sign-req client client01 # sudo mkdir /etc/openvpn/client/client01 # sudo ln -s /usr/share/easy-rsa/pki/issued/client01.crt /etc/openvpn/client/client01/client.crt # sudo ln -s /usr/share/easy-rsa/pki/private/client01.key /etc/openvpn/client/client01/client.key # sudo ln -s /usr/share/easy-rsa/pki/ca.crt /etc/openvpn/client/client01/ca.crt # sudo ln -s /etc/openvpn/ta.key /etc/openvpn/client/client01/ta.key # sudo cp /usr/share/doc/openvpn/examples/sample-config-files/client.conf /etc/openvpn/client/client01/client.ovpn
On modifie le fichier "/etc/openvpn/client/client01/client.ovpn" ainsi (la ligne qui commence par "dhcp-option ..." sert essentiellement pour les clients qui se connecteront sous système Windows) :
... remote patate.spou.net 1194 ... comp-lzo ... dhcp-option DNS 10.11.12.1 ...
On peut faire en sorte de condenser tous les fichiers ("client.ovpn", "ca.crt", "client.crt", "client.key" et "ta.key") dans un seul fichier "client.ovpn", cela est utile notamment pour la version mobile du logiciel OpenVPN Connect. Pour cela on modifie le fichier "/etc/openvpn/client/client01/client.ovpn" de cette sorte (à vous de combler les trous selon le contenu de vos fichiers correspondant à chaque section) :
... <ca> -----BEGIN CERTIFICATE----- ... -----END CERTIFICATE----- </ca> <cert> Certificate: Data: Version: 3 (0x2) Serial Number: ... -----BEGIN CERTIFICATE----- ... -----END CERTIFICATE----- </cert> <key> -----BEGIN ENCRYPTED PRIVATE KEY----- ... -----END ENCRYPTED PRIVATE KEY----- </key> ... <tls-auth> -----BEGIN OpenVPN Static key V1----- ... -----END OpenVPN Static key V1----- </tls-auth> key-direction 1 ...
On copie les fichiers du client (en transformant notamment les liens symboliques en des fichiers réels) dans le répertoire de notre utilisateur usuel (ici "webadmin") afin de pouvoir les récupérer ensuite via le protocole SSH/SFTP (grâce au logiciel FileZilla par exemple) :
# sudo cp -Lr /etc/openvpn/client/client01 ~ # sudo chown -R webadmin:webadmin ~/client01
Installer un serveur DNS local
Avant de transmettre les certificats VPN générés précédemment à nos clients, il nous reste à installer le serveur DNS local 10.11.12.1 qui est mentionné dans les fichiers de configuration de notre serveur et de nos clients VPN.
Cela va permettre de donner potentiellement accès aux utilisateurs qui se connectent à notre service VPN à des sites web cachés sur notre serveur en créant un nom de domaine privé, ici le domaine spou.local.
On commence par installer les logiciels nécessaires :
# sudo apt install -y bind9 bind9utils bind9-doc dnsutils
On modifie ensuite le fichier "/etc/bind/named.conf.local" ainsi :
... zone "spou.local" IN { type master; file "/etc/bind/forward.spou.local.db.signed"; allow-update { none; }; }; zone "12.11.10.in-addr.arpa" IN { type master; file "/etc/bind/reverse.spou.local.db"; allow-update { none; }; };
On se base sur un modèle existant pour créer le fichier de configuration de nos hôtes qui appartiendront au domaine spou.local :
# sudo cp /etc/bind/db.local /etc/bind/forward.spou.local.db
On modifie le fichier "/etc/bind/forward.spou.local.db" comme ci-dessous, on va notamment créer le nom d'hôte www.spou.local pour un éventuel site web privé et on va également faire en sorte que l'on puisse envoyer des e-mails à des adresses ***@spou.local (le nom d'hôte ns1.spou.local est le nom général donné à notre serveur DNS, c'est obligatoire pour la configuration du serveur mais dans la pratique on ne l'utilisera pas) :
... $TTL 604800 @ IN SOA ns1.spou.local. postmaster.spou.local. ( 2 ; Serial 604800 ; Refresh 86400 ; Retry 2419200 ; Expire 604800 ) ; Negative Cache TTL @ IN NS ns1.spou.local. @ IN A 10.11.12.1 ns1 IN A 10.11.12.1 www IN CNAME spou.local. @ IN MX 10 spou.local.
On vérifie que tout est OK dans notre fichier grâce à la commande suivante :
# sudo named-checkzone spou.local /etc/bind/forward.spou.local.db
On se base sur un modèle existant pour créer le fichier de configuration du "reverse DNS" pour les noms d'hôtes créés précédemment :
# sudo cp /etc/bind/db.127 /etc/bind/reverse.spou.local.db
On modifie le fichier "/etc/bind/reverse.spou.local.db" ainsi pour correspondre aux modifications effectuées dans le fichier précédent (si nous avions créé un nom d'hôte qui pointe vers une machine qui a pour IP 10.11.12.142, nous aurions alors ajouté une ligne commençant par "142 IN PTR ..." ) :
... $TTL 604800 @ IN SOA ns1.spou.local. postmaster.spou.local. ( 2 ; Serial 604800 ; Refresh 86400 ; Retry 2419200 ; Expire 604800 ) ; Negative Cache TTL @ IN NS ns1.spou.local. @ IN A 10.11.12.1 ns1 IN A 10.11.12.1 1 IN PTR www.spou.local. 1 IN PTR ns1.spou.local.
On vérifie que tout est OK dans notre fichier grâce à la commande suivante :
# sudo named-checkzone 12.11.10-in.addr.arpa /etc/bind/reverse.spou.local.db
On va maintenant renforcer l'authentification de notre serveur DNS en utilisant des signatures numériques en suivant le protocole DNSSEC grâce aux commandes suivantes (la commande "dnssec-signzone ..." sera à refaire à chaque fois que l'on modifie ou ajoute les noms d'hôte de notre domaine spou.local, si d'ailleurs cette commande semble ne pas aboutir, remplacer le paramètre "/dev/random" par "/dev/urandom") :
# cd /etc/bind # sudo dnssec-keygen -a RSASHA256 -b 1024 -n ZONE spou.local # sudo dnssec-keygen -f KSK -a RSASHA256 -b 2048 -n ZONE spou.local # sudo bash -c 'for key in `ls Kspou.local*.key`; do echo "\$INCLUDE /etc/bind/$key" >> forward.spou.local.db; done' # sudo dnssec-signzone -A -3 $(head -c 1000 /dev/random | sha256sum | cut -b 1-16) -N INCREMENT -o spou.local -t forward.spou.local.db # sudo chown -R root:bind /etc/bind # sudo chmod -R g+rw /etc/bind # sudo chown -R root:bind /var/cache/bind # sudo chmod -R g+rw /var/cache/bind
On modifie le fichier "/etc/default/named" (ou "/etc/default/bind9" selon les versions) afin de n'utiliser que le protocole IPv4 car notre serveur n'est pas configuré pour gérer correctement l'IPv6 et les fichiers journaux de notre système risquent d'être pollués par des messages d'alerte) :
... OPTIONS="-u bind -4" ...
On redémarre le serveur DNS :
# sudo systemctl restart bind9
On modifie le fichier "/etc/resolv.conf" comme ci-dessous afin que notre serveur utilise exclusivement le serveur DNS local. En effet, le serveur DNS qu'on a installé ne fait pas que gérer le domaine spou.local, il sait aussi agir comme un DNS normal en traduisant tous les autres noms de domaine Internet en adresse IP. Cela peut être pratique pour notre serveur notamment pour sa fonction de serveur d'e-mails afin que ses requêtes DNS ne soient pas bloquées par des serveurs DNS externes qui n'apprécient pas d'être sollicités trop souvent, ce qui peut être le cas quand on reçoit des milliers de courriers spam qui utilisent souvent des faux noms de domaine qui vont quand même être vérifiés auprès des serveurs DNS :
search spou.local nameserver 127.0.0.1
Créer un site web privé
Nous avons configuré précédemment le nom d'hôte www.spou.local lors de la mise en place de notre serveur de DNS local, on veut maintenant qu'un utilisateur qui s'est connecté à notre VPN et qui tape l'adresse http://www.spou.local dans la barre d'adresse de son navigateur internet arrive sur un site web fonctionnel.
On commence par générer nos propres certificats auto-signés pour le nom de domaine spou.local car même si la connexion de l'utilisateur est déjà protégée du fait qu'il est connecté en VPN et qu'aucun individu extérieur à ce VPN ne pourra voir son activité sur le site www.spou.local, il n'en reste pas moins que l'utilisateur sera tout de même redirigé automatiquement vers la version HTTPS du site www.spou.local car on ne veut pas modifier toute notre configuration Nginx/Varnish/Apache précédente.
Il faut donc créer un certificat SSL pour ce site en exécutant les commandes ci-dessous qui vont créer tout d'abord un certificat "général" qui nous servira en tant qu'autorité de certification non-officielle (dénommée "Poulpe CA") pour générer ensuite autant de certificats SSL qu'on le souhaite (mais ici on va en générer qu'un seul qui fonctionnera pour tous les noms d'hôte du domaine spou.local et qui est valable 10 ans, soit 3650 jours) :
# sudo openssl genrsa -out /etc/ssl/CA_spou_local.key 2048 # sudo openssl req -new -x509 -days 3650 -key /etc/ssl/CA_spou_local.key -subj "/C=FR/ST=Poulpe State/L=Poulpeville/O=Poulpe Corp./CN=Poulpe CA" -out /etc/ssl/CA_spou_local.crt # sudo openssl req -newkey rsa:2048 -nodes -keyout /etc/ssl/STAR_spou_local.key -subj "/C=FR/ST=Poulpe State/L=Poulpeville/O=Poulpe Corp./CN=*.spou.local" -out /etc/ssl/STAR_spou_local.csr # sudo bash -c 'openssl x509 -req -extfile <(printf "subjectAltName=DNS.1:spou.local,DNS.2:*.spou.local,IP:10.11.12.1") -days 3650 -in /etc/ssl/STAR_spou_local.csr -CA /etc/ssl/CA_spou_local.crt -CAkey /etc/ssl/CA_spou_local.key -CAcreateserial -out /etc/ssl/STAR_spou_local.crt' # sudo ln -sf /etc/ssl/CA_spou_local.crt /etc/ssl/STAR_spou_local.ca # sudo sh -c 'cat /etc/ssl/STAR_spou_local.crt /etc/ssl/STAR_spou_local.ca >> /etc/ssl/STAR_spou_local.fullchain'
Par contre, un certificat auto-signé provoquera des erreurs lorsque les utilisateurs visiteront nos différents sites web. Il faut obligatoirement envoyer à chacun des utilisateurs (par e-mail, clé USB ou autre) le fichier "/etc/ssl/CA_spou_local.crt" créé précédemment et qui permet d'authentifier notre autorité de certification non-officielle. Les utilisateurs devront ensuite aller dans leur navigateur internet préféré et ajouter ce certificat racine "CA_spou_local.crt".
Sur Google Chrome, par exemple, il faut aller dans les paramètres, cliquer sur "paramètres avancés", cliquer sur "Gérer les certificats", cliquer sur le bouton "importer" et suivre les instructions. Il faut notamment cocher le bouton "Placer tous les certificats dans le magasin suivant", cliquer sur le bouton "Parcourir" et choisir le dossier "Autorités de certification racines de confiance" (il faut peut-être un compte utilisateur avec des droits d'administration sur le poste, sur Windows notamment, pour faire cela) et on redémarre le navigateur internet.
Nous allons maintenant configurer Apache pour servir ce site caché, pour cela on crée un fichier "/etc/apache2/sites-enabled/private.conf" dans lequel on peut mettre ce type de contenu :
<VirtualHost *:6666> ServerName www.spou.local ServerAlias spou.local ErrorLog "|$/usr/bin/tee -a ${APACHE_LOG_DIR}/error.log |/usr/bin/rotatelogs -l ${APACHE_LOG_DIR}/private/error-%Y-%m-%d.log 86400" CustomLog "|/usr/bin/rotatelogs -l ${APACHE_LOG_DIR}/private/access-%Y-%m-%d.log 86400" combined SetEnv HTTPS on DocumentRoot /var/www/private </VirtualHost>
Il faut créer le dossier "/var/log/apache2/private" pour les logs de ce site ainsi que le dossier "/var/www/private" qui lui contiendra les fichiers du site :
# sudo mkdir /var/log/apache2/private # sudo mkdir /var/www/private # sudo chown -R www-data:webadmin /var/log/apache2/private # sudo chmod -R g+rw /var/log/apache2/private # sudo chown -R www-data:webadmin /var/www/private # sudo chmod -R g+rw /var/www/private
Pour finir, on configure également Nginx, en ajoutant les lignes suivantes dans le fichier "/etc/nginx/sites-enabled/00-default-ssl.conf", le plus important étant de restreindre l'accès aux seules personnes qui se sont connectées via le VPN et qui se sont donc vu attribuer une adresse qui commence par "10.11.12" (à noter que l'on peut toujours ajouter une couche de sécurité supplémentaire en configurant un nom de domaine et/ou un nom d'hôte beaucoup moins évident sur le serveur DNS local du genre 4xf4.gloub1496kk3.local que seules des personnes initiées pourront vraiment connaitre) :
... server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name spou.local www.spou.local; ssl_certificate /etc/ssl/STAR_spou_local.fullchain; ssl_certificate_key /etc/ssl/STAR_spou_local.key; proxy_intercept_errors on; error_page 500 502 503 504 /custom_50x.html; location = /custom_50x.html { root /var/www/html; internal; } location / { allow 10.11.12.0/24; deny all; proxy_pass http://127.0.0.1:6667; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $host; } }
Il ne nous reste plus qu'à redémarrer les serveurs Apache et Nginx :
# sudo systemctl restart apache2 # sudo systemctl restart nginx
Commentaires