VPN de bureau : autoriser l’accès à un seul serveur/port (moindre privilège)

Cet article vous a aidé ?

Le VPN du bureau fonctionne. Tout le monde est content. Jusqu’à ce que quelqu’un découvre que « l’accès VPN » équivaut essentiellement à « une autoroute privée vers tout le réseau d’entreprise ».
Puis vous recevez le message à minuit : « Pourquoi le prestataire peut-il accéder à la base de données ? » et vous réalisez que vous avez construit un tunnel, pas une rambarde.

L’objectif ici est brutalement simple : une fois qu’un utilisateur se connecte au VPN, il doit pouvoir atteindre exactement un serveur sur exactement un port.
Pas « idéalement ». Pas « à moins qu’il ne connaisse le sous‑réseau ». Exactement. Tout le reste est un accident qui attend une invitation au calendrier.

Ce que « un seul serveur/port » signifie réellement

Le moindre privilège sur un VPN n’est pas « les utilisateurs ne voient que le sous‑réseau dont ils ont besoin ». C’est une fiction polie.
Les sous‑réseaux servent au routage ; les privilèges servent à la sécurité.
Quand vous dites « un seul serveur/port », vous dites en réalité :

  • Le client VPN reçoit une IP (ou pas), mais le routage seul n’est pas digne de confiance pour faire respecter quoi que ce soit.
  • La passerelle VPN et/ou le serveur cible applique des règles d’autorisation et refuse par défaut.
  • Toutes les autres destinations et ports sont bloqués, y compris les services « internes » comme DNS, SMB, SSH, RDP et les points de métriques.
  • Il existe de l’observabilité : logs, compteurs et moyen de prouver ce qui a été bloqué et pourquoi.

L’anti‑patron est « nous ne poussons qu’une route ». Ce n’est pas du moindre privilège ; c’est une suggestion. Si le client peut ajouter des routes manuellement,
ou s’il y a de la NAT, ou une seconde interface sur la machine VPN, vous aurez des connexions surprises.

Un design solide implique généralement deux plans de contrôle :
(1) contrôles réseau (pare‑feu/routage à l’entrée VPN), et
(2) contrôles de service (pare‑feu/authentification applicative sur la destination).
Si vous n’en faites qu’un, vous apprendrez tôt ou tard pourquoi les gens font l’autre.

Faits intéressants et un peu d’histoire

  • Les VPN n’ont pas été conçus comme des outils zero‑trust. La pensée VPN d’entreprise initiale considérait « à l’intérieur du tunnel » comme « à l’intérieur du bureau ». Cette hypothèse a mal vieilli.
  • IPsec précède beaucoup d’habitudes de sécurité d’entreprise modernes. Il vient d’une époque où les pare‑feu périmétriques faisaient la loi, pas la segmentation interne.
  • Le split tunneling a toujours été controversé. Il réduit la charge sur le réseau d’entreprise, mais crée aussi des points de confiance mixtes (Wi‑Fi domestique + tunnel corp.).
  • Les pare‑feu ont appris la notion d’état pour résoudre une vraie douleur. Les ACLs sans état rendaient « autoriser TCP/443 » délicat sans aussi autoriser le trafic de réponse ; le suivi d’état a corrigé cela.
  • « Utilisateur VPN = utilisateur réseau » est un raccourci historique. C’était pratique opérationnellement quand les systèmes d’identité étaient plus simples et le travail à distance exceptionnel.
  • La conception de WireGuard est remarquablement concise. Son minimalisme a facilité les audits et le déploiement comparé aux stacks VPN tentaculaires, et cela a changé les choix par défaut.
  • La NAT est devenue un béquille de sécurité. On l’a traitée comme de l’isolation ; ce n’en est pas. C’est de la traduction d’adresses, pas de l’autorisation.
  • La micro‑segmentation n’a pas commencé dans le cloud. Les datacenters l’ont faite avec VLANs et ACLs bien avant que « zero trust » ne devienne un mot à la mode.

Modèle de menace : ce que vous empêchez (et ce que vous n’empêchez pas)

Vous essayez d’empêcher le mouvement latéral depuis un client VPN vers le reste du réseau. Cela inclut :

  • Scans de ports sur des plages internes (« juste vérifier ce qu’il y a »).
  • Atteindre des surfaces d’administration : SSH, RDP, consoles type vCenter, BMC, gestion NAS, imprimantes (oui), et tout ce qui a une interface web.
  • Utiliser le DNS interne pour découvrir des noms que vous n’aviez pas l’intention de publier.
  • Accès aux services de métadonnées, registres internes ou points de monitoring qui divulguent topologie et identifiants.

Vous ne résolvez pas :

  • Les identifiants compromis pour le service autorisé. (Vous avez toujours besoin d’une authentification forte là‑dessus.)
  • Le malware sur l’endpoint qui exfiltre des données via le port autorisé. (Il faut DLP/monitoring et des contrôles côté applicatif.)
  • L’inspection du trafic en profondeur au niveau du contenu. (C’est un système séparé, avec ses propres coûts opérationnels.)

Une citation pour garder votre posture honnête. Comme Bruce Schneier l’a dit : La sécurité est un processus, pas un produit. Vous ne « configurez le moindre privilège » qu’une seule fois.
Vous le maintenez moindre‑privilège pendant que les besoins évoluent et que le personnel tourne.

