- Le tunneling SSH transporte du trafic TCP sur une connexion SSH sécurisée et sert à ouvrir en toute sécurité des chemins d’accès restreints, par exemple pour chiffrer des protocoles legacy, accéder à des panneaux d’administration ou joindre des serveurs derrière un NAT
- Côté serveur,
AllowTcpForwarding yes est nécessaire ; pour ouvrir un port sur une interface autre que loopback, il faut configurer GatewayPorts yes et redémarrer le serveur SSH
ssh -J, ssh -L, ssh -R et ssh -D servent respectivement au jump host, à la redirection locale, à la redirection distante et à la redirection dynamique basée sur SOCKS5
- Pour garder un tunnel en arrière-plan, utilisez
ssh -fN ; la détection des coupures se règle avec des paramètres de heartbeat comme ClientAliveInterval et ClientAliveCountMax
- Le tunneling SSH ne prend pas directement en charge UDP, et TCP-over-TCP peut entraîner des problèmes de latence et de débit ; il s’agit donc davantage d’un outil pour ouvrir des chemins TCP précis que d’une alternative au VPN
Dans quels cas utiliser le tunneling SSH
- Le tunneling SSH et la redirection de ports transmettent du trafic TCP via une connexion SSH, du client vers le serveur ou du serveur vers le client
- Il est possible d’utiliser des ports TCP et des sockets UNIX, mais les exemples se concentrent sur les ports TCP
- Les usages typiques se répartissent entre sécurité, dépannage et contournement de connexion
- Sécurité
- Chiffrer des connexions non sécurisées comme FTP ou des protocoles legacy
- Accéder à un panneau d’administration web via un tunnel SSH basé sur l’authentification par clé publique
- N’ouvrir que le port 22, sans exposer de ports supplémentaires comme 80/443
- Dépannage
- Contourner un pare-feu ou un filtre de contenu
- Choisir un autre chemin réseau
- Connexion
- Accéder à un serveur situé derrière un NAT
- Entrer depuis Internet vers un serveur interne via un jump host
- Exposer un port local sur Internet
Paramètres à vérifier avant la redirection de ports
- Les options des exemples peuvent être combinées et configurées selon l’environnement
- Si
bind_address n’est pas spécifié, la valeur par défaut est localhost
- Les utilisateurs locaux et distants doivent disposer des droits nécessaires pour ouvrir des ports sur chaque machine
- Les ports
0-1024 nécessitent des droits root en l’absence de configuration particulière
- Les autres ports peuvent aussi être configurés par un utilisateur standard
- Les pare-feu côté client et réseau doivent également être ouverts selon le chemin de redirection
- La redirection de ports doit être activée sur le serveur SSH
AllowTcpForwarding yes
- Elle est souvent activée par défaut, mais il faut vérifier la configuration du serveur
- Pour rediriger un port vers une interface autre que
127.0.0.1, activez GatewayPorts sur le serveur SSH
GatewayPorts yes
- Après modification, le service du serveur SSH doit être redémarré
Jump host SSH et tunnels à plusieurs sauts
ssh -J s’utilise pour se connecter de manière transparente à un hôte distant en passant par un ou plusieurs hôtes intermédiaires
ssh -J user@REMOTE-MACHINE:22 -p 22 user@10.99.99.1
- Lorsque le port par défaut
22 est utilisé, l’indication du port peut être omise
- En utilisant REMOTE-MACHINE comme jump host, la connexion apparaît comme suit
[user@REMOTE-MACHINE]$ ss | grep -i ssh
tcp ESTAB 0 0 167.135.173.108:ssh 192.160.140.207:45960
tcp ESTAB 0 0 10.99.99.2:49770 10.99.99.1:ssh
- Les rôles des adresses de l’exemple sont les suivants
167.135.173.108 : IP publique de REMOTE-MACHINE
192.160.140.207 : IP publique de LOCAL-MACHINE
10.99.99.2 : IP interne de REMOTE-MACHINE
10.99.99.1 : IP interne de REMOTE-WEBAPP
- Pour utiliser plusieurs jump hosts, séparez-les par des virgules
ssh -J user@REMOTE-MACHINE:22,user@ANOTHER-REMOTE-MACHINE:22 -p 22 user@10.99.99.1
Redirection de port locale
- La redirection de port locale utilise l’option
ssh -L
- Le premier exemple transmet
10.10.10.1:8001 de LOCAL-MACHINE vers localhost:8000 sur REMOTE-MACHINE
ssh -L 10.10.10.1:8001:localhost:8000 user@REMOTE-MACHINE
- Sur REMOTE-MACHINE, le journal d’accès d’un serveur web lié uniquement à
127.0.0.1 ressemble à ceci
127.0.0.1 - - [30/Dec/2022 18:05:15] "GET / HTTP/1.1" 200
- Cette requête est initiée depuis LOCAL-MACHINE
- Le second exemple transmet le port local
8001 vers 10.99.99.1:8000 via REMOTE-MACHINE
ssh -L 8001:10.99.99.1:8000 user@REMOTE-MACHINE
- Dans le journal d’accès du serveur web de REMOTE-WEBAPP, la requête apparaît comme venant de l’IP interne de REMOTE-MACHINE
10.99.99.2 - - [30/Dec/2022 21:28:42] "GET / HTTP/1.1" 200
Redirection de port distante
- La redirection de port distante utilise l’option
ssh -R
- L’exemple transmet le port
8000 de REMOTE-MACHINE vers localhost:8001 ou 10.10.10.2:8001 côté local
ssh -R 8000:localhost:8001 user@REMOTE-MACHINE
ssh -R 8000:10.10.10.2:8001 user@REMOTE-MACHINE
- Il est aussi possible de configurer l’écoute sur une interface distante précise,
10.99.99.2:8000
ssh -R 10.99.99.2:8000:10.10.10.2:8001 user@REMOTE-MACHINE
- Pour écouter ailleurs que sur l’interface loopback,
GatewayPorts yes doit être activé sur le serveur SSH
Redirection de port dynamique et SOCKS5
- Pour transmettre plusieurs ports, SSH utilise le protocole SOCKS
- SOCKS est un protocole de proxy transparent, et SSH utilise sa version moderne, SOCKS5
- Le port par défaut d’un serveur SOCKS5 est
1080, défini dans la RFC 1928
- Le client doit être configuré pour utiliser le proxy SOCKS au niveau de l’application ou de l’OS
- L’exemple
ssh -D ouvre un proxy SOCKS sur 10.10.10.1:5555
ssh -D 10.10.10.1:5555 user@REMOTE-MACHINE
- Sur le client LOCAL,
curl permet de tester le chemin de connexion
curl -L -x socks5://10.10.10.1:5555 brrl.net/ip
- Si tout fonctionne correctement, l’IP publique de REMOTE-MACHINE est renvoyée
Tunneling SSH TUN/TAP
- Le flag
-w permet de créer un tunnel bidirectionnel
- Les interfaces doivent avoir été créées au préalable
- Cette méthode conserve la réserve qu’elle n’a pas été testée
-w local_tun[:remote_tun]
Exécution en arrière-plan et arrêt
- Pour lancer un tunnel en arrière-plan de façon native, utilisez
-fN
-f : exécution en arrière-plan
-N : ne pas ouvrir de shell
ssh -fN -L 8001:127.0.0.1:8000 user@REMOTE-MACHINE
- Sinon, il est possible d’utiliser
screen ou d’autres outils
- Pour arrêter un SSH exécuté en arrière-plan, trouvez le processus et terminez-le via son PID
user@pleasejustwork:~$ ps -ef | grep ssh
[...]
user 19255 1 0 11:40 ? 00:00:00 ssh -fN -L 8001:127.0.0.1:8000 user@REMOTE-MACHINE
[...]
kill 19255
Maintien de connexion SSH et reconnexion
- Il existe plusieurs façons de maintenir une connexion SSH
- Les options de heartbeat pour gérer les timeouts peuvent être configurées côté client, côté serveur ou des deux côtés
ClientAliveInterval envoie une requête toutes les n secondes pour maintenir la connexion
ClientAliveInterval 15
ClientAliveCountMax correspond au nombre de requêtes heartbeat envoyées avant de fermer la connexion après absence de réponse de l’autre côté
ClientAliveCountMax 3
3 est la valeur par défaut ; avec 0, la fermeture de la connexion est désactivée
- Dans cet exemple de configuration, la connexion est coupée après environ 45 secondes sans réponse
- Pour se reconnecter après une coupure, on peut utiliser
autossh, un script, un cronjob, etc.
Limites et précautions de sécurité
-
UDP
- SSH s’appuie sur un transport fiable pour un déchiffrement correct
- UDP ne fournit pas cette fiabilité ; il n’est donc pas pris en charge dans un tunnel SSH et n’est pas recommandé
- Il existe une méthode couvrant UDP over SSH tunneling, mais elle conserve la réserve qu’elle n’a pas été testée
-
TCP-over-TCP
- L’overhead réduit le débit et augmente la latence
- Sur les connexions avec perte de paquets ou forte latence, un TCP meltdown peut se produire
- On peut consulter cet article sur TCP over TCP
- Lors d’une utilisation d’OpenVPN-over-TCP pendant un certain temps, le débit était inférieur à celui d’UDP, mais le fonctionnement était stable ; les résultats dépendent fortement de la configuration
-
Limites en tant qu’alternative au VPN
- Le tunneling SSH peut être utilisé comme un VPN, mais un VPN est plus adapté pour de meilleures performances
-
Risques de sécurité
- Si cette fonctionnalité n’est pas nécessaire, il est recommandé de la désactiver
- Un attaquant peut utiliser le tunneling SSH et la redirection de ports pour contourner les pare-feu et d’autres mesures de sécurité
-
Documentation de référence
1 commentaires
Avis sur Hacker News
En 2024, mieux vaut configurer LocalForward, RemoteForward et ProxyJump dans
~/.ssh/configplutôt que d’écrire à la main de longues commandes SSHCela fait gagner beaucoup de temps quand on accède avec
ssh,scpoursyncà un serveur distant qui nécessite de passer par plusieurs connexions SSH intermédiairesPar exemple, il suffit d’enchaîner
jump-host-1,jump-host-2etjump-host-3avecProxyJump, puis de se connecter àtarget-servervia un aliasLocalForward 0.0.0.0:8080 0.0.0.0:80transfère le port distant 80 vers le port local 8080, etRemoteForward 0.0.0.0:9022 0.0.0.0:22transfère les requêtes SSH arrivant sur le port distant 9022 vers le port local 22Avec
LocalForwardetRemoteForward, la partie de gauche correspond au serveur cible et celle de droite au local ; il y a aussi l’astuce consistant à utiliser0.0.0.0plutôt quelocalhostou127.0.0.1ssh_config, une configuration utile consiste à se connecter directement en SSH aux machines quand on est à la maison ou dans son VPN auto-hébergé, et à passer automatiquement par un jump host quand on est à l’extérieurOn peut d’abord détecter si l’on est à la maison/sur le VPN via l’adresse du routeur, avec quelque chose comme
Match host *.example.org exec "getent ahosts router.example.org | grep -q ^10.0.0.1", puis utiliserProxyJump jump.example.orgsi l’adresse MAC obtenue viaarpne correspond pas à la valeur attendueL’ordre est important : il faut d’abord détecter le réseau VPN/domestique, puis appliquer le jump host si l’on est à l’extérieur
Si l’on crée un VPS de courte durée pour utiliser SSH comme proxy SOCKS afin de contourner une restriction géographique, ou si l’on aide temporairement une autre équipe et qu’on doit se connecter une seule fois à un serveur auquel on n’accède pas d’habitude, les options en ligne de commande me semblent préférables
0.0.0.0peut être risquéCela peut ouvrir le port sur toutes les interfaces réseau et, surtout si le serveur distant n’a pas de pare-feu, exposer quelque chose à tout Internet
Pour du tunneling ou du port forwarding fréquent, un fichier de configuration est une bonne solution, mais pour une tâche ponctuelle ou rare, les options en ligne de commande me semblent préférables
Je cherche une solution un peu à la GitOps, adaptée à un seul utilisateur avec plusieurs machines, qui récupérerait la configuration depuis un endroit comme GitHub sans nécessiter de serveur séparé toujours allumé
bash/fishpour n’avoir à retenir qu’un minimum d’argumentsSi j’oublie, je consulte les définitions de fonctions que j’ai documentées
Dans l’environnement d’entreprise absurde où je travaille, le tunneling SSH est indispensable
À cause de la bureaucratie, obtenir un accès, ouvrir un port ou obtenir une exception pare-feu/VPN peut prendre des semaines
L’article mentionne
-D, mais n’en explique pas suffisamment la puissanceSi vous exécutez
ssh -D 8888 someserveret configurez le proxy SOCKS du navigateur surlocalhost:8888, tout le trafic du navigateur est routé viasomeserverFirefox est encore capable de faire cela sans modifier les paramètres système par défaut, ce qui est très utile
Mais en arrivant en entreprise, j’ai découvert qu’à cause des listes d’IP autorisées, je ne pouvais même pas établir de connexion SSH vers un serveur quelconque sur Internet ; c’était tellement pénible que j’ai même cherché comment créer un tunnel HTTP et faire ajouter à la liste blanche un serveur que je contrôlais, avant de finalement changer de travail
Ces restrictions existent pour une raison, et les contourner peut passer pour un manque d’expertise et un mépris des procédures et de la sécurité de l’organisation
Si obtenir un accès prend des semaines ou des mois, il faut attendre ; personne ne veut être responsable d’avoir ouvert une porte dérobée vers des informations confidentielles ou d’avoir compromis la sécurité
Le bricolage de tunneling SSH le plus sale que j’aie fait à 3 h du matin consistait à relier trois datacenters
Les trois sites, situés dans la même zone métropolitaine, étaient connectés à l’Internet backbone, mais à cause de règles de routage bizarres, A ne pouvait se connecter qu’à B, et seul B pouvait se connecter à C
Au final, pour déplacer les données de A vers C en passant par B, il a fallu mélanger rsync + tunnel SSH + clés + astuces de routage ; après avoir ajusté plusieurs fois cette commande digne d’une incantation, voir tout l’ensemble fonctionner d’un seul coup avait quelque chose de magique
Avec le recul, la manière de faire me paraît évidente, mais pour le débutant que j’étais à l’époque, c’était une grande réussite, et je me souviens encore de l’excitation en constatant que la synchronisation était terminée
~/.ssh/configet ProxyJump, on peut en pratique sauter autant d’étapes que nécessaire, comme A, B, C, D, ELes détails de la visualisation sont bons
En réseau, j’aimerais surtout qu’il existe beaucoup plus d’outils pour représenter visuellement le trafic, notamment aux niveaux de connexion les plus bas
Bien sûr, ce n’est qu’une représentation statique de concepts, et la plupart des fournisseurs réseau proposent eux aussi une forme de visualisation du trafic, mais cela se limite généralement à des métriques ou graphiques individuels
Si un serveur Linux ou un appareil IoT se trouve derrière un pare-feu, sans IP fixe, et que vous voulez vous y connecter en SSH, vous pouvez utiliser un service de tunneling comme https://sshreach.me
J’ai pas mal utilisé le tunneling pendant des années, mais je ne connaissais pas l’option
-JPlutôt que de passer 30 minutes à configurer un tunnel chaque fois que j’en ai besoin tous les quelques mois, j’aimerais bien qu’il existe un outil visuel pour configurer les tunnels
Il est expliqué que TCP-over-TCP augmente l’overhead, réduit le débit, accroît la latence et peut provoquer un effondrement TCP sur des connexions avec perte de paquets ou à forte latence, comme les liaisons satellite
Mais avec un tunnel SSH, ce n’est en réalité pas un problème tant qu’on n’utilise pas TAP/TUN
C’est parce que SSH désencapsule le flux TCP avant de le transmettre
En revanche, lorsqu’on utilise plusieurs canaux, les performances peuvent se dégrader à cause du blocage en tête de ligne
Il y a environ 15 ans, j’ai appris les tunnels SSH pour contourner le pare-feu du réseau de mon université, et j’ai dû changer le port par défaut pour le 443
Depuis, je continue à m’en servir pour bien plus de choses que le contournement de pare-feu
Avec
sshuttle, le tunneling devient beaucoup plus pratiqueEn l’utilisant par exemple comme
sshuttle -r user@host 10.0.0.0/8, la plage10/8est automatiquement tunnelisée et cela fonctionne en pratique comme un VPN au-dessus de SSHJe me demande si SSH dispose lui-même d’une fonction de redirection
Par exemple, si A essaie de se connecter en SSH à B, B lui indique de se connecter à C, A se connecte directement et de façon transparente à C, et B ne reste plus sur le chemin principal des données
Mon pare-feu/routeur ne transmet pas correctement l’option DHCP 67 et envoie systématiquement sa propre adresse ; j’ai donc dû configurer une IP virtuelle/des règles pour que, lorsque le trafic de démarrage PXE sur ce port arrive à l’IP du routeur, il soit routé vers le vrai serveur de démarrage PXE
Sinon, il suffit d’utiliser la fonction de saut :
ssh -J B CSi B n’a pas besoin d’être sur le chemin et qu’on peut se connecter directement à C, autant se connecter directement à C ; si ce n’est pas possible, B devra de toute façon servir de saut
En expliquant davantage le problème, il pourrait y avoir une solution plus adaptée
Pour des hôtes quelque peu embarqués, on peut faire en sorte que le DNS se charge du « routage », mais dans ce cas il faut gérer soi-même la vérification de l’empreinte de la clé d’hôte