% Tunnel SSH avec reverse

# Introduction

L'idée est d'ouvrir un tunnel SSH qui passe par un serveur relai.

Le poste de travail (poste) se connecte à la cible via le relai.

```
        ____________           ____________
poste -------------->[ relai ]-------------> cible
 p_tun >> Tunnel(L) >> p_relai << Tunnel(R) <<port_ssh
        ____________           _____________
```

## Définition d'un tunnel `local to server`  :

```
port client SSH >> Tunnel(L) >> port serveur SSH
```

## Définition d'un tunnel `reverse from server`  :

```
port client SSH << Tunnel(R) << port serveur SSH
```

## Exemple

```
        __________           _________
poste ------------>[ relai ]-----------> cible
  6122>> Tunnel(L) >>6022<< Tunnel(R) <<22
        __________           _________
```

- 6122 port d'entrée (1 = in)
- 6022 port de sortie du tunnel poste > relai (0 = out)
- 22 port SSH de la cible

# Mise en application

## IPI

- `<poste>`: mon poste de travail (port 6122 sera relié au port 22 de la cible)
- `<relai>`: `luke`
  - (port `6022` reliera la sortie du tunnel entrant (poste > relai) à l'entrée du tunnel reverse (relai > cible))
- `<cible>`: `proxmox-patrick`

Exemple serveur IPI: adresse publique: `185.64.149.17`

## Création d'une paire de clé sur la cible

En tant qu'utilisateur standard (nom = `u_ssh_cible`)

Générer une paire de clé privé/publique sur la `<cible>` **SANS** *passphrase*.

Copier la clé publique (elle sera copiée dans le fichier `authorized_keys` de l'utilisateur `tunnel@<relai>`)

## Mise en place du relai

### Création d'un utilisateur `tunnel` sur `<relai>`

#### Fichier `authorized_keys` pour l'utilisateur `tunnel`

Préfixe:

```
from="185.64.149.17",no-agent-forwarding,no-pty,no-X11-forwarding,permitopen="localhost:6022",command="/home/tunnel/bin/tunnelcheck"
```

Copie de la clé publique de la `<cible>`:

```
from="185.64.149.17",no-agent-forwarding,no-pty,no-X11-forwarding,permitopen="localhost:6022",command="/home/tunnel/bin/tunnelcheck" ssh-ed25519 AAAACccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc u_ssh_cible@cible
```

#### Création du script de vérification du tunnel

Sur la machine `<relai>`

```bash
mkdir bin
touch bin/tunnelcheck
chmod +x bin/tunnelcheck
```

Copier le code suivant dans `bin/tunnelcheck` :

```bash
#!/bin/bash
set -Eeuo pipefail

parameters=(${SSH_ORIGINAL_COMMAND-})

if [[ ${#parameters[@]} -gt 1 ]]
then
	server_response=$(ssh -o PasswordAuthentication=no -p ${parameters[1]} -n -f localhost exit 2>&1 | cut -c1-17 || echo "")
	if [[ ${server_response:-} = "Permission denied" ]]
	then
		echo TUNNEL_OK
		exit 0
	else
		echo TUNNEL_KO
		exit 1
	fi
fi
```

## Mise en place du reverse tunnel sur `<cible>`

### Lancement initial

```bash
ssh -f -T -N -R 6022:localhost:22 tunnel@relai.aezi.fr
```

#### Vérification depuis le `<relai>`

Depuis le `<relai>` en tant qu'utilisateur `tunnel`, lancer:

```bash
SSH_ORIGINAL_COMMAND="tunnel_check 6022" /home/tunnel/bin/tunnelcheck
```

:::important

Procéder à la vérification des *fingerprint* si nécessaire

:::

### Mise en place du `crontab`

Sur la machine `<cible>` (en tant qu'`u_ssh_cible` ):

```bash
crontab -e
```

Coller la ligne suivante:

```
*/30 * * * * /usr/bin/ssh tunnel@relai.aezi.fr /home/tunnel/bin/tunnelcheck 6022 && echo OK || /usr/bin/ssh -f -T -N -R 6022:localhost:22 tunnel@relai.aezi.fr
```

## Depuis le `<poste>` de travail

Ouverture du tunnel vers le `<relai>`

```
ssh -f -T -N -L 6122:localhost:6022 tunnel@relai.aezi.fr
```

### Connection

```bash
ssh -p 6122 u_ssh_cible@localhost
```

### 


```bash
# Sur ma machine
ssh -f -T -N -L 6122:localhost:6022 tunnel@relai.aezi.fr
ssh -L 55522:localhost:55555 tunnel@relai.aezi.fr

# Pour se connecter
ssh -p 55522 laurent@127.0.0.1

```

## IMPORTANT: à la première connection

Vérifier les *fingerprint*



# Finalisation de la sécurisation

Désactiver l'utilisateur `tunnel`

### Sur le serveur cible

```bash
#!/bin/bash

#autossh -f -M 0 -N -o "ServerAliveInterval 10" -o "ServerAliveCountMax 3" -T -N -R 22:localhost:55555 tunnel@relai.aezi.fr
#autossh -v -M 0 -o "ServerAliveInterval 10" -o "ServerAliveCountMax 3" -T -N -f -R 55555:localhost:22 tunnel@relai.aezi.fr
autossh -v -M 55556 -T -N -f -R 55555:localhost:22 tunnel@relai.aezi.fr
#ssh -v -f -N -T -R 55555:localhost:22 tunnel@relai.aezi.fr

```


# Solution Maison

Côté serveur

```
ssh tunnel@relai.aezi.fr /home/tunnel/bin/tunnelcheck 55555 && echo OK || ssh -f -T -N -R 55555:localhost:22 tunnel@relai.aezi.fr
```

Côté relai

```bash
$ cat bin/tunnelcheck
#!/bin/bash
set -Eeuo pipefail

parameters=(${SSH_ORIGINAL_COMMAND-})

if [[ ${#parameters[@]} -gt 1 ]]
then
	server_response=$(ssh -o PasswordAuthentication=no -p ${parameters[1]} -n -f localhost exit 2>&1 | cut -c1-17 || echo "")
	if [[ ${server_response:-} = "Permission denied" ]]
	then
		echo TUNNEL_OK
		exit 0
	else
		echo TUNNEL_KO
		exit 1
	fi
fi
```

Pour tester côté relai:

```bash
$ SSH_ORIGINAL_COMMAND="tunnel_check 55555" bin/tunnelcheck
```


# Sources

Gestion des sessions et du contrôle

- [shell script - Getting a pid for an ssh process that backgrounded itself - Unix & Linux Stack Exchange](https://unix.stackexchange.com/questions/389014/getting-a-pid-for-an-ssh-process-that-backgrounded-itself)
- [linux - How to tell if an ssh ControlMaster connection is in use - Server Fault](https://serverfault.com/questions/211213/how-to-tell-if-an-ssh-controlmaster-connection-is-in-use)

