Redirection de port avec OpenSSH
Suite à notre article sur l’utilisation des rebonds SSH, nous allons à présent passer en revue différentes façons de réaliser des redirections de port. En effet, il est parfois nécessaire de rediriger un flux de données de notre machine locale vers un serveur distant, ou à l’inverse, du serveur distant vers notre machine. On parle alors de SSH tunneling ou de SSH port forwarding.
Il existe trois types de transfert de port SSH :
- Redirection locale de port
- Redirection distante de port
- Transfert dynamique de port
Nous allons ici nous intéresser aux redirections locales et distantes de port. Aussi, pour illustrer nos propos, nous prendrons l’architecture suivante comme exemple.
Dans tous les exemples qui suivront, nous nous placerons en tant que l’utilisateur Bob, avec la configuration de départ suivante :
bob:~$ ls -l .ssh/
total 32
-rw-r--r-- 1 demo demo 227 May 11 14:32 config
-rw------- 1 demo demo 387 May 11 14:19 id_ed25519
-rw-r--r-- 1 demo demo 85 May 11 14:19 id_ed25519.pub
-rw-r--r-- 1 demo demo 193 May 11 14:32 known_hosts
bob:~$ cat ~/.ssh/id_ed25519.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINOhMAfcAVBTLJ3qgT3Nv3YDWwCjYRYjbsSW5lP8wcUt bob
bob:~$ cat .ssh/config
Host server_A
Hostname server_A
User admin
PubkeyAuthentication yes
IdentityFile ~/.ssh/id_ed25519
Host server_B
Hostname 10.0.0.2
User admin
PubkeyAuthentication yes
IdentityFile ~/.ssh/id_ed25519
ProxyJump server_A
Redirection locale de port
La redirection locale de port permet de transférer le flux TCP d’un port de notre système vers un port d’une machine distante, qui est ensuite transférée vers un port de cette dernière.
Avec ce type de transfert de port, le client SSH écoute sur un port donné et route toutes connexions vers ce port vers le port distant souhaité. La machine de destination peut être l’hôte sur lequel se trouve le serveur SSH auquel on s’adresse ou toute autre machine qui peut être atteinte par celui-ci.
La syntaxe à utiliser est la suivante :
$ ssh -L [LOCAL_IP:]LOCAL_PORT:DESTINATION:DESTINATION_PORT [USER@]SSH_SERVER
Les paramètres [LOCALIP]:LOCALPORT correspondent à l’adresse IP et le numéro de port de la machine locale, celle depuis laquelle on initie la connexion SSH. Lorsque LOCALIP_ est omis, le client OpenSSH se lie sur localhost. Les paramètres DESTINATION:DESTINATION_PORT correspondent à l’adresse IP ou le nom d’hôte et le port de la machine de destination, c’est à dire le serveur vers lequel on souhaite rediriger le traffic local. Puis finalement, les paramètres [USER@]SERVER_IP, correspondent à l’utilisateur, et l’adresse IP ou le nom d’hôte du serveur SSH.
Intéressons nous à un exemple. Installons et configurons un serveur HTTP sur le serveur B, qui écoute sur toutes ses interfaces réseaux, or ce serveur n’est pas accessible directement depuis l’Internet. Il est nécessaire de passer par l’intermédiaire du bastion A.
bob:~$ ssh server_B netstat -nlt | grep 80
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN
tcp6 0 0 :::80 :::* LISTEN
bob:~$ ssh server_A curl -s http://10.0.0.2
Hello, world!
Nous souhaitons ici pouvoir utiliser notre navigateur pour effectuer les requêtes HTTP depuis notre poste de travail. On peut alors faire comme ceci :
bob:~$ ssh -L 8080:127.0.0.1:80 server_B
Last login: Tue May 11 15:03:49 2021 from 10.0.0.1
admin@b:~$
On obtient un pseudo-terminal sur le serveur B, mais si on regarde les ports ouverts sur notre machine, on observe que le port 8080 a été ouvert.
bob:~$ netstat -nat | grep LISTEN
tcp 0 0 127.0.0.1.8080 *.* LISTEN
tcp6 0 0 ::1.8080 *.* LISTEN
Désormais, les requêtes HTTP envoyées sur 127.0.0.1:8080 sont redirigées dans le tunnel SSH vers le port 80 du serveur B. On peut donc faire :
bob:~$ curl http://127.0.0.1:8080
Hello, world!
On a bien le résultat souhaité puisque le serveur HTTP du serveur B nous a répondu.
On aurait très bien pu faire autrement. En effet, puisque le serveur B est sur le même sous-réseau que le serveur A, et que dans notre cas, les règles de pare-feux en vigueur de chaque côté le permettent, les requêtes HTTP peuvent être émises depuis le serveur A. On doit alors changer le paramètre DESTINATION en positionnant l’adresse IP du service HTTP.
bob:~$ ssh -L 8080:10.0.0.2:80 server_B
Last login: Tue May 11 15:29:18 2021 from 10.0.0.1
admin@b:~$
Et on obtient le même résultat que précédement.
bob:~$ curl http://127.0.0.1:8080
Hello, world!
Il est également possible de faire en sorte que la connexion SSH n’aboutisse pas à l’obtention d’un pseudo-terminal. Il faut alors renseigner les options suivantes, -f pour que le client OpenSSH s’exécute en tâche de fond, et -N pour ne pas exécuter de commande sur le serveur SSH sur lequel on se connecte.
bob:~$ ssh -f -N -L 8080:10.0.0.2:80 server_B
Cependant, il devient nécessaire de tuer le processus correspondant dès lors que l’on souhaite mettre un terme à la redirection de ports.
Redirection distante de port
La redirection distante de port est l’opposée de la redirection locale de port. Elle permet de rediriger un port de la machine distante vers un port de la machine locale, qui est ensuite redirigé vers un port de la machine de destination. Elle est principalement utilisée pour donner accès à un service interne à une machine à l’extérieur du réseau sur lequel ce trouve ce service.
La syntaxe de la commande est la suivante :
$ ssh -R [REMOTE:]REMOTE_PORT:DESTINATION:DESTINATION_PORT [USER@]SSH_SERVER
Les paramètres [REMOTE:]REMOTE_PORT représente l’adresse IP et le port sur le serveur SSH distant. Lorsque REMOTE est omis, cela signifie que le port REMOTE_PORT devra être lié à toutes les interfaces réseaux. Les paramètres DESTINATION:DESTINATION_PORT, représentent l’adresse IP, ou le nom d’hôte, et le port de la machine de destination. Puis finalement, les paramètres [USER@]SERVER_IP, correspondent à l’utilisateur, et l’adresse IP ou le nom d’hôte du serveur SSH.
Comme précédement, intéressons nous à un exemple. Cette fois-ci, considérons un serveur HTTP, non pas sur le serveur B, mais sur notre propre machine. Le serveur B ne peut accéder directement à notre service HTTP car celui-ci n’est pas exposé à l’Internet.
bob:~$ netstat -nlt | grep 80
tcp 0 0 127.0.0.1:80 0.0.0.0:* LISTEN
bob:~$ curl -s http://127.0.0.1
Hello, world!
Nous souhaitons rediriger le flux TCP du port 8080 du serveur B sur le port 80 de notre environnement. On peut alors faire :
bob:~$ ssh -R 8080:127.0.0.1:80 server_B
Last login: Tue May 11 16:04:41 2021 from 10.0.0.1
admin@b:~$ netstat -nlt | grep 8080
tcp 0 0 127.0.0.1:8080 0.0.0.0:* LISTEN
On observe que le port 8080 à bien été ouvert sur le serveur B. Aussi, il est désormais possible depuis ce même serveur de joindre le service HTTP de la machine depuis laquelle a été initié le tunnel SSH.
admin@b:~$ curl -s http://127.0.0.1:8080
Hello, world!
La redirection distante de port est moins fréquemment utilisée, mais permet de faire des choses très intéressantes. Elle permet, entre autres, de contourner des règles de filtrages de flux réseau par pare-feux, en réalisant ce que l’on appelle des tunnels SSH inversés, afin de donné un accès Internet non restrictif à une machine sur lequel nous avons au moins un accès SSH. Cependant, son usage peut parfois jouer des tours, comme nous avons pu le voir dans l’article relatant l’exploitation d’un mauvais usage de cette fonctionnalité.