Petite blague #1 : Si vous autorisez « tout l’interne » depuis le VPN, vous ne faites pas de la sécurité — vous faites du cosplay de bureau à distance.

Trois schémas qui fonctionnent vraiment

Schéma A : la passerelle VPN applique une liste d’autorisation stricte (le plus courant)

Le concentrateur VPN (ou la machine Linux exécutant WireGuard/OpenVPN) agit comme point d’étranglement. Les clients VPN atterrissent sur une interface/sous‑réseau dédié.
Une politique de pare‑feu dit : depuis le sous‑réseau VPN → autoriser vers target_ip:target_port, refuser tout le reste.

Avantages : modèle mental simple, contrôle centralisé, bons logs. Inconvénients : si la passerelle est mal configurée ou contournée (chemins dual‑homés, hairpinning),
vous pouvez ouvrir accidentellement plus que prévu.

Schéma B : pas d’accès réseau général ; publier un seul service via un proxy

Au lieu de laisser les clients VPN atteindre le serveur cible directement, vous exposez le service via un reverse proxy (pour HTTP/HTTPS) ou un proxy TCP
(pour le non‑HTTP). Le client VPN ne peut atteindre que le proxy ; seul le proxy peut atteindre la cible.

Avantages : contrôles au niveau applicatif, meilleure intégration d’identité, audit plus simple. Inconvénients : vous ajoutez un saut et une chose de plus à maintenir.

Schéma C : placer la cible dans un « réseau de services VPN » dédié

Créez un segment isolé (VLAN/VRF) où réside le serveur cible, avec des règles d’ingress strictes. Les clients VPN ne peuvent router que vers ce segment,
et ce segment ne peut pas router largement vers l’extérieur.

Avantages : forte réduction de l’aire de propagation. Inconvénients : plus d’ingénierie réseau, et il est facile de se tromper sur le routage du chemin de retour et d’accuser « le VPN ».

Mon avis tranché : Schéma A plus restrictions côté serveur est la base. Si vous pouvez faire le Schéma B sans faire pleurer l’équipe applicative, faites‑le.
Le Schéma C est excellent quand vous avez une vraie infrastructure réseau et une discipline de contrôle des changements.

Implémentation : WireGuard + pare‑feu (recommandé)

WireGuard est populaire parce qu’il est simple à exploiter. Mais WireGuard lui‑même n’est pas un moteur de contrôle d’accès.
AllowedIPs est avant tout un concept de routage/sélection de pair, pas une « politique de sécurité qu’on ne peut pas contourner ».
Traitez‑le comme de la tuyauterie utile, puis appliquez la politique avec des règles de pare‑feu là où ça compte.

Conception : sous‑réseau VPN dédié et une seule destination autorisée

  • Interface VPN : wg0
  • Sous‑réseau VPN : 10.50.0.0/24
  • Serveur cible : 10.20.30.40
  • Port autorisé : 5432/tcp (exemple : Postgres)

Configuration WireGuard (serveur)

Gardez la configuration serveur ennuyeuse. L’ennui, c’est bien. L’ennui signifie que votre futur vous n’aura pas à rétro‑ingénier « l’astuce ».

cr0x@server:~$ sudo sed -n '1,120p' /etc/wireguard/wg0.conf
[Interface]
Address = 10.50.0.1/24
ListenPort = 51820
PrivateKey = (redacted)
# Optional: save config on runtime changes
SaveConfig = false

[Peer]
PublicKey = (redacted)
AllowedIPs = 10.50.0.10/32

Important : Le AllowedIPs du pair étant 10.50.0.10/32 signifie « ce pair possède cette IP VPN ».
Cela n’empêche pas magiquement le pair d’essayer de joindre 10.20.30.40 une fois le tunnel établi. C’est le travail du pare‑feu.

Politique de pare‑feu avec nftables (préféré sur Linux moderne)

L’approche propre est : refuser par défaut depuis le VPN → partout, puis percer un trou exact. Autorisez aussi le trafic établi/related.
Et consignez les abandons avec limitation de débit pour ne pas transformer vos disques en DoS.

cr0x@server:~$ sudo nft list ruleset
table inet filter {
  chain input {
    type filter hook input priority 0; policy drop;
    iif "lo" accept
    ct state established,related accept
    iif "wg0" tcp dport 22 accept
    iif "eth0" tcp dport 51820 accept
    ip protocol icmp accept
    counter drop
  }

  chain forward {
    type filter hook forward priority 0; policy drop;
    ct state established,related accept

    # Allow VPN clients to reach exactly one server/port
    iif "wg0" ip saddr 10.50.0.0/24 ip daddr 10.20.30.40 tcp dport 5432 accept

    # Optional: allow VPN clients to reach only the VPN gateway DNS forwarder
    # iif "wg0" ip saddr 10.50.0.0/24 ip daddr 10.50.0.1 udp dport 53 accept
    # iif "wg0" ip saddr 10.50.0.0/24 ip daddr 10.50.0.1 tcp dport 53 accept

    # Log and drop everything else from VPN
    iif "wg0" limit rate 10/second burst 20 log prefix "VPN-DROP " flags all counter drop
    counter drop
  }

  chain output {
    type filter hook output priority 0; policy accept;
  }
}

