Artisan Numérique

/système/réseau/ssh/ Les différents canaux de SSH

Pour beaucoup, ssh est simplement l'outil permettant d'ouvrir une session sécurisée sur une machine distante. Et au fond, que devrions-nous comprendre de plus d'un outil appelé Secured Shell ?

En réalité SSH doit plutôt être vu comme un système client-serveur permettant d'établir un tunnel chiffré entre deux machines. Après ce que l'on peut faire de ce tunnel est tout le sujet de cet article.

Un canal pour les entrées/sorties standards

Pour commencer, voyons un peu ce qui se passe lorsque l'on tape un classique ssh gaston@titine.

  1. Le client SSH ouvre un tunnel chiffré sur le service SSHD (démon SSH) du serveur titine.
  2. Le serveur demande le mot de passe de l'utilisateur Gaston et l'authentifie.
  3. Le service SSHD crée un pseudo terminal (PTY) pour Gaston, récupère son shell par défaut (ex. /bin/bash) et le lance en l'associant au PTY.
  4. À partir de maintenant, tout ce qui est saisi sur l'entrée standard du client SSH est expédié au travers du tunnel chiffré vers le PTY distant, et est donc reçu par le shell distant comme si cela avait été saisi en local.
  5. Dans l'autre sens, tout ce que le shell a à nous raconter est envoyé vers son PTY, passe par le tunnel et est écrit sur la sortie standard par SSH.

Dans cette première approche, si l'on oublie deux minutes le PTY, SSH permet donc d'exécuter à distance une commande, le shell, et de l'exploiter comme si elle était locale. Le tunnel est donc ici exploiter pour véhiculer les canaux STDIN/STDOUT et STDERR de la commande distante.

Si l'on ajoute une commande à SSH, par exemple ssh gaston@titine hostname, la dite commande sera exécutée, à distance, au sein du shell de référence de l'utilisateur Gaston. À la différence du cas précédent, le shell n'exécutera que cette commande et mettra fin à ses jours juste après. Cette syntaxe nous permet donc de lancer n'importe quelle commande sur le serveur distant et de prendre en local connaissance de son résultat.

Pour conclure sur cet aspect, voyons deux exemples plus complet :

gastoncat ~/.ssh/id_dsa.pub | <kbd>ssh</kbd> robert@machine "cat >> ~/.ssh/authorized_keys"
Exemple de redirection simple

Ici la commande cat va envoyer le contenu du fichier id_dsa.pub dans l'entrée standard de ssh qui va s'empresser (après authentification) de transmettre cela dans son tunnel chiffré à l'entrée standard de la commande cat qui va l'ajouter au fichier distant authorized_keys. Dans la mesure où c'est Robert qui a lancé la commande, c'est son dossier HOME qui sera utilisé pour le tilde. Pour mémoire, cette commande est une version manuelle de ssh-copy-id.

Deuxième exemple, dans l'autre sens cette fois :

gastonssh gaston@serveur_avec_grosse_ligne "cat ~/Pas.Bien.S01E03.VOSTFR.HDTV.avi" | mplayer -
2nd exemple de redirection simple

Dans cet exemple la lancé dans le shell distant, cat, va débiter un fichier dans la sortie standard. Les données seront expédiées à tracers le tunnel et SSH les relayera sur sa propre sortie standard. Ensuite mplayer récupère ces données pour faire ce qu'il a à faire (le paramètre - dans le monde unix signifie souvent "entrée standard").

Pour ceux qui ne verrais pas à quel point cette commande peut être utile, je n'en dirais pas plus ;-)

Maintenant, SSH permet de véhiculer beaucoup plus de choses que les entrées/sorties standard des commandes. En réalité, et c'est la logique du titre de ce chapitre, SSH va multiplexer son tunnel en différents canaux. Voyons donc les autres.

Un canal pour rediriger un port

Redirection d'un port distant vers un port local

Nous avons vu que SSH fonctionnait comme un tunnel sécurisé permettant de faire passer, de manière chiffrée, des données d'une commande à une autre, l'une locale, l'autre distante. Mais ce ne serait pas rendre hommage à cet outil que de le limiter à ce simple usage.

En effet, ssh est parfaitement capable de faire la même chose mais directement sur un port TCP/IP cette fois. Imaginons un cas classique. J'ai un réseau local utilisant webmin. Ce dernier est un serveur WEB utilisant le port 10000. Or je n'ai pas très envie de publier ce port sur un réseau public, et pourtant pouvoir accéder à cette interface d'administration à distance peut-être très utile. La solution ? Passer par un routage de port avec ssh :

::routage du port distant titine:10000 vers le port local localhost:8080::
gastonssh titine -L 8080:localhost:10000
gaston@titine$

Une fois la commande exécutée et la connexion établie, si vous prenez votre navigateur WEB et que vous allez à l'adresse localhost:8080 (le port 8080 de VOTRE machine locale), la requête va transiter par ssh et être effectuée sur le serveur distant au port localhost:10000. Le résultat de la requête va revenir par le même chemin et s'afficher sur votre navigateur. Et voilà :-)

Alors nous avons utilisé localhost, qui indique ici l'adresse local de la machine distante (faut suivre ;-) ). Cela désigne donc bien titine, mais via son IP locale (127.0.0.1). Cette commande permet donc d'atteindre toutes les machines qui peuvent être accessible de la machine distante, locales ou pas. A méditer très sérieusement lorsque vous ouvrez benoîtement un accès ssh à un tiers...

Redirection d'un port local vers un port distant

Il est aussi possible par ssh d'effectuer l'opération inverse et ainsi autoriser la machine distance à se connecter sur un serveur de votre lan

