Reverse ssh : Accéder à un serveur derrière un NAT - Firewall
De wikiGite
Sommaire
Avec au moins un accès externe
Un des serveurs du réseau local protégé par un firewall est accessible en SSH depuis l'extérieur. Lui-même a ensuite accès aux autres serveurs du réseau local.
On peut, en ligne de commande, passer par ce serveur pour en atteindre un autre (Tunnel_SSH_via_un_serveur_intermédiaire).
On peut aussi se servir de du paramètre ProxyCommand, dans ce cas le plus simple est de préconfigurer la connexion par le fichier .ssh/config du poste local. On y déclare :
Host serveur_intermediaire Hostname serveur_intermediaire.domain.com User root ForwardAgent yes Host serveur_de_destination Hostname 192.168.0.200 User admin ProxyCommand ssh serveur_intermediaire -q -W %h:%p
"ForwardAgent" : transférer l'agent local (donc notre config) sur le reverse proxy "Hostname 192.168.0.200" : pour le serveur final on utilise l'adresse réseau interne, celle connue du serveur_intermediaire
On a plus qu'à se connecter par
ssh serveur_de_destination
et l'agent + proxyCommand font le reste.
Sans aucun accès externe
Le serveur A se trouvant derriere le par-feu créé un tunnel vers le serveur B. Depuis B on se connecte au serveur A au travers du tunnel ssh.
Prérequis
Ajouter cette ligne dans /etc/ssh/sshd_config sur B:
AllowTcpForwarding yes
Par sécurité créer un utilisateur dédié au tunnel sur B :
adduser userssh
Reverse ssh
Le port 22222 de l'exemple suivant doit se trouver entre 1024 et 65535. Il faut evidement tenir une liste des ports associés aux machines.
Créez le tunnel sur le serveur A :
ssh -NR 22222:localhost:22 userssh@serveurB
Se connecter au tunnel depuis le serveur B
ssh -p 22222 rootA@127.0.0.1
Lancement automatique sur le serveur A avec autossh
aptitude install autossh
Générer une paire de clef avec root
ssh-keygen -t dsa
Faire un echange de clef avec le serveur B:
ssh-copy-id -i /root/.ssh/id_dsa.pub userssh@serveurB
En l’exécutant au démarrage (rc.local)
ajouter dans /etc/rc.local :
autossh -i /root/.ssh/id_dsa -NR 22222:localhost:22 userssh@serveurB &
En créant un script d'init
SYSVINIT
Créer un script dans /etc/init.d/autosshd et remplacer les variables REMOTE_ADDR et LISTEN_PORT :
#!/bin/bash
### BEGIN INIT INFO
# Provides: autosshd
# Required-Start:
# Required-Stop:
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: starts the autossh daemon
# Description: starts autossh
### END INIT INFO
REMOTE_USER="userssh"
REMOTE_ADDR="test.systea.fr"
LISTEN_PORT="22222"
DAEMON="/usr/bin/autossh"
DESC="Autossh daemon"
LOGFILE="/var/log/autossh.log"
PIDFILE="/tmp/$REMOTE_USER-$REMOTE_ADDR.pid"
export AUTOSSH_PIDFILE=/tmp/$REMOTE_USER-$REMOTE_ADDR.pid
test -f $DAEMON || exit 0
is_running() {
if [ -f $PIDFILE ]; then
PID=`cat $PIDFILE`
if [ -n "$PID" ]; then
return 0
else
return 1
fi
else
return 1
fi
}
start_autossh() {
if ! is_running; then
echo -n "Starting $DESC"
$DAEMON -i /root/.ssh/id_dsa -NR $LISTEN_PORT:localhost:22 $REMOTE_USER@$REMOTE_ADDR >> $LOGFILE 2>&1 &
sleep 1;
if is_running; then
echo " [DONE] : Running @ pid $PID "
else
echo '[FAIL]';
fi
else
echo "[FAIL] Already running (pid $PID)"
fi
}
stop_autossh() {
if is_running; then
echo -n "Stopping $DESC: "
kill -s SIGTERM $PID
echo "[DONE]"
else
echo "[FAIL] : Not running "
fi
[ -f $APIDFILE ] && rm -f $PIDFILE
}
case "$1" in
start)
start_autossh
;;
stop)
stop_autossh
;;
force-reload|restart)
stop_autossh
start_autossh
;;
status)
if is_running; then
echo "$DESC: running (pid $PID)"
exit 0
else
echo "$DESC: not running"
[ -f $PIDFILE ] && exit 1 || exit 3
fi
;;
log)
if [ -f $LOGFILE ]; then
tail $LOGFILE
else
echo "[FAIL] : log file '$LOGFILE' does't exist"
fi
;;
*)
echo "Usage: $0 {start|stop|restart|force-reload|status|log}"
exit 3
;;
esac
exit 0
Autoriser l'execution du script :
chmod +x /etc/init.d/autosshd
Ajouter le script au démarage :
update-rc.d autosshd defaults
SYSTEMD
En créant un script /etc/systemd/system/foo-autossh.service
[Unit]
Description=AutoSSH service for a reverse tunnel from foo to bar
After=network.target
[Service]
User=autossh
# -p [PORT]
# -l [user]
# -M 0 --> no monitoring
# -N Just open the connection and do nothing (not interactive)
# LOCALPORT:IP_ON_EXAMPLE_COM:PORT_ON_EXAMPLE_COM
ExecStart=/usr/bin/autossh -M 0 -f -N -T -q -o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" -R 22222:localhost:22 userssh@serveurB
ExecStop=killall -s KILL autossh
Restart=always
RestartSec=60
[Install]
WantedBy=multi-user.target
Se connecter à d'autres ports
On souhaite par exemple se connecter à un serveur web se trouvant sur A.
Sur A :
ssh -NR 22280:localhost:80 userssh@serveurB
Sur B :
firefox "http://127.0.0.1:22280"
Se connecter à partir d'un poste client
Poste ---> INTERNET ---> serveurB ---> INTERNET ---> serveurA
Sur le poste on lance :
ssh root@serveurB -t ssh -p 22222 root@127.0.0.1