À remarquer :

  • Politique drop sur la chaîne forward : la machine VPN n’est pas un routeur « par défaut ». C’est un videur avec un clipboard.
  • La règle d’autorisation est entièrement qualifiée : interface, sous‑réseau source, IP de destination, protocole et port.
  • Nous enregistrons les abandons depuis wg0 avec un taux limité. Sans limitation, un stagiaire ennuyé avec nmap devient votre problème de rétention de logs.

Routage et NAT : évitez la NAT « utile » à moins d’en avoir vraiment besoin

Si votre serveur cible sait déjà router en retour vers le sous‑réseau VPN via la passerelle VPN, vous n’avez pas besoin de NAT. C’est plus propre et plus auditable.
La NAT peut cacher l’identité du client au serveur cible et compliquer les listes d’autorisation côté serveur.

Si vous ne pouvez pas modifier les routes côté cible, vous pouvez utiliser la NAT source sur la passerelle VPN pour que la cible réponde à la passerelle.
Mais considérez cela comme un compromis et consignez‑le.

cr0x@server:~$ sudo nft list table ip nat
table ip nat {
  chain postrouting {
    type nat hook postrouting priority 100; policy accept;
    oif "eth0" ip saddr 10.50.0.0/24 ip daddr 10.20.30.40 tcp dport 5432 masquerade
  }
}

Décision : si vous voyez des règles de masquerade qui s’appliquent à des destinations larges (comme « any »), resserrez‑les. La NAT n’est pas un sauf‑conduit.

Implémentation : OpenVPN + pare‑feu (toujours courant)

OpenVPN est éprouvé et omniprésent. Le même principe s’applique : OpenVPN pousse des routes ; le pare‑feu applique l’accès.
OpenVPN prend aussi en charge la config par client (CCD), que les gens utilisent comme si c’était de la segmentation. Cela aide, mais ce n’est pas un remplacement du pare‑feu.

Forme de la configuration serveur OpenVPN

cr0x@server:~$ sudo sed -n '1,160p' /etc/openvpn/server/server.conf
port 1194
proto udp
dev tun0
server 10.60.0.0 255.255.255.0
topology subnet
persist-key
persist-tun
keepalive 10 60
user nobody
group nogroup

# Don't push broad routes unless you mean it
;push "route 10.0.0.0 255.0.0.0"

# Optionally push a single host route (still not a security boundary)
push "route 10.20.30.40 255.255.255.255"

client-config-dir /etc/openvpn/ccd

Exemple CCD (par client)

cr0x@server:~$ sudo cat /etc/openvpn/ccd/alice
ifconfig-push 10.60.0.10 255.255.255.0

Bonne hygiène. Toujours pas de contrainte. L’application de la contrainte, c’est le pare‑feu dans FORWARD ou l’équivalent nftables.

Exemple iptables (héritage mais encore vu)

cr0x@server:~$ sudo iptables -S FORWARD
-P FORWARD DROP
-A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
-A FORWARD -i tun0 -s 10.60.0.0/24 -d 10.20.30.40/32 -p tcp -m tcp --dport 5432 -j ACCEPT
-A FORWARD -i tun0 -j LOG --log-prefix "VPN-DROP " --log-level 4
-A FORWARD -i tun0 -j DROP

Décision : si la politique n’est pas DROP, corrigez‑la. Si vous voyez -A FORWARD -i tun0 -j ACCEPT quelque part, c’est la règle « bar ouvert ». Supprimez‑la.

Contrôles côté serveur : supposez que le VPN ment

Si le serveur cible est important, appliquez aussi une politique de pare‑feu sur celui‑ci. La passerelle VPN est un point de contrôle unique, ce qui est bien — jusqu’à ce que ce ne le soit plus.
Une règle mal appliquée, une seconde instance VPN, un changement d’urgence, ou une exception dans un groupe de sécurité cloud peuvent contourner votre passerelle.

Côté cible : n’autorisez que le sous‑réseau VPN au service

Exemple : la cible est 10.20.30.40, le service est Postgres 5432/tcp. Autorisez uniquement depuis le sous‑réseau VPN, refusez les autres.

cr0x@server:~$ sudo nft list ruleset
table inet filter {
  chain input {
    type filter hook input priority 0; policy drop;
    iif "lo" accept
    ct state established,related accept

    # Allow Postgres only from VPN subnet
    ip saddr 10.50.0.0/24 tcp dport 5432 accept

    # Allow admin SSH only from a management subnet (example)
    ip saddr 10.1.2.0/24 tcp dport 22 accept

    limit rate 5/second burst 10 log prefix "TARGET-DROP " flags all counter drop
  }

  chain forward {
    type filter hook forward priority 0; policy drop;
  }

  chain output {
    type filter hook output priority 0; policy accept;
  }
}

Si c’est une application web au lieu d’une base de données, vous pouvez être plus strict : n’autorisez que l’IP du proxy/passerelle, pas tout le sous‑réseau VPN.

Petite blague #2 : Le moyen le plus rapide d’apprendre la « défense en profondeur » est de compter sur un seul pare‑feu puis de rencontrer le stagiaire avec sudo.

Tâches pratiques : 12+ vérifications réelles avec commandes, sorties et décisions

Ces tâches sont écrites comme si vous étiez d’astreinte et que quelqu’un demande : « L’utilisateur VPN peut‑il atteindre seulement ce service ? »
Chaque tâche inclut : une commande, à quoi ressemble une sortie réaliste, ce que cela signifie, et la décision suivante.

Tâche 1 : Confirmer que l’interface VPN est active et a le sous‑réseau attendu