::Routage du port local localhost:10000 sur le port distant titine:8080::
gastonssh titine -R 8080:localhost:10000
gaston@titine$

Si sur la machine distante je vais cette fois à l'adresse localhost:8080, j'accède en réalité au port 10000 de ma machine locale.

Un tunnel pour les applications graphiques (ou pas)

Le gros point fort de X11, notamment par rapport à ce wayland dont tout le monde parle, c'est sa trop méconnue transparence réseau. En effet, X11 est un serveur graphique auquel se connectent des clients que sont les applications graphiques. Lorsque les clients et le serveur sont locaux, les communications passent par les sockets UNIX, mais lorsque le serveur et les clients ne sont pas sur la même machine, tout passe par le réseau classique.

Du coup, techniquement il est possible de lancer des applications graphiques distantes qui utiliseraient notre serveur X11 local. Pour cela il faudrait :

  1. Modifier le paramétrage du serveur X11 pour accepter les connections externes en modifier /etc/X11/xinit/xserverrc, en enlevant le -nolisten et en relançant X11.
  2. Authoriser les clients à se connecter sur notre serveur par un xhost +
  3. Régler sur la machine distante la variable DISPLAY pour qu'elle pointe sur notre serveur (ex. DISPLAY=MA_MACHINE:0.0).

Bref, pas simple...

Où alors, autre solution, ne rien faire et laisser SSH établir une redirection de port tout seul comme un grand. Ainsi si vous lancez ssh -X machine_distante et qu'une fois connecté vous tapez echo $DISPLAY vous constaterez que la variable a été réglée par ssh à localhost:10.0. Si vous lancez une application dans ce shell, par exemple xcalc, elle va donc se connecter sur le port 6010 (6000 + Numéro du display), et ainsi contacter sans encombre notre serveur X11 local comme n'importe quelle application X11 locale.

Après la viabilité de la solution dépend grandement de la qualité des liaisons mais dans la mesure où X11 a été pensé pour les réseaux 1mb/s, je vous laisse imaginer ce que cela donne sur un réseau local gigabit.

Utilisation du tunnel en proxy SOCKS

SSH complète la panoplie du tunnel chiffré par un outil de poids : un proxy SOCKS.

Un proxy SOCKS est un petit serveur utilisant un protocole permettant à une application qui sait en faire usage (un navigateur WEB, un messenger, un client FTP, etc..) de se connecter sur le net sans avoir directement de connexion à internet. Toutes les demandes de l'application vont donc passer par le proxy SOCKS.

Un proxy SOCKS se distingue d'un Proxy HTTP par le fait qu'il n'est pas spécialisé à un seul protocole (contrairement au cas précédent) mais va router globalement le trafic qu'il soit FTP, HTTP, POP, etc...

Pour utiliser une machine distante comme passerelle internet et la machine locale comme proxy socks, il me suffit donc de lancer la commande suivante :

gastonssh titine -D 3128
gaston@titine$
Établissement d'un proxy SOCKS à partir de la machine distante sur le port local 3128

Et si je configure par exemple FireFox pour utiliser le serveur SOCKS localhost:3128, je vais pouvoir, à travers la connexion SSH, utiliser la connexion Internet de la machine distante sans aucune limite. Je peux aller sur n'importe quelle machine du réseau distant, je peux aussi utiliser la connexion Internet du réseau distant. Bref, faire à peu près ce que je veux. La aussi, c'est le genre de chose à méditer avant de donner sans réfléchir un accès ssh sur une machine.

Un peu de configuration

Créer des automatiquement un canal de redirection

Le client SSH est totalement paramétrable par fichier de configuration. Et comble de la joie, la configuration peut être dans le fichier /etc/ssh/ssh_config mais surtout aussi dans votre dossier perso ~/.ssh/config.

Dans ce fichier il est possible de définir à peu prés tous les aspects de SSH, y compris donc les canaux de redirection. Cela se fait très simplement en ajoutant au fichier de configuration une directive Host

# on ne veut pas de redirection d'affichage par défaut
ForwardX11 no
Host titine
  # routage du port distant titine:10000 vers le port local localhost:8080
  LocalForward=8080 localhost:10000

  # Routage du port local localhost:10000 sur le port distant titine:8080
  RemoteForward=8080 localhost:10000

Host totoche
  # Redirection d'affichage
  ForwardX11 yes

  # Création d'un canal SOCKS5
  DynamicForward 3128
automatisation des redirections

Limiter un peu tout cela...

Il est bien évidement possible de paramétrer le serveur, notamment pour limiter un peu les dégâts d'une ouverture trop sauvage. Dans ce cas, la configuration à modifier se trouve dans le fichier /etc/ssh/sshd_config.

Pour désactiver globalement les redirections, il suffit d'ajouter/modifer la directive AllowTcpForwarding No. Même principe avec la directive X11Forwarding pour la redirection d'affichage.

Vous pouvez aussi (merci à Lord pour la précision :) limiter cela par utilisateur en en ajoutant cette fois une directive Match. À la mode Unix, le principe est donc de désactiver pour tout le monde, et d'activer au cas par cas :

AllowTcpForwarding No
X11Forwarding no
Match User robert
    AllowTCPForwarding yes
    X11Forwarding yes
Activation juste pour l'utilisateur Robert

Dans la série porte blindée sur murs en cartons, la désactivation des redirections n'apporte strictement aucune sécurité si vous autorisez l'accès au shell à un utilisateur.

Conclusion

Ce rapide tour d'horizon nous a permis de voir à quel point SSH est un outil versatile et souple. Et dangereux aussi. A manier donc avec d'infinies précautions dès qu'il s'agit d'ouvrir un accès ssh sur votre machine, ou de laisser passer ssh sur un firewall.