Objectifs d'apprentissage
À la fin de ce cours, l'apprenant peut :
- expliquer le principe d'un tunnel VPN (chiffrement, authentification, routage) ;
- comparer WireGuard, IPsec/IKEv2 et OpenVPN sur les critères de complexité, performance et cas d'usage ;
- lire une configuration WireGuard (
wg-quick, clés,AllowedIPs, persistance,PersistentKeepalive) ; - appliquer des durcissements SSH (authentification par clé,
sshd_config,~/.ssh/config,ssh-agent,ProxyJump, redirection de ports) ; - décider si SSH suffit pour un cas d'usage ou si un VPN client-serveur est préférable ;
- utiliser SSH pour rediriger un port local ou distant, ou créer une SOCKS proxy ;
- distinguer un bastion (jump host) d'un VPN ;
- organiser l'authentification forte (MFA, FIDO, certificats) au-dessus d'une authentification réseau ;
- configurer une journalisation et une surveillance minimales (fail2ban en mention).
Prérequis
- Terminal macOS, notions de réseau (adresses IP, ports, protocoles UDP/TCP), SSH de base (cours Réseau).
- Cours Chiffrement et cryptographie conseillé (clés asymétriques, signature, authentification).
- Cours Sécurité des systèmes pour le moindre privilège et les secrets.
- Aucune distribution Linux ni VPN client/serveur réel requis pour suivre les exemples.
Parcours et chapitres
1. Principes du tunneling VPN
Un tunnel VPN chiffre tout le trafic entre deux points (client et passerelle, ou site-à-site).
Primitive fondamentale : encapsuler un paquet dans un autre, chiffrer, envoyer, déchiffrer, extraire à l'arrivée.
Avantages : - Confidentialité en transit (eavesdropping réseau évité). - Authentification mutuelle (client et serveur se reconnaissent). - Intégrité (modification détectée grâce au chiffrement authentifié). - Routage sélectif (split tunneling possible : certaines destinations via VPN, autres en direct).
Limites : - Ne protège pas les données au repos (disque, sauvegarde). - Ne cache pas le fait qu'une connexion existe (métadonnées : qui parle à qui, volume). - Pas de subsstitut à une authentification utilisateur (MFA complémentaire recommandée).
Cryptokey routing (WireGuard) : chaque clé publique est associée à une plage d'adresses (AllowedIPs). Un paquet arrivant de cette plage avec cette clé est de facto authentifié.
2. WireGuard : minimalisme et simplicité
Concept : protocole léger, env. 4 000 lignes de code, basé sur cryptographie moderne (Noise, Curve25519, ChaCha20-Poly1305, BLAKE2s).
Quand l'utiliser : - Configuration serveur VPN sur Linux ou Windows. - Connexion client VPN rapide et stable. - Site-à-site privé (connexion entre deux réseaux d'une organisation). - Routage sécurisé sur internet non fiable.
Quand hésiter : - Besoin de rouler dès lundi sans étudier des cryptos modernes : OpenVPN plus établi. - Législation imposant des certificats X.509 : IKEv2 mieux accepté.
Génération des clés
WireGuard utilise des paires Curve25519 en base64 (32 octets = 44 caractères en base64).
Attention, effet notable. Cette commande peut écrire ou écraser un fichier. Lire le contexte, les droits et l’effet attendu indiqués après le bloc ; ne jamais l’exécuter sur un système réel sans validation, d’abord dans un environnement de test.
umask 077 && wg genkey > privatekey-client && wg pubkey < privatekey-client > publickey-clientBloc actif : la touche C copie la commande seule, sans invite ni sortie.
- Contexte : Terminal, dossier de test, aucune autre session SSH ouverte.
- Droits : utilisateur normal,
umask 077crée privatekey avec permissions 600 (lisible par propriétaire seul). - Effet : génère une paire aléatoire ; la clé privée ne doit jamais être partagée.
- Vérification :
ls -l privatekey-clientaffiche-rw-------;cat publickey-clientaffiche une chaîne base64 de 44 caractères. - Retour arrière : supprimer les deux fichiers.
La clé privée d'un client/serveur ne doit jamais : - Être envoyée sur le réseau. - Être partagée avec un autre client. - Être stockée en clair (si sensibilité élevée, chiffrer avec GPG).
Configuration WireGuard (wg-quick sur Linux)
Fichier /etc/wireguard/wg0.conf (synthétique, jamais sur serveur réel) :
[Interface]
PrivateKey = oJrw8O+z7YB... # base64 de la clé privée, 44 caractères
Address = 192.0.2.100/32
ListenPort = 51820
DNS = 203.0.113.5
[Peer]
PublicKey = gI6E... # clé publique du pair (serveur)
Endpoint = 203.0.113.1:51820
AllowedIPs = 192.0.2.0/24, 203.0.113.0/24
PersistentKeepalive = 25
Champs clés :
PrivateKey: base64 de la clé privée du client. N'accepte qu'une clé par interface.Address: adresse IP du client dans le tunnel (et masque). Peut être plusieurs avec virgules.ListenPort: port UDP d'écoute (si ce client reçoit des paquets ; optionnel pour client pur).DNS: serveur DNS à utiliser sur ce tunnel (optionnel, plateforme-dépendant).[Peer]: un pair (serveur ou autre client).PublicKey: clé publique du pair.Endpoint: IP:port du pair sur internet (absent si pair ne peut pas initier, ex. client derrière NAT).AllowedIPs: quels trafics sont envoyés via ce pair (CIDR, séparés par virgules). Exemple :0.0.0.0/0= tout le trafic (défaut). Important : routage entièrement basé sur cette clé, pas d'authentification par login.PersistentKeepalive: envoyer un keepalive chiffré toutes les N secondes. Recommandé pour clients derrière NAT/firewall ;0= désactivé (défaut). WireGuard official : 25 secondes est un compromis robuste.
Activation (lecture seule) :
Attention, effet notable. Cette commande peut s'exécuter avec des droits élevés. Lire le contexte, les droits et l’effet attendu indiqués après le bloc ; ne jamais l’exécuter sur un système réel sans validation, d’abord dans un environnement de test.
sudo wg-quick up wg0Bloc actif : la touche C copie la commande seule, sans invite ni sortie.
- Contexte : Terminal, fichier
/etc/wireguard/wg0.confprêt, utilisateur avecsudo. - Droits : création de l'interface réseau, modification des routes.
- Effet : crée l'interface virtuelle, attribue les adresses, lit les pairs de la config, établit le tunnel UDP.
- Vérification :
wg showaffiche l'interface, la clé publique dérivée, les pairs, les statistiques (paquets envoyés/reçus, dernier handshake). - Retour arrière :
sudo wg-quick down wg0supprime l'interface.
Lecture de l'état avec wg
wg showBloc actif : la touche C copie la commande seule, sans invite ni sortie.
Affiche (exemple fictif) :
interface: wg0 public key: bKWYZ8dq... private key: (hidden) listening port: 51820peer: gI6E3l1... endpoint: 203.0.113.1:51820 allowed ips: 192.0.2.0/24, 203.0.113.0/24 latest handshake: 45 seconds ago transfer: 1.2 MiB received, 845 KiB sent persistent keepalive: every 25 secondsLecture : - public key : clé publique de cette interface (dérivée de PrivateKey), jamais secrète. - peer: gI6E3l... : clé publique d'un pair identifié. - latest handshake : il y a combien de temps le tunnel s'est établi (< 2 min = sain ; > quelques heures = peut-être pas de trafic). - transfer : compteurs cumulatifs.
Split tunneling
Si on place 0.0.0.0/0 dans AllowedIPs, tout le trafic IP est envoyé par le tunnel (y compris vers ses propres ressources locales). Exemple plus réaliste :
AllowedIPs = 192.0.2.0/24, 198.51.100.0/24
Seul le trafic vers ces réseaux emprunte le tunnel ; le reste va en direct. Important pour les VPN d'entreprise où des ressources critiques doivent rester privées.
3. IPsec et IKEv2 (RFC 7296)
Concept : norme standardisée (STD 79, octobre 2014) pour établir et maintenir des tunnels chiffrés.
IKEv2 (Internet Key Exchange version 2) = protocole de négociation sur UDP 500 et 4500. ESP (Encapsulating Security Payload) = protocole de chiffrement au-dessus d'IP.
Quand l'utiliser : - Besoin d'interopérabilité (implémentations tierces, clients mobiles iOS/Android native). - Exigence légale/de conformité de certificats X.509. - Responsable infrastructure déjà familier avec les normes IETF.
Quand hésiter : - Configuration et dépannage plus complexes qu'OpenVPN. - Nécessite certificats (plus lourd à gérer que clés WireGuard).
Phases de negociation : 1. IKE_SA_INIT (non chiffré) : échange de paramètres, Diffie-Hellman. 2. IKE_AUTH (chiffré) : authentification mutuelle, création de la première Child SA (tunnel de données). 3. CREATE_CHILD_SA (maintenance) : rekeying, ajout de nouvelles connections.
NAT traversal : UDP 4500 pour paquets encapsulés quand NAT détecté.
Hors du cadre de ce cours : configuration détaillée d'IKEv2 sur un serveur (strongSwan, libreswan). Consulter la documentation des outils.
4. OpenVPN
Concept : logiciel et protocole propriétaire, mais ouvert (source disponible), flexible.
Quand l'utiliser : - Configuration VPN "classique" sur serveur Linux/Windows existant. - Beaucoup de documentation et d'outils graphiques (Tunnelblick sur macOS). - Authentication par certificats X.509 ou par username/password.
Quand hésiter : - Plus lourd à déployer et maintenir qu'une solution appliance simple.
Aspect chiffrement : TLS pour établir le canal de contrôle et d'authentification, puis paramètres de chiffrement de données (AES, ChaCha20) négociés.
Hors du cadre : installation et configuration OpenVPN. Consulter openvpn.net/community-resources/.
5. SSH : tunneling léger et polyvalent
SSH n'est pas un VPN complet, mais peut en jouer plusieurs rôles : - Redirection de port local (-L) : accès local à un service distant via tunnel SSH. - Redirection de port distant (-R) : exposer un service local sur un serveur distant. - SOCKS proxy (-D) : proxy dynamique SOCKS4/5 sur le poste client. - Jump host (-J) : accès via un hôte intermédiaire.
Avantages : - Léger (souvent déjà disponible). - Authentification par clé publique robuste. - Agent SSH pour gestion centralisée des clés.
Limites : - Pas de routage au niveau IP complet (ex. ping, DNS transparents). - Stateful : chaque session SSH doit rester active.
Authentification SSH par clé
Clés par défaut : Ed25519 (recommandé, 32 octets), ECDSA, RSA (3072 bits minimum).
ssh-keygen -t ed25519 -C "client-demo@example.test" -N "" -f ~/.ssh/id-demoBloc actif : la touche C copie la commande seule, sans invite ni sortie.
- Contexte : Terminal utilisateur, répertoire
~/.sshpréparé. - Droits : création de fichier dans le dossier personnel.
- Effet : génère
id-demo(clé privée) etid-demo.pub(clé publique).-N ""= pas de passphrase (à éviter en production ; ici démo jetable). - Vérification :
ls -l ~/.ssh/id-demo*affiche-rw-------pour la privée,-rw-r--r--pour la publique. - Retour arrière : supprimer les deux fichiers.
Distribution de la clé publique :
ssh-copy-id -i ~/.ssh/id-demo.pub -p 22 user@203.0.113.10Bloc actif : la touche C copie la commande seule, sans invite ni sortie.
Ajoute id-demo.pub à ~/.ssh/authorized_keys sur le serveur.
- Contexte : Terminal, mot de passe du compte
userrequis une seule fois. - Droits : write sur
authorized_keysdu compteusersur le serveur. - Effet : login par clé devient possible.
- Vérification :
ssh -i ~/.ssh/id-demo user@203.0.113.10ouvre une session sans mot de passe. - Retour arrière : retirer la ligne de
authorized_keyssur le serveur.
Gestion des clés avec ssh-agent et ~/.ssh/config
ssh-agent déverrouille une clé en mémoire, puis toute commande SSH utilise cette clé sans demander la passphrase.
eval $(ssh-agent)ssh-add ~/.ssh/id-demoBloc actif : la touche C copie la commande seule, sans invite ni sortie.
- Contexte : Terminal, clé
id-demoavec passphrase. - Droits : utilisateur normal.
- Effet :
ssh-agentdémarre (si non actif),ssh-addle demande passphrase une fois, agent la garde. - Vérification :
ssh-add -laffiche les clés chargées. - Retour arrière :
ssh-add -Dvide l'agent ;kill $SSH_AGENT_PIDarrête l'agent.
~/.ssh/config centralise la config par hôte :
Host bastion
HostName 203.0.113.1
User admin
Port 22
IdentityFile ~/.ssh/id-demo
IdentitiesOnly yes
StrictHostKeyChecking accept-new
Host interne
HostName 192.0.2.50
User app-user
ProxyJump bastion
IdentityFile ~/.ssh/id-interne
Clés : - Host : pattern (wildcards permis, ex. internal-*). - HostName : adresse réelle. - User : login par défaut. - Port : port SSH (défaut 22). - IdentityFile : quelle(s) clé(s) essayer (plusieurs lignes possibles). - IdentitiesOnly yes : utiliser seulement les clés listées, pas l'agent (utile si agent contient trop de clés). - StrictHostKeyChecking : yes (strict), accept-new (ajouter les nouvelles clés). - ProxyJump : tunnel via un autre hôte (equiv. de -J en CLI).
Lecture : première occurrence de chaque clé gagne ; ordre important (plus spécifique d'abord).
ssh interneBloc actif : la touche C copie la commande seule, sans invite ni sortie.
Ouvre une session SSH vers 192.0.2.50 : 1. Se connecte à bastion (203.0.113.1) avec admin et id-demo. 2. Établit un tunnel depuis interne via bastion. 3. Authentifie avec app-user et id-interne.
Redirection de ports
Local forward : accès local à un service distant.
ssh -L 3306:192.0.2.80:3306 bastionBloc actif : la touche C copie la commande seule, sans invite ni sortie.
- Contexte : Terminal.
- Droits : bind à localhost:3306 (ports < 1024 nécessitent sudo ; ici 3306 OK).
- Effet : SSH vers
bastion, puis écoute sur localhost:3306 ; tout ce qu'on envoie à localhost:3306 passe par le tunnel et sort viabastionvers 192.0.2.80:3306. - Vérification :
mysql -h 127.0.0.1 -P 3306se connecte au serveur MySQL via le tunnel. - Retour arrière : Ctrl-C sur la session SSH.
SOCKS proxy : proxy dynamique.
ssh -D 1080 bastionBloc actif : la touche C copie la commande seule, sans invite ni sortie.
Écoute sur localhost:1080 ; navigateur configuré pour SOCKS 5, localhost:1080. Tout le trafic HTTP passe par le tunnel SSH.
Durcissement de sshd_config (serveur SSH)
Fichier /etc/ssh/sshd_config sur le serveur (synthétique) :
Port 22
ListenAddress 203.0.113.1
Protocol 2
# Authentification
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
AuthenticationMethods publickey
MaxAuthTries 3
LoginGraceTime 60
# Accès
AllowUsers user1 user2
AllowGroups ssh-users
DenyUsers root
# Comportement
ClientAliveInterval 300
ClientAliveCountMax 3
AllowTcpForwarding yes
GatewayPorts no
X11Forwarding no
PermitTunnel no
LogLevel VERBOSE
Clés essentiels : - PasswordAuthentication no : pas de mot de passe (seules clés publiques acceptées). - PermitRootLogin no : root ne peut pas se connecter en SSH (utiliser un utilisateur normal + sudo). - AuthenticationMethods publickey : une seule méthode requise (ici clé publique ; sinon publickey,password pour exiger les deux). - MaxAuthTries 3 : 3 tentatives max avant déconnexion. - AllowUsers user1 user2 : seuls ces utilisateurs peuvent SSH (whitelist). - DenyUsers root : explicitement refuser root (redondant si PermitRootLogin no). - ClientAliveInterval 300 : envoyer un keepalive toutes les 5 min, fermer si pas de réponse après ClientAliveCountMax essais. - GatewayPorts no : forward distant (-R) lié à localhost seul, pas à toutes les interfaces. - X11Forwarding no : pas de forwarding X11 (sauf si nécessaire).
Rechargement après édition :
Attention, effet notable. Cette commande peut s'exécuter avec des droits élevés. Lire le contexte, les droits et l’effet attendu indiqués après le bloc ; ne jamais l’exécuter sur un système réel sans validation, d’abord dans un environnement de test.
sudo sshd -tBloc actif : la touche C copie la commande seule, sans invite ni sortie.
Teste la syntaxe sans redémarrer.
Attention, effet notable. Cette commande peut s'exécuter avec des droits élevés. Lire le contexte, les droits et l’effet attendu indiqués après le bloc ; ne jamais l’exécuter sur un système réel sans validation, d’abord dans un environnement de test.
sudo systemctl reload sshBloc actif : la touche C copie la commande seule, sans invite ni sortie.
Recharge la config (connexions existantes conservées).
- Contexte : Terminal avec
sudo, serveur SSH actif. - Droits : lecture
/etc/ssh/sshd_config. - Effet : sshd relit sa config (connecté ou non).
- Vérification :
sudo systemctl status sshousudo systemctl restart sshsi erreur. - Retour arrière : restaurer le fichier d'avant, relancer.
6. Bastions et accès sans port ouvert
Bastion (jump host) : serveur proxy d'accès.
Cas d'usage : serveurs internes sans accès SSH direct de l'internet. Les administrateurs se connectent via un bastion.
Internet → Bastion (SSH port 22 ouvert) → Serveur interne (SSH port 22, réseau privé)
Configuration SSH basique :
Host internal-server
HostName 192.0.2.50
ProxyJump admin@203.0.113.2:22
ProxyJump (SSH 7.3+) remplace ProxyCommand nc -X connect.
Accès sans port ouvert sur internet : Cloudflare Tunnel / Access.
WireGuard ou IPsec sont des tunnels bidirectionnels (serveur expose un port). Cloudflare Tunnel inverse le modèle : - Serveur interne établit une connexion sortante vers Cloudflare. - Utilisateurs accèdent via Cloudflare (leur accès est entrant sur Cloudflare, pas sur le serveur). - Le serveur n'expose aucun port sur internet.
Voir le cours Cloudflare (section Cloud) pour un détail.
7. Authentification forte et gestion des secrets
Un tunnel VPN ou SSH chiffre le trafic, mais n'authentifie que le serveur VPN/SSH lui-même.
Authentification utilisateur en sus : - Mot de passe fort (NIST : au moins 16 caractères, aléatoire). - MFA/2FA : code TOTP (Google Authenticator, Authy) ou FIDO2 (YubiKey, clé de sécurité). - Certificats X.509 : pour les services critiques (VPN entreprise).
Gestion des secrets : - Clé privée SSH/VPN jamais en clair sur le disque (chiffrer avec GPG ou stockage chauffeur macOS). - PGPASSWORD ou .pgpass jamais écrit en dur dans un script ; utiliser gpg-agent ou equivalent. - SSH keys : passphrases fortes + agents.
8. Journalisation et surveillance
WireGuard : - Peu de logs : WireGuard écrit dans syslog (Linux) ou Windows Event Log. - Monitoring : wg show périodiquement, alerter si latest handshake > seuil.
SSH : - LogLevel VERBOSE ou DEBUG en /etc/ssh/sshd_config pour enregistrer authentifications. - Logs : /var/log/auth.log (Debian/Ubuntu) ou /var/log/secure (RHEL). - Fail2ban : tarte à la crème, lire des logs SSH, bloquer les IP après N échecs.
Exemple fail2ban (mention) : crée des règles iptables pour bannir une IP après 5 tentatives échouées en 10 min.
Hors du cadre : configuration complète de fail2ban.
9. Comparaison résumée
| Critère | WireGuard | IPsec/IKEv2 | OpenVPN | SSH |
|---|---|---|---|---|
| Code | ~4k lignes | Complexe (RFC) | ~10k lignes | ~25k lignes |
| Performances | Excellent | Bon | Bon | Moyen (overhead SSH) |
| Setup | Simple | Moyen (certs) | Moyen | Très simple (clés) |
| Interop | Croissante | Excellente | Excellente | Universelle |
| Cas idéal | Site-à-site, VPN léger | Entreprise, certs | Historique, souplesse | Jump host, redirection |
| Quand l'utiliser | Défaut sauf constraints | Exigence légale | Si autre solution trop lourde | Accès basique, redirection |
Exercices et vérifications
- Générer une paire WireGuard :
wg genkey | tee privatekey | wg pubkey; vérifier la taille (base64 44 caractères). - SSH via jump host : configurer
~/.ssh/configavecProxyJump; test. - Port forwarding SSH :
-Lvers un service non accessible directement ; vérifier qu'il répond. - Bastions conceptuel : dessiner un diagramme réseau avec un bastion. Quelles données passent par le bastion ? (Réponse : toutes les données SSH, donc tout si tout passe par SSH.)
- Configuration sshd : lire
/etc/ssh/sshd_configd'une machine existante (macOS préféré) ; identifier les paramètres non standard. - WireGuard en lecture : si WireGuard installé,
wg show; interpréterlatest handshakeettransfer. - Durcissement mental : quels paramètres sshd empêcheraient votre utilisateur normal de se connecter ? (Ex. AllowUsers incorrect.)
- Fail2ban concept : expliquer comment fail2ban détecte une attaque par force brute SSH. (Réponse : nombre d'authentifications échouées en N secondes.)
- Split tunneling : donner un
AllowedIPsqui force seul le trafic vers le serveur DNS via WireGuard. (Réponse :203.0.113.5/32si c'est le DNS.) - Certificats vs clés : quand préferer certificats X.509 (IKEv2) à des clés WireGuard ? (Réponse : révocation, déploiement massif, loi, interop.)
Points non vérifiés ou à confirmer
- Versions macOS, OpenSSH, WireGuard de Stéphane : inconnues.
- Availability de WireGuard sur les distributions Linux cibles : non confirmée.
- Strongswan, libreswan ou autre implémentation IPsec préférée : non décidé.
- Configuration détaillée de fail2ban : hors cadre, pages non consultées.
- OpenVPN détails (tls-crypt, overhead, mode tun vs tap) : pages non consultées (OpenVPN 2.6+).
- SSH ControlMaster, SOCKS profond : non couverts ici.
- Certificats X.509 pour SSH (
ssh-keygen -s,cert-authority) : non couverts. - FIDO sur SSH (ed25519-sk, ecdsa-sk) : non couverts.
- Intégration Kerberos/LDAP avec SSH : non couverte.
- Logique de
known_hostset host key verification : résumé seulement. - Architecture et sécurité de Cloudflare Tunnel/Access : voir cours Cloudflare.
Sources officielles
Consultées le 18 octobre 2026.