cr0x@server:~$ ip -brief addr show wg0
wg0             UNKNOWN        10.50.0.1/24

Signification : l’interface VPN existe et a l’adresse attendue. Si elle manque ou si le sous‑réseau est erroné, vos règles de pare‑feu risquent de ne pas correspondre.

Décision : si le nom d’interface diffère (par ex. wg-office), mettez à jour les règles de pare‑feu pour correspondre à l’interface réelle.

Tâche 2 : Vérifier les pairs WireGuard et l’état du handshake

cr0x@server:~$ sudo wg show wg0
interface: wg0
  public key: (redacted)
  listening port: 51820

peer: (redacted)
  endpoint: 203.0.113.10:53422
  allowed ips: 10.50.0.10/32
  latest handshake: 1 minute, 12 seconds ago
  transfer: 18.23 MiB received, 41.77 MiB sent

Signification : le tunnel est vivant. Si le handshake est « never », ne perdez pas de temps sur la politique du pare‑feu — réglez d’abord la connectivité/authentification.

Décision : pas de handshake → vérifier la reachabilité UDP et les clés ; handshake OK → passer au routage et au pare‑feu.

Tâche 3 : S’assurer que le forwarding IP est activé sur la passerelle VPN (si vous attendez du routage)

cr0x@server:~$ sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 1

Signification : le noyau transmettra les paquets entre interfaces. Si c’est 0, votre « liste d’autorisation » est parfaite et inutile.

Décision : définissez à 1 seulement si cet hôte est destiné à router. Si vous utilisez un design proxy‑only, vous pouvez vouloir couper le forwarding.

Tâche 4 : Inspecter la politique et les compteurs nftables forward

cr0x@server:~$ sudo nft list chain inet filter forward
table inet filter {
  chain forward {
    type filter hook forward priority filter; policy drop;
    ct state established,related accept
    iif "wg0" ip saddr 10.50.0.0/24 ip daddr 10.20.30.40 tcp dport 5432 accept
    iif "wg0" limit rate 10/second burst 20 log prefix "VPN-DROP " flags all counter drop
    counter packets 1294 bytes 188290 drop
  }
}

Signification : le drop par défaut est en place, et vous avez une autorisation explicite. Les compteurs vous disent si du trafic heurte des drops.

Décision : si les compteurs de drop s’incrémentent quand un utilisateur essaie le service autorisé, votre règle d’autorisation est erronée (mauvaise IP, port, interface ou protocole).

Tâche 5 : Confirmer la route vers le réseau cible sur la passerelle VPN

cr0x@server:~$ ip route get 10.20.30.40
10.20.30.40 via 10.20.30.1 dev eth0 src 10.20.30.10 uid 0
    cache

Signification : la passerelle sait comment atteindre la cible et quelle IP source elle utilisera. Si elle route sur la mauvaise interface, vos attentes NAT/pare‑feu se cassent.

Décision : chemin incorrect → corriger le routage avant de toucher au pare‑feu. Les pare‑feu ne réparent pas la topologie.

Tâche 6 : Valider le routage du chemin de retour (depuis la cible vers le sous‑réseau VPN)

cr0x@server:~$ ssh cr0x@10.20.30.40 'ip route get 10.50.0.10'
10.50.0.10 via 10.20.30.10 dev eth0 src 10.20.30.40 uid 0
    cache

Signification : la cible sait renvoyer le trafic vers la passerelle VPN pour les clients VPN. Si ce n’est pas le cas, vous verrez un comportement « SYN envoyé, pas de réponse ».

Décision : si le chemin de retour est erroné et que vous ne pouvez pas le changer, envisagez la NAT sur la passerelle (mais gardez‑la fortement ciblée).

Tâche 7 : Tester le port autorisé unique depuis la perspective d’un client VPN (avec nc)

cr0x@server:~$ nc -vz 10.20.30.40 5432
Connection to 10.20.30.40 5432 port [tcp/postgresql] succeeded!

Signification : le chemin réseau et les règles de pare‑feu autorisent le port. Cela ne signifie pas que l’authentification est correcte — seulement que le TCP se connecte.

Décision : si cela échoue, vérifiez les drops sur la passerelle/cible. Si cela réussit, assurez‑vous que tout le reste échoue.

Tâche 8 : Prouver le refus : tenter un port interdit sur la même cible

cr0x@server:~$ nc -vz 10.20.30.40 22
nc: connect to 10.20.30.40 port 22 (tcp) failed: Operation timed out

Signification : le timeout est souvent un « drop par le pare‑feu ». Un « Connection refused » signifierait que le pare‑feu a autorisé mais que le service n’écoute pas.

Décision : si vous obtenez « refused » sur un port interdit, vous autorisez trop. Corrigez le pare‑feu passerelle/cible.

Tâche 9 : Prouver le refus : tenter un hôte interne qui devrait être inaccessible

cr0x@server:~$ nc -vz 10.20.30.41 5432
nc: connect to 10.20.30.41 port 5432 (tcp) failed: Operation timed out

Signification : vous restreignez par IP de destination, pas « n’importe quel serveur sur ce port ». Bien.

Décision : si ça se connecte, votre règle d’autorisation est trop large (sous‑réseau de destination au lieu d’hôte, ou une règle « accept all » plus loin).

Tâche 10 : Vérifier conntrack pour des flux inattendus (repérer « ça s’est connecté d’une manière ou d’une autre »)

