Contexte : Relier 2 sites distants via VPN sécurisé (WireGuard / IPsec) avec communication inter-VLAN.
| Site | VLAN | Réseau | Passerelle | Client test |
|---|---|---|---|---|
| SITE A (Paris) | VLAN 10 (ADMIN) | 10.0.10.0/24 | 10.0.10.254 | 10.0.10.10 |
| VLAN 20 (USERS) | 10.0.20.0/24 | 10.0.20.254 | 10.0.20.10 | |
| VLAN 30 (GUEST) | 10.0.30.0/24 | 10.0.30.254 | 10.0.30.10 | |
| SITE B (Lyon) | VLAN 10 (ADMIN) | 10.1.10.0/24 | 10.1.10.254 | 10.1.10.10 |
| VLAN 20 (USERS) | 10.1.20.0/24 | 10.1.20.254 | 10.1.20.10 | |
| VLAN 30 (GUEST) | 10.1.30.0/24 | 10.1.30.254 | 10.1.30.10 |
# Installation WireGuard sudo apt update && sudo apt install wireguard resolvconf -y # Génération des clés cd /etc/wireguard/ sudo umask 077 sudo wg genkey | tee privatekey | sudo wg pubkey > publickey # Afficher les clés (à conserver précieusement) echo "=== PRIVATE KEY (À GARDER SECRET) ===" sudo cat privatekey echo "" echo "=== PUBLIC KEY (À PARTAGER AVEC SITE B) ===" sudo cat publickey
# Même procédure sur Site B cd /etc/wireguard/ sudo umask 077 sudo wg genkey | tee privatekey | sudo wg pubkey > publickey echo "=== PUBLIC KEY (À PARTAGER AVEC SITE A) ===" sudo cat publickey
[Interface] PrivateKey =Address = 10.255.0.1/30 ListenPort = 51820 MTU = 1420 # Routage IP et iptables PostUp = sysctl -w net.ipv4.ip_forward=1 PostUp = iptables -A FORWARD -i wg0 -j ACCEPT PostUp = iptables -t nat -A POSTROUTING -s 10.0.0.0/16 -o wg0 -j MASQUERADE PostDown = iptables -D FORWARD -i wg0 -j ACCEPT PostDown = iptables -t nat -D POSTROUTING -s 10.0.0.0/16 -o wg0 -j MASQUERADE [Peer] PublicKey = AllowedIPs = 10.1.0.0/16, 10.255.0.2/32 Endpoint = :51820 PersistentKeepalive = 25
[Interface] PrivateKey =Address = 10.255.0.2/30 ListenPort = 51820 MTU = 1420 PostUp = sysctl -w net.ipv4.ip_forward=1 PostUp = iptables -A FORWARD -i wg0 -j ACCEPT PostUp = iptables -t nat -A POSTROUTING -s 10.1.0.0/16 -o wg0 -j MASQUERADE PostDown = iptables -D FORWARD -i wg0 -j ACCEPT PostDown = iptables -t nat -D POSTROUTING -s 10.1.0.0/16 -o wg0 -j MASQUERADE [Peer] PublicKey = AllowedIPs = 10.0.0.0/16, 10.255.0.1/32 Endpoint = :51820 PersistentKeepalive = 25
# Sur les deux sites sudo systemctl enable wg-quick@wg0 sudo systemctl start wg-quick@wg0 # Vérifier l'état du tunnel sudo wg show # Tester la connexion tunnel ping 10.255.0.2 # Depuis Site A vers le tunnel Site B
sudo apt install strongswan strongswan-pki libcharon-extra-plugins -y # Configuration NAT-Traversal echo "net.ipv4.conf.all.forwarding=1" >> /etc/sysctl.conf sysctl -p
config setup
charondebug="ike 2, knl 2, cfg 2"
uniqueids=no
conn site-to-site
auto=start
keyexchange=ikev2
authby=secret
type=tunnel
left=192.168.1.1
leftsubnet=10.0.0.0/16
right=192.168.2.1
rightsubnet=10.1.0.0/16
ike=aes256-sha256-modp2048!
esp=aes256-sha256!
ikelifetime=86400s
keylife=3600s
dpddelay=30s
dpdtimeout=120s
dpdaction=restart
192.168.1.1 192.168.2.1 : PSK "mot_de_passe_tres_long_et_securise_avec_au_moins_32_caracteres"
sudo systemctl restart strongswan sudo ipsec statusall
config vpn ipsec phase1-interface
edit "VPN-S2S"
set interface "wan1"
set ike-version 2
set peertype any
set proposal aes256-sha256
set remote-gw 192.168.2.1
set psksecret "mot_de_passe_securise"
set localid "Paris"
set remoteid "Lyon"
next
end
config vpn ipsec phase2-interface
edit "VPN-S2S-P2"
set phase1name "VPN-S2S"
set proposal aes256-sha256
set src-addr-type name
set src-name "LAN_A"
set dst-name "LAN_B"
next
end
config firewall policy
edit 10
set name "VPN-Out"
set srcintf "internal"
set dstintf "VPN-S2S"
set srcaddr "LAN_A"
set dstaddr "LAN_B"
set action accept
set schedule "always"
set service "ALL"
next
edit 11
set name "VPN-In"
set srcintf "VPN-S2S"
set dstintf "internal"
set srcaddr "LAN_B"
set dstaddr "LAN_A"
set action accept
next
end
# VPN → WireGuard → Tunnels # Interface: WAN, Listen Port: 51820, MTU: 1420 # Tunnel Address: 10.255.0.1/30 # VPN → WireGuard → Peers (ajouter site B) # Public Key: (clé publique de l'autre site) # Endpoint: IP_publique_B:51820 # AllowedIPs: 10.1.0.0/16, 10.255.0.2/32 # Firewall → Rules → WG # Action: Pass, Protocol: any, Source: any, Destination: any # System → Routing → Static Routes # Destination: 10.1.0.0/16, Gateway: 10.255.0.2 # Destination: 10.255.0.0/30, Gateway: 10.255.0.2
# Sur Linux sudo ip route add 10.1.0.0/16 via 10.255.0.2 dev wg0 # Pour persistance (Ubuntu/Debian) echo "up route add -net 10.1.0.0 netmask 255.255.0.0 gw 10.255.0.2 dev wg0" | sudo tee -a /etc/network/interfaces # Sur pfSense # System → Routing → Static Routes # Destination: 10.1.0.0/16, Gateway: 10.255.0.2 # Sur FortiGate # config router static # edit 10 # set dst 10.1.0.0 255.255.0.0 # set gateway 10.255.0.2 # set device "VPN-S2S" # next # end
# Sur Linux sudo ip route add 10.0.0.0/16 via 10.255.0.1 dev wg0 # Pour persistance echo "up route add -net 10.0.0.0 netmask 255.255.0.0 gw 10.255.0.1 dev wg0" | sudo tee -a /etc/network/interfaces
| Source | Destination | Action | Justification |
|---|---|---|---|
| VLAN 10 (ADMIN) Site A | VLAN 10 (ADMIN) Site B | ✅ AUTORISÉ | Admins peuvent communiquer |
| VLAN 20 (USERS) Site A | VLAN 20 (USERS) Site B | ❌ BLOQUÉ | Users ne traversent pas le VPN |
| VLAN 10 (ADMIN) Site A | VLAN 20 (USERS) Site B | ❌ BLOQUÉ | Isolation inter-VLAN |
| VLAN 30 (GUEST) | Tout site distant | ❌ BLOQUÉ | Invités n’ont pas accès au VPN |
# Exemple: Autoriser uniquement VLAN10 (Admin) entre les sites # Sur Site A (Paris) - autoriser le trafic depuis VLAN10 vers Site B iptables -A FORWARD -i vlan10 -o wg0 -d 10.1.0.0/16 -j ACCEPT iptables -A FORWARD -i wg0 -o vlan10 -s 10.1.0.0/16 -j ACCEPT # Bloque tout autre trafic VPN par défaut iptables -A FORWARD -i wg0 -j DROP iptables -A FORWARD -o wg0 -j DROP
Ces livrables servent à valider et documenter une configuration exploitable en PME. Cliquez sur chaque bouton pour copier le contenu.
Topologie 2 sites avec pfSense et WireGuard pré-configuré.
{
"name": "TP_VPN_SiteToSite",
"version": "2.2.0",
"topology": {
"nodes": [
{"node_id": "siteA-fw", "name": "pfSense_Paris", "node_type": "qemu", "x": 0, "y": 200, "properties": {"image": "pfSense-2.6.0.iso", "ram": 1024}},
{"node_id": "siteB-fw", "name": "pfSense_Lyon", "node_type": "qemu", "x": 800, "y": 200, "properties": {"image": "pfSense-2.6.0.iso", "ram": 1024}},
{"node_id": "siteA-pc1", "name": "ADMIN_Paris", "node_type": "vpcs", "x": -150, "y": 100, "properties": {"script": "ip 10.0.10.10/24 10.0.10.254"}},
{"node_id": "siteA-pc2", "name": "USERS_Paris", "node_type": "vpcs", "x": -150, "y": 200, "properties": {"script": "ip 10.0.20.10/24 10.0.20.254"}},
{"node_id": "siteB-pc1", "name": "ADMIN_Lyon", "node_type": "vpcs", "x": 950, "y": 100, "properties": {"script": "ip 10.1.10.10/24 10.1.10.254"}},
{"node_id": "siteB-pc2", "name": "USERS_Lyon", "node_type": "vpcs", "x": 950, "y": 200, "properties": {"script": "ip 10.1.20.10/24 10.1.20.254"}},
{"node_id": "switch-net", "name": "Cloud_Internet", "node_type": "ethernet_switch", "x": 400, "y": 200}
],
"links": [
{"nodes": [{"node_id": "siteA-fw","port":2},{"node_id": "switch-net","port":1}]},
{"nodes": [{"node_id": "siteB-fw","port":2},{"node_id": "switch-net","port":2}]}
]
}
}
Testeur VPN : ping inter-sites, mesure débit/perte via iperf3, génération rapport.
Installation : pip install colorama iperf3
Utilisation : python3 vpn_tester.py --menu
#!/usr/bin/env python3
# vpn_tester.py - Testeur de VPN site-à-site
import subprocess, sys, argparse, time
from datetime import datetime
try:
from colorama import init, Fore, Style
init()
except:
class Fore: RED=GREEN=YELLOW=CYAN=RESET=''
class VPNTester:
def __init__(self):
self.results = []
self.config = {
"tunnel_ip": "10.255.0.2",
"remote_admin": "10.1.10.10",
"tests": [
{"name": "Test ping tunnel VPN", "ip": "10.255.0.2", "expected": "ALLOW"},
{"name": "Test ping ADMIN Site A → Site B", "ip": "10.1.10.10", "expected": "ALLOW"},
{"name": "Test ping USERS Site A → Site B", "ip": "10.1.20.10", "expected": "BLOCK"},
{"name": "Test ping ADMIN Site B → Site A", "ip": "10.0.10.10", "expected": "ALLOW"}
]
}
def ping(self, ip, count=3):
param = '-n' if sys.platform.lower().startswith('win') else '-c'
try:
r = subprocess.run(['ping', param, str(count), '-W', '2', ip], capture_output=True, text=True)
success = r.returncode == 0
# Extraire le temps moyen
if success:
import re
match = re.search(r'time[= ]+(\d+(?:\.\d+)?)', r.stdout)
latency = match.group(1) if match else "N/A"
else:
latency = "N/A"
return success, latency
except:
return False, "N/A"
def iperf_test(self, server_ip, duration=5):
"""Test débit via iperf3 (nécessite serveur iperf3 sur la cible)"""
try:
result = subprocess.run(['iperf3', '-c', server_ip, '-t', str(duration)], capture_output=True, text=True, timeout=duration+5)
if result.returncode == 0:
import re
match = re.search(r'([\d\.]+) (Mbits/sec|Gbits/sec|\wbits/sec)', result.stdout)
if match:
return f"{match.group(1)} {match.group(2)}"
return "N/A"
except:
return "N/A"
def run(self):
print(f"{Fore.CYAN}🔍 Test du tunnel VPN...{Fore.RESET}\n")
print(f"📅 {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
for t in self.config["tests"]:
success, latency = self.ping(t["ip"])
passed = (success and t["expected"] == "ALLOW") or (not success and t["expected"] == "BLOCK")
self.results.append({**t, "actual": success, "latency": latency, "passed": passed})
status = f"{Fore.GREEN}✓{Fore.RESET}" if passed else f"{Fore.RED}✗{Fore.RESET}"
result_text = f"{latency}ms" if success else "TIMEOUT"
print(f"{status} {t['name']}: {result_text} (attendu: {t['expected']})")
# Test débit
print(f"\n{Fore.CYAN}📊 Test de débit (iperf3)...{Fore.RESET}")
bandwidth = self.iperf_test(self.config["tunnel_ip"])
print(f" Débit tunnel VPN: {bandwidth}")
return self.results
def html_report(self, filename="vpn_report.html"):
passed = sum(1 for r in self.results if r['passed'])
total = len(self.results)
score = (passed/total)*100 if total>0 else 0
html = f"""TP 3 — VPN site‑à‑site PME | CyberRéseau Pro
📊 Rapport VPN Site-à-Site
Date: {datetime.now()}
Score: {score:.1f}% ({passed}/{total})
| Test | IP | Attendu | Réel | Latence | Statut |
|---|---|---|---|---|---|
| {r['name']} | {r['ip']} | {r['expected']} | {'SUCCÈS' if r['actual'] else 'ÉCHEC'} | {r['latency']} | " html += f"{'✅ OK' if r['passed'] else '❌ ÉCHEC'} |
Généré par VPN Tester | CyberRéseau Pro
" with open(filename, 'w', encoding='utf-8') as f: f.write(html) print(f"{Fore.GREEN}📄 Rapport généré: {filename}{Fore.RESET}") def menu(self): while True: print(f"\n{Fore.CYAN}════════════════════════════════════════╗{Fore.RESET}") print(f"{Fore.CYAN} TESTEUR VPN SITE-À-SITE{Fore.RESET}") print(f"{Fore.CYAN}════════════════════════════════════════╝{Fore.RESET}") print("1. 🔍 Lancer les tests") print("2. 📄 Générer rapport HTML") print("3. 🚪 Quitter") choice = input(f"{Fore.YELLOW}Votre choix : {Fore.RESET}") if choice == '1': self.run() elif choice == '2': if self.results: self.html_report() else: print("Lancez d'abord les tests") elif choice == '3': break if __name__ == "__main__": tester = VPNTester() if len(sys.argv) > 1 and '--menu' in sys.argv: tester.menu() else: tester.run() tester.html_report()Diagnostic VPN : état tunnel, logs, performances, checklist.
Utilisation : chmod +x diagnostic_vpn.sh && ./diagnostic_vpn.sh --all
#!/bin/bash
RAPPORT="vpn_diag_$(date +%Y%m%d_%H%M%S).txt"
GREEN='\033[0;32m'; RED='\033[0;31m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m'
log() { echo -e "$1" | tee -a "$RAPPORT"; }
log_header() { echo ""; log "${CYAN}═══════════════════════════════════════${NC}"; log "$1"; log "${CYAN}═══════════════════════════════════════${NC}"; }
check_wireguard() {
log_header "État WireGuard"
if command -v wg &>/dev/null; then
wg show | tee -a "$RAPPORT"
else
log "WireGuard non installé"
fi
}
check_ipsec() {
log_header "État IPsec"
if command -v ipsec &>/dev/null; then
ipsec statusall 2>/dev/null | head -30 | tee -a "$RAPPORT"
else
log "IPsec non installé"
fi
}
test_connectivity() {
log_header "Tests de connectivité VPN"
local tests=(
"Tunnel VPN:10.255.0.2"
"ADMIN Site B:10.1.10.10"
"USERS Site B:10.1.20.10"
)
for test in "${tests[@]}"; do
name="${test%:*}"
ip="${test#*:}"
if ping -c 2 -W 2 "$ip" &>/dev/null; then
log "${GREEN}✅ $name: SUCCÈS${NC}"
else
log "${RED}❌ $name: ÉCHEC${NC}"
fi
done
}
check_routes() {
log_header "Routes VPN"
ip route show | grep -E "10\.|wg|tun" | tee -a "$RAPPORT"
}
check_mtu() {
log_header "Vérification MTU"
log "=== MTU actuel ==="
ip link show wg0 2>/dev/null | grep mtu | tee -a "$RAPPORT"
log ""
log "=== Test MTU optimal ==="
for mtu in 1500 1450 1420 1400; do
if ping -M do -s $(($mtu - 28)) -c 1 -W 1 10.255.0.2 &>/dev/null 2>&1; then
log "${GREEN}✓ MTU $mtu fonctionne${NC}"
break
else
log "✗ MTU $mtu échoue"
fi
done
}
checklist() {
log_header "CHECKLIST VPN SITE-À-SITE"
cat >> "$RAPPORT" << 'EOF'
□ 1. WireGuard/IPsec installé sur les deux sites
□ 2. Clés publiques échangées entre sites
□ 3. Fichier de configuration complet
□ 4. Port UDP 51820 ouvert sur les firewalls
□ 5. Tunnel actif (wg show / ipsec statusall)
□ 6. Routage statique configuré (route add)
□ 7. IP forwarding activé (sysctl net.ipv4.ip_forward=1)
□ 8. Règles iptables acceptent le trafic VPN
□ 9. Ping inter-sites fonctionnel
□ 10. MTU correctement ajusté si nécessaire
EOF
cat "$RAPPORT" | tail -15
}
auto_mode() {
log_header "DIAGNOSTIC VPN AUTOMATIQUE"
check_wireguard
check_ipsec
check_routes
test_connectivity
check_mtu
checklist
echo -e "${GREEN}✓ Rapport sauvegardé: $RAPPORT${NC}"
}
show_menu() {
echo ""; echo -e "${CYAN}═══════════════════════════════════════${NC}"
echo -e " DIAGNOSTIC VPN SITE-À-SITE"
echo -e "${CYAN}═══════════════════════════════════════${NC}"
echo "1. 🔍 Diagnostic complet"
echo "2. 🔐 Vérifier WireGuard/IPsec"
echo "3. 🌐 Tester connectivité"
echo "4. 📋 Afficher checklist"
echo "5. 🚪 Quitter"
echo -n "Votre choix : "
}
if [ "$1" == "--all" ] || [ "$1" == "-a" ]; then
auto_mode
else
while true; do
show_menu; read choice
case $choice in
1) auto_mode ;;
2) check_wireguard; check_ipsec ;;
3) test_connectivity ;;
4) checklist ;;
5) echo -e "${GREEN}Au revoir !${NC}"; exit 0 ;;
*) echo -e "${RED}Choix invalide${NC}" ;;
esac
done
fi
# 1. Rendre les scripts exécutables
chmod +x vpn_tester.py
chmod +x diagnostic_vpn.sh
# 2. Installer les dépendances Python
pip3 install colorama iperf3
# 3. Lancer le test interactif
python3 vpn_tester.py --menu
# 4. Lancer le diagnostic bash
./diagnostic_vpn.sh --all
# 5. Vérifier l'état du tunnel
wg show
# ou
ipsec statusall
# 6. Tester le routage
traceroute 10.1.10.10
| Erreur | Pourquoi ? | Solution |
|---|---|---|
| Handshake ne s'établit pas | Port fermé / clés erronées / IP endpoint | Vérifier ports ouverts, endpoint IP, clés (wg show) |
| Ping OK mais pas les flux applicatifs | AllowedIPs ou routage manquant | AllowedIPs + routage statique dans chaque firewall |
| Débit faible / pertes paquets | MTU trop élevé | Réduire MTU à 1400 ou 1420 sur l'interface tunnel |
| VPN se coupe après inactivité | Keepalive manquant | Ajouter PersistentKeepalive = 25 dans la section Peer |
| FortiGate : Phase 1 OK, Phase 2 KO | Proposal mismatch | Vérifier que Phase2 utilise les mêmes paramètres que Phase1 |
| # | Test | Commande | Résultat attendu |
|---|---|---|---|
| 1 | Ping tunnel VPN | ping 10.255.0.2 | ✅ SUCCÈS |
| 2 | Ping Site A → Site B (ADMIN) | ping 10.1.10.10 | ✅ SUCCÈS |
| 3 | Ping Site A → Site B (USERS) | ping 10.1.20.10 | ❌ ÉCHEC (si filtré) |
| 4 | Ping Site B → Site A (ADMIN) | ping 10.0.10.10 | ✅ SUCCÈS |
| 5 | Test débit tunnel | iperf3 -c 10.255.0.2 | Débit > 10 Mbps |
| 6 | Test pertes paquets | ping -c 100 10.255.0.2 | Perte < 1% |
| 7 | Traceroute Site A → Site B | traceroute 10.1.10.10 | Passe par 10.255.0.2 |
wg show montre "latest handshake: none"# Vérifier l'état sudo wg show sudo journalctl -u wg-quick@wg0 -f # Vérifier que les clés correspondent # Sur Site A, la clé publique du peer doit être = clé privée de Site B # Sur Site B, clé publique du peer = clé privée de Site A # Vérifier les ports ouverts sudo netstat -tulpn | grep 51820 # Sur le firewall, autoriser UDP 51820
# Vérifier le routage ip route show | grep -E "10\.1|10\.0" # Vérifier les règles iptables au niveau applicatif iptables -L FORWARD -v -n iptables -t nat -L POSTROUTING -v -n # Ajouter des règles si nécessaire iptables -A FORWARD -p tcp --dport 80 -j ACCEPT
# Réduire MTU sur l'interface wg0 sudo ip link set dev wg0 mtu 1400 # Tester avec ping de taille fixe ping -M do -s 1472 -c 3 10.255.0.2 # Test MTU 1500 ping -M do -s 1392 -c 3 10.255.0.2 # Test MTU 1420 # Dans /etc/wireguard/wg0.conf MTU = 1400
diagnose vpn ike log-filter dst-addr4 192.168.2.1 diagnose debug application ike -1 diagnose debug enable # Voir les logs diagnose debug application ike 5
#!/bin/bash echo "=== DIAGNOSTIC VPN RAPIDE ===" echo "1. État WireGuard" wg show echo "" echo "2. Routes" ip route show | grep -E "10\.|wg" echo "" echo "3. iptables FORWARD" iptables -L FORWARD -v -n | head -20 echo "" echo "4. Tests ping" ping -c 2 10.255.0.2 && echo "✅ Tunnel OK" || echo "❌ Tunnel KO" ping -c 2 10.1.10.10 && echo "✅ Site B ADMIN OK" || echo "❌ Site B ADMIN KO" echo "=== Diagnostic terminé ==="
Ces liens correspondent au matériel utile pour reproduire ce TP en conditions réelles.
🔗 Liens affiliés Amazon — aucun surcoût pour vous.
Ce module fait partie du Pack TP Sécurité Réseau : VLAN, firewall, VPN, Wi‑Fi sécurisé et 802.1X. L’objectif est de passer d’une configuration isolée à une démarche complète de sécurisation PME.
Voir tout le Pack TP Télécharger le guide gratuitAvant de considérer ce module comme exploitable, vérifiez les points suivants :
Ce module fait partie du Pack TP Sécurité Réseau PME. Remplacez le lien ci-dessous par votre lien Gumroad après publication.
Acheter / télécharger le pack Voir la page du pack