cr0x@server:~$ sudo conntrack -L -p tcp 2>/dev/null | head -n 5
tcp      6 431999 ESTABLISHED src=10.50.0.10 dst=10.20.30.40 sport=49822 dport=5432 src=10.20.30.40 dst=10.50.0.10 sport=5432 dport=49822 [ASSURED] mark=0 use=1
tcp      6 119 SYN_SENT src=10.50.0.10 dst=10.20.30.40 sport=49830 dport=22 src=10.20.30.40 dst=10.50.0.10 sport=22 dport=49830 mark=0 use=1

Signification : vous pouvez voir les connexions tentées, même celles qui ont échoué. Les entrées SYN_SENT qui persistent peuvent indiquer des drops ou des problèmes de chemin de retour.

Décision : si vous voyez des flux établis vers des destinations/ports non autorisés, votre politique fuit — auditez l’ordre des règles de pare‑feu et les exemptions NAT.

Tâche 11 : Surveiller les logs de drop en direct (sans se noyer)

cr0x@server:~$ sudo journalctl -k -f | grep 'VPN-DROP' | head
Dec 28 10:22:01 vpn-gw kernel: VPN-DROP IN=wg0 OUT=eth0 SRC=10.50.0.10 DST=10.20.30.40 LEN=60 TOS=0x00 PREC=0x00 TTL=63 ID=51123 DF PROTO=TCP SPT=49830 DPT=22 WINDOW=64240 SYN

Signification : le pare‑feu bloque activement. Vous obtenez une preuve concrète : IP source, destination et port.

Décision : si vous voyez des abandons vers des IP internes inattendues, vous avez prouvé pourquoi le moindre privilège est important. Gardez‑les bloqués.

Tâche 12 : Confirmer que le serveur cible voit les vraies IP clients (ou pas)

cr0x@server:~$ ssh cr0x@10.20.30.40 'sudo ss -tnp sport = :5432 | head -n 5'
State  Recv-Q Send-Q Local Address:Port Peer Address:Port Process
ESTAB  0      0      10.20.30.40:5432 10.50.0.10:49822 users:(("postgres",pid=1421,fd=7))

Signification : la cible voit l’IP client VPN (10.50.0.10). Si elle voit l’IP de la passerelle VPN, la NAT est en jeu.

Décision : préférez voir les vraies IP clients pour l’audit et les contrôles par utilisateur. Si vous devez NATer, compensez par des logs passerelle et une identité forte côté appli.

Tâche 13 : Vérifier le comportement DNS (la découverte interne accidentelle est fréquente)

cr0x@server:~$ resolvectl status | sed -n '1,40p'
Global
       Protocols: -LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
resolv.conf mode: stub
Current DNS Server: 1.1.1.1
       DNS Servers: 1.1.1.1 8.8.8.8

Signification : ce client n’utilise pas le DNS interne, donc le nommage interne n’est pas divulgué via le tunnel (ou utilisé pour énumérer des services).

Décision : si vous poussez le DNS interne aux clients VPN, assurez‑vous que vous n’autorisez pas aussi l’accès à tout ce que ces noms résolvent.

Tâche 14 : Prouver que les règles de pare‑feu persistent au redémarrage

cr0x@server:~$ sudo systemctl is-enabled nftables
enabled

Signification : le pare‑feu reviendra après redémarrage. S’il est désactivé, votre politique stricte pourrait n’être qu’un miracle en mémoire.

Décision : activez‑le et stockez les règles dans une configuration gérée. Si vous faites ça à la main en production, au moins documentez‑le et commitez‑le.

Mode opératoire de diagnostic rapide

Quand « l’utilisateur VPN ne peut pas atteindre le port autorisé » arrive, vous avez besoin d’une méthode rapide pour trouver le goulet sans danse interprétative.
Voici l’ordre qui gaspille le moins de temps.

1) Confirmer que le tunnel est actif (ne pas déboguer la politique sans tunnel)

  • WireGuard : sudo wg show wg0 → cherchez un handshake récent et des compteurs de transfert croissants.
  • OpenVPN : vérifiez les logs serveur et le statut client ; confirmez que le client a une IP dans le pool VPN attendu.

S’il n’y a pas de handshake, vous êtes en territoire « reachabilité réseau/clefs/auth », pas en territoire segmentation.

2) Confirmer que le client essaie vraiment la bonne destination/port

  • Exécutez nc -vz target port depuis le client.
  • Vérifiez si ça time‑out (drop) ou refuse (service inaccessible mais autorisé).

3) Cherchez d’abord les drops sur la passerelle VPN

  • Inspectez les compteurs et logs nftables/iptables pour le flux tenté.
  • Si la passerelle ne le voit pas, le client ne route peut‑être pas dans le tunnel, ou vous testez depuis la mauvaise interface.

4) Valider le routage et le chemin de retour

  • Sur la passerelle : ip route get target.
  • Sur la cible : ip route get vpn_client_ip.

Le routage est la raison n°1 pour laquelle « ça devrait fonctionner » ne fonctionne pas, spécialement quand la NAT est à moitié configurée.

5) Enfin, vérifiez le pare‑feu local de la cible et la liaison du service

  • Pare‑feu de la cible : confirmez qu’il autorise depuis le sous‑réseau VPN vers le port du service.
  • Service : confirmez qu’il écoute sur la bonne interface (pas seulement localhost).

Erreurs courantes (symptômes → cause racine → correction)

Erreur 1 : « Nous avons poussé une seule route, donc les utilisateurs ne peuvent atteindre qu’un seul serveur »

Symptômes : Un utilisateur peut atteindre d’autres IP internes en ajoutant des routes manuellement, ou en utilisant des chemins existants et du hairpin NAT.

Cause racine : Confusion entre configuration de routage client et autorisation.

Correction : Appliquez la liste d’autorisation sur le chemin forward de la passerelle VPN (et idéalement sur la cible). Refuser par défaut. Consigner les drops.

Erreur 2 : Autoriser « sous‑réseau VPN → any » temporairement, puis oublier

Symptômes : Des semaines plus tard, un audit trouve que des utilisateurs VPN peuvent RDP sur des serveurs au hasard. Personne ne se souvient pourquoi.

Cause racine : Changements d’urgence sans rollback ni expiration.

Correction : Limitez les exceptions dans le temps. Utilisez la gestion de configuration et la revue de code pour les règles de pare‑feu. Ajoutez une alerte pour les acceptations larges depuis les interfaces VPN.

Erreur 3 : Interpréter « Connection refused » comme « bloqué »

Symptômes : Vous croyez que le pare‑feu fonctionne parce que les tests échouent, mais ils échouent avec « refused », pas « timeout ».

Cause racine : Le pare‑feu autorise le trafic ; le service le rejette car il n’écoute pas ou a un contrôle d’accès.

Correction : Pour les chemins interdits, vous voulez des timeouts/drops (ou des rejects explicites si c’est votre politique). Vérifiez les compteurs du pare‑feu et ss -lntp sur le serveur.

Erreur 4 : La NAT cache l’identité client, cassant l’audit et les contrôles serveur

Symptômes : Les logs de la cible montrent toutes les connexions depuis l’IP de la passerelle VPN ; les limites et listes par utilisateur échouent.

Cause racine : Masquerade appliqué largement, souvent comme solution rapide pour le routage de retour.

Correction : Préférez le routage réel. Si vous devez NATer, restreignez‑la à une destination/port et compensez par des logs passerelle et une authentification forte applicative.

Erreur 5 : Règles de pare‑feu sur la mauvaise chaîne (INPUT vs FORWARD)

Symptômes : Le pare‑feu de la passerelle semble strict, mais les clients VPN peuvent quand même atteindre des services internes.

Cause racine : Les règles ont été appliquées à INPUT (trafic vers la passerelle) au lieu de FORWARD (trafic à travers la passerelle).

Correction : Placez les règles d’autorisation/refus dans le chemin de forwarding. Gardez INPUT pour protéger la passerelle elle‑même.

Erreur 6 : L’IPv6 contourne silencieusement votre politique IPv4 seule

Symptômes : Vous avez bloqué l’IPv4, pourtant les utilisateurs atteignent encore des choses. Les captures montrent des flux IPv6.

Cause racine : Clients et réseaux dual‑stack, avec des règles de pare‑feu écrites uniquement pour IPv4.

Correction : Utilisez table inet dans nftables et contrôlez explicitement l’IPv6. Ou désactivez l’IPv6 sur l’interface VPN si c’est acceptable.

Erreur 7 : Le DNS fuit la topologie interne

Symptômes : Même bloqués, les utilisateurs VPN peuvent interroger le DNS interne et énumérer des noms de service.

Cause racine : Le serveur DNS est joignable depuis le sous‑réseau VPN, ou le DNS est autorisé « parce que ça semble inoffensif ».

Correction : N’autorisez pas le DNS interne sauf si nécessaire. Si nécessaire, autorisez uniquement un résolveur contrôlé/split‑horizon qui ne révèle pas tout.

Erreur 8 : Logger chaque paquet droppé sans limitation

Symptômes : Les logs noyau débordent ; les disques se remplissent ; la réponse aux incidents devient « pourquoi syslog est tombé ? »

Cause racine : Règles de log non bridées combinées à des scans ou des clients mal configurés.

Correction : Limitez le débit des logs, agrégez les compteurs et échantillonnez intelligemment. Votre journalisation doit survivre aux mauvais jours, pas les provoquer.

Listes de contrôle / plan pas à pas

Plan pas à pas : passer de « VPN ouvert » à « un serveur/port seulement »

  1. Choisissez le point d’application. Utilisez la passerelle VPN comme point d’étranglement principal. Décidez si vous appliquez aussi sur le serveur cible (vous devriez).
  2. Définissez le tuple exact : source (sous‑réseau VPN), IP de destination, port de destination, protocole. Écrivez‑le. Si c’est « ce que l’appli utilise », vous n’en avez pas fini.
  3. Créez un sous‑réseau VPN dédié. Ne le mélangez pas avec des plages internes existantes. La segmentation commence par des frontières d’adresses propres.
  4. Mettre le refus par défaut sur le chemin de forwarding. Sur la passerelle, la chaîne forward doit être DROP par défaut.
  5. Ajoutez une règle d’autorisation unique. Entièrement qualifiée. Pas de sous‑réseaux sauf si la demande concerne vraiment plusieurs cibles.
  6. Gérez le routage de retour. Préférez une route sur la cible (ou le routeur amont) vers le sous‑réseau VPN via la passerelle. N’utilisez la NAT que si nécessaire.
  7. Verrouillez le serveur cible. Autorisez uniquement le sous‑réseau VPN (ou l’IP passerelle/proxy) vers le port du service.
  8. Décidez du DNS. Si le client n’a pas besoin du DNS interne, ne le fournissez pas. Si nécessaire, filtrez‑le et limitez‑le.
  9. Rendez‑le observable. Compteurs, logs à débit limité, et habitude de les vérifier après les changements.
  10. Testez le refus, pas seulement l’autorisation. Essayez de vous connecter à des ports et hôtes interdits et assurez‑vous que ça échoue comme prévu.
  11. Rendez‑le persistant. Services systemd activés, configs sous contrôle de version, et changements revus.
  12. Faites une revue périodique des accès. Les besoins évoluent ; votre pare‑feu ne doit pas « évoluer » silencieusement avec eux.

Checklist de contrôle des changements (pour les adultes dans la pièce)

  • Y a‑t‑il une règle d’autorisation explicite pour le serveur/port unique ? (Pas une règle vague de sous‑réseau.)
  • La politique forward par défaut est‑elle DROP ?
  • Les logs/compteurs confirment‑ils que seul ce flux réussit ?
  • Une exception temporaire a‑t‑elle une date d’expiration ?
  • Pouvons‑nous prouver le routage de retour sans NAT large ?
  • L’IPv6 est‑il traité intentionnellement ?
  • Le serveur cible est‑il aussi restreint ?

Trois mini‑histoires d’entreprise depuis le terrain

Mini‑histoire 1 : L’incident causé par une mauvaise hypothèse

Une entreprise de taille moyenne avait un « VPN fournisseur » pour une intégration paie. Le prestataire avait besoin d’un accès HTTPS à un seul endpoint interne.
L’équipe réseau a poussé une seule route vers cet hôte et s’est sentie fière de sa retenue. Ils l’ont même noté dans un ticket de changement.

Quelques mois plus tard, un audit interne montra que le compte prestataire pouvait atteindre un serveur de fichiers. Personne n’y crut. La table de routage sur l’ordinateur du prestataire paraissait propre.
Mais la passerelle VPN faisait aussi de la NAT pour « simplifier les choses », et la politique forward était permissive : elle permettait au sous‑réseau VPN d’atteindre des réseaux internes parce que
« sinon le dépannage est difficile ».

Le prestataire n’avait jamais eu l’intention d’accéder au serveur de fichiers. Ce n’était pas le but. Le problème était qu’un endpoint prestataire compromis avait désormais un chemin pavé vers des actifs internes.
L’hypothèse était « le routage équivaut à restriction ». La réalité était « le routage est une suggestion ; les pare‑feu sont l’exécution ».

La correction fut ennuyeuse : DROP par défaut sur le forward, une règle d’autorisation unique, et un pare‑feu côté serveur sur le point d’extrémité.
La partie difficile fut organisationnelle : admettre que « nous avons poussé une route » était du théâtre de sécurité.

Mini‑histoire 2 : L’optimisation qui s’est retournée

Un autre endroit voulait réduire la charge sur sa passerelle VPN. Ils activèrent le split tunneling et poussèrent le DNS interne pour que les laptops résolvent les services internes.
L’idée : seul le trafic applicatif nécessaire passe par le tunnel ; le reste reste local. Les graphes de bande passante étaient plus propres. Tout le monde était content.

Puis vint le bug étrange : un sous‑ensemble d’utilisateurs accédait parfois au « service autorisé » mais parfois subissait des timeouts.
Le canal d’incidents se remplit de suppositions confiantes : « WireGuard est instable », « la base est surchargée », « c’est probablement le MTU ».

Le réel problème était opérationnellement banal. Avec le split tunneling et le DNS interne, les clients résolvaient des noms internes hors réseau,
et certains laptops avaient des chevauchements d’adresses locales (routeurs domestiques utilisant les mêmes plages privées que le corp.). Les clients envoyaient parfois le trafic « interne » localement,
sans jamais entrer dans le VPN. Les règles du pare‑feu de la passerelle n’étaient donc pas sur le chemin.

L’« optimisation » a économisé de la bande passante mais créé une loterie de routage. La résolution fut de ne plus compter sur DNS+split tunneling pour la sécurité déterministe.
Ils ont figé la cible par IP pour l’accès VPN, corrigé les chevauchements d’adresses et forcé le trafic du service via le tunnel. Ennuyeux, prévisible, correct.

Mini‑histoire 3 : La pratique ennuyeuse mais correcte qui a sauvé la mise

Une équipe de services financiers avait l’habitude, qui paraissait superflue : chaque changement de pare‑feu comprenait un test « prouver le refus ».
Pas seulement « est‑ce que ça marche », mais « est‑ce que tout le reste échoue ». Ils gardaient un petit script qui tentait des connexions vers quelques ports internes interdits.

Un après‑midi, une mise à jour de l’OS sur la passerelle VPN a changé le backend du pare‑feu. Les règles ont été chargées, mais un nom de chaîne a changé,
et leur politique « n’autoriser qu’un port » est devenue effectivement « autoriser tout ce qui est établi », avec de nouvelles règles accept trop larges ajoutées par un script legacy.

Personne ne le remarqua tout de suite, parce que le service autorisé fonctionnait toujours. C’est ainsi que ces échecs se cachent : le succès n’est pas la preuve de la restriction.
Mais leur suite de tests post‑changement l’a signalé immédiatement. Les tentatives de connexion interdites ne time‑out pas — elles se connectaient.

Ils ont rollbacké en minutes et réappliqué correctement les règles. Pas de rapport d’incident. Pas de récit de compromission. Juste une petite pratique ennuyeuse qui a évité
un gros problème. C’est ce à quoi ressemble la fiabilité quand elle marche : il ne se passe rien.

FAQ

1) Puis‑je faire respecter « un seul serveur/port » uniquement avec AllowedIPs de WireGuard ?

Non. AllowedIPs est du routage et de l’association de pair. Ça aide, mais ce n’est pas la frontière d’application que vous voulez.
Utilisez des règles de pare‑feu sur la passerelle (et idéalement sur la cible).

2) Dois‑je utiliser la NAT ou un routage propre ?

Préférez le routage propre pour que la cible voie les vraies IP clients et que vous puissiez auditer et mettre des listes d’autorisation côté serveur.
Utilisez la NAT seulement quand vous ne pouvez pas corriger les chemins de retour, et restreignez‑la au port/destination unique.

3) Le « split tunnel » est‑il compatible avec le moindre privilège ?

Parfois, mais c’est facile à rater. Le split tunnel augmente la dépendance aux décisions de routage correctes sur le client et réduit votre capacité à observer centralement les chemins.
Pour « un seul serveur/port », forcer le trafic de ce service à travers le tunnel est généralement plus propre.

4) Où dois‑je appliquer les restrictions : passerelle, cible, ou les deux ?

Les deux. L’application à la passerelle réduit l’aire de blast et vous donne des logs centraux. L’application sur la cible protège contre des chemins de contournement et des erreurs de configuration.
Défense en profondeur, sans discours marketing.

5) Comment restreindre par utilisateur, pas seulement par sous‑réseau VPN ?

La voie la plus simple est des IP VPN par utilisateur et des règles qui correspondent à ip saddr 10.50.0.10 plutôt qu’au sous‑réseau entier.
Mieux encore : placez le service derrière un proxy conscient d’identité pour que l’accès soit lié à l’authentification, pas seulement à l’IP source.

6) Qu’en est‑il de l’accès au DNS et aux serveurs de temps ?

Ne les autorisez pas automatiquement. Si votre service unique est spécifié par IP, vous n’aurez peut‑être pas besoin du DNS interne.
Si vous devez fournir le DNS, autorisez‑le uniquement à un résolveur contrôlé et considérez le DNS comme des métadonnées sensibles.

7) Est‑il préférable de dropper le trafic plutôt que de le rejeter ?

Le drop (timeout) divulgue moins sur ce qui existe, mais peut ralentir le dépannage.
Le reject peut rendre l’expérience utilisateur plus claire. Pour la segmentation VPN, je droppe par défaut et consigne avec limitation, puis j’utilise des rejects explicites seulement si nécessaire.

8) Comment prouver aux auditeurs que l’accès est restreint ?

Montrez les règles de pare‑feu (refus par défaut + unique autorisation), montrez les compteurs/logs des tentatives refusées, et fournissez des preuves de test :
la connexion au port autorisé réussit, les connexions aux ports/hôtes interdits time‑out. Si vous ne pouvez pas produire cela rapidement, vous ne le contrôlez pas vraiment.

9) Et l’IPv6 — dois‑je m’en soucier ?

Oui, parce que vos clients y sont probablement déjà connectés. Si vous pare‑feurez seulement l’IPv4, vous pouvez permettre involontairement des chemins IPv6.
Utilisez les tables nftables inet ou désactivez explicitement l’IPv6 sur l’interface VPN si cela convient à votre environnement.

10) Si le service est HTTPS, dois‑je quand même appliquer « un port seulement » ?

Oui, mais pensez aussi à publier le service via un reverse proxy où vous pouvez appliquer l’identité, mTLS, l’enregistrement des requêtes et les quotas.
La restriction réseau est nécessaire ; elle n’est pas suffisante.

Conclusion : prochaines étapes efficaces

« L’accès VPN bureau » n’est pas un choix binaire entre « pas d’accès » et « tout l’intérieur ». Vous pouvez — et devez — concevoir pour un seul serveur et un seul port.
Voilà à quoi ressemble le moindre privilège quand on peut le mesurer.

  1. Choisissez votre point d’application : implémentez le forwarding par défaut DENY sur la passerelle VPN.
  2. Écrivez une règle d’autorisation précise : interface + source + IP destination + protocole + port.
  3. Validez le routage de retour : corrigez d’abord les routes ; utilisez la NAT fortement ciblée seulement si inévitable.
  4. Ajoutez des restrictions côté serveur : la cible doit accepter le port du service seulement depuis le sous‑réseau VPN (ou la passerelle/proxy).
  5. Prouvez le refus après chaque changement : testez ports/hôtes interdits et surveillez les compteurs/logs avec limitation.

Faites cela, et votre VPN cesse d’être un couloir vers le bâtiment. Il devient une porte verrouillée avec une clé spécifique.
Ce n’est pas de la paranoïa ; c’est de l’hygiène professionnelle.

← Précédent
ZFS : Utiliser NVMe comme SLOG — Quand c’est parfait et quand c’est excessif
Suivant →
Erreur de l’API REST WordPress : ce qui casse REST et comment dépanner

Laisser un commentaire