web-dev-qa-db-fra.com

Comment garder un tunnel SSH ouvert de manière fiable?

J'utilise un tunnel SSH depuis le travail pour contourner divers pare-feu idotiques (ça va avec mon patron :)). Le problème, c’est qu’après un certain temps, la connexion SSH se bloque et que le tunnel est rompu.

Si je pouvais au moins surveiller le tunnel automatiquement, je pourrais le redémarrer quand il se bloque, mais je n'ai même pas trouvé le moyen de le faire.

Des points bonus pour celui qui peut me dire comment empêcher ma connexion SSH de rester suspendue, bien sûr!

223
Peltier

On dirait que vous avez besoin de autossh . Ceci surveillera un tunnel ssh et le redémarrera au besoin. Nous l'utilisons depuis quelques années et cela semble bien fonctionner.

autossh -M 20000 -f -N your_public_server -R 1234:localhost:22 -C

Plus de détails sur le paramètre -M ici

267
KeithB

Tous les pare-feu avec état oublient une connexion après ne pas avoir vu un paquet pour cette connexion pendant un certain temps (pour éviter que les tables d'état ne se remplissent de connexions où les deux extrémités sont mortes sans fermer la connexion). La plupart des implémentations TCP enverront un paquet keepalive après une longue période sans avoir à entendre l'autre côté (2 heures est une valeur commune). Si, toutefois, il existe un pare-feu avec état qui oublie la connexion avant que les paquets keepalive puissent être envoyés, une connexion longue durée mais inactive mourra.

Si tel est le cas, la solution consiste à éviter que la connexion ne devienne inactive. OpenSSH a une option appelée ServerAliveInterval qui peut être utilisée pour éviter que la connexion ne soit inactive trop longtemps (en prime, elle détectera le moment où l'homologue est mort plus tôt, même si la connexion est inactive).

37
CesarB

Sur votre propre ordinateur Mac ou Linux, configurez votre SSH pour maintenir le serveur SSH en vie toutes les 3 minutes. Ouvrez un terminal et installez votre .ssh invisible chez vous:

cd ~/.ssh/ 

puis créez un fichier de configuration d'une ligne avec:

echo "ServerAliveInterval 180" >> config

vous devriez aussi ajouter:

ServerAliveCountMax xxxx (high number)

la valeur par défaut est 3; ServerAliveInterval 180 cesse alors d'envoyer après 9 minutes (3 des 3 minutes spécifiées par ServerAliveInterval).

23
David Shaw

J'ai utilisé le script Bash suivant pour continuer à générer de nouveaux tunnels SSH lorsque le précédent est mort. L'utilisation d'un script est pratique lorsque vous ne voulez pas ou ne pouvez pas installer de paquets supplémentaires ni utiliser le compilateur.

while true
do
  ssh <ssh_options> [user@]hostname
  sleep 15
done

Notez que cela nécessite un fichier de clés pour établir la connexion automatiquement, mais c'est également le cas avec autossh.

21
Jawa

Systemd convient parfaitement pour cela.

Créez un fichier de service /etc/systemd/system/sshtunnel.service contenant:

[Unit]
Description=SSH Tunnel
After=network.target

[Service]
Restart=always
RestartSec=20
User=sshtunnel
ExecStart=/bin/ssh -NT -o ServerAliveInterval=60 -L 5900:localhost:5900 user@otherserver

[Install]
WantedBy=multi-user.target

(Modifiez la commande ssh à votre convenance)

  • cela fonctionnera comme utilisateur sshtunnel alors assurez-vous que cet utilisateur existe en premier
  • lancez systemctl enable sshtunnel pour qu'il démarre au démarrage
  • émettez systemctl start sshtunnel pour commencer immédiatement

Mise à jour janvier 2018 : certaines distributions (par exemple, Fedora 27) peuvent utiliser la stratégie SELinux pour empêcher l'utilisation de SSH depuis systemd init. prévoir les exemptions nécessaires.

13
IanB

Il me semble que vous interprétez mal ServerAliveCountMax. Si je comprends bien la documentation, c'est le nombre de messages actifs du serveur qui peuvent rester sans réponse sans que la connexion soit interrompue. Donc, dans les cas comme ceux dont nous discutons ici, définir une valeur élevée garantira simplement qu’une connexion bloquée ne sera ni détectée ni interrompue!

Le simple fait de définir ServerAliveInterval devrait suffire à résoudre le problème avec un pare-feu qui oublie la connexion. Si vous laissez ServerAliveCountMax low, l’auteur de l’origine peut constater l’échec et s’arrêter si la connexion échoue quand même.

Ce que vous voulez, c’est 1) que la connexion reste ouverte en permanence dans des circonstances normales, 2) que l’échec de la connexion soit détecté et que le côté d’origine quitte en cas d’échec, et 3) que la commande ssh soit ré-émise chaque fois exits (la manière dont vous faites cela dépend beaucoup de la plate-forme, le script "while true" suggéré par Jawa est un moyen, sous OS XI, de configurer un élément de lancement).

9
user2793784

Utilisez toujours l'option ServerAliveInterval SSH au cas où les problèmes de tunnel sont générés par des sessions expirées NAT.

Utilisez toujours une méthode de réapparition au cas où la connectivité cesserait complètement, vous avez au moins trois options ici:

  • programme autossh
  • le script bash (while true do ssh ...; sleep 5; done) ne supprime pas la commande de veille, ssh peut échouer rapidement et vous devez réactiver trop de processus
  • /etc/inittab, pour avoir accès à une boîte livrée et installée dans un autre pays, derrière NAT, sans transfert de port à la boîte, vous pouvez le configurer pour créer un tunnel ssh de nouveau à vous:

    tun1:2345:respawn:/usr/bin/ssh -i /path/to/rsaKey -f -N -o "ServerAliveInterval 180" -R 55002:localhost:22 user@publicip 'sleep 365d'
    
  • script upstart sur Ubuntu, où /etc/inittab n'est pas disponible:

    start on net-device-up IFACE=eth0
    stop on runlevel [01S6]
    respawn
    respawn limit 180 900
    exec ssh -i /path/to/rsaKey -N -o "ServerAliveInterval 180" -R 55002:localhost:22 user@publicip
    post-stop script
        sleep 5
    end script
    

ou utilisez toujours les deux méthodes.

9
claudiuf

J'ai résolu ce problème avec ceci:

Modifier

~/.ssh/config

Et ajouter

ServerAliveInterval 15
ServerAliveCountMax 4

Selon page de manuel pour ssh_config:

ServerAliveCountMax
         Sets the number of server alive messages (see below) which may be
         sent without ssh(1) receiving any messages back from the server.
         If this threshold is reached while server alive messages are
         being sent, ssh will disconnect from the server, terminating the
         session.  It is important to note that the use of server alive
         messages is very different from TCPKeepAlive (below).  The server
         alive messages are sent through the encrypted channel and there‐
         fore will not be spoofable.  The TCP keepalive option enabled by
         TCPKeepAlive is spoofable.  The server alive mechanism is valu‐
         able when the client or server depend on knowing when a connec‐
         tion has become inactive.

         The default value is 3.  If, for example, ServerAliveInterval
         (see below) is set to 15 and ServerAliveCountMax is left at the
         default, if the server becomes unresponsive, ssh will disconnect
         after approximately 45 seconds.  This option applies to protocol
         version 2 only.

 ServerAliveInterval
         Sets a timeout interval in seconds after which if no data has
         been received from the server, ssh(1) will send a message through
         the encrypted channel to request a response from the server.  The
         default is 0, indicating that these messages will not be sent to
         the server.  This option applies to protocol version 2 only.
6
nachopro

ExitOnForwardFailure yes est un bon complément aux autres suggestions. S'il se connecte mais ne peut pas établir la redirection de port, il vous sera tout aussi inutile que s'il ne s'était pas connecté du tout.

3
jcomeau_ictx

Un peu de bidouille, mais j'aime bien utiliser screen pour le garder. J'ai actuellement une avance à distance qui fonctionne depuis des semaines.

Exemple, en commençant localement:

screen
ssh -R ......

Lorsque le transfert à distance est appliqué et que vous avez un shell sur l'ordinateur distant:

screen
Ctrl + a + d

Vous avez maintenant un transfert à distance ininterrompu. L'astuce consiste à lancer l'écran des deux côtés

1
landypro

J'ai récemment eu ce problème moi-même, car ces solutions vous obligent à ressaisir le mot de passe chaque fois que vous utilisez un identifiant de mot de passe. J'ai utilisé sshpass dans une boucle avec une invite de texte pour éviter d'avoir le mot de passe dans le fichier de commandes.

Je pensais partager ma solution sur cette thead au cas où quelqu'un d'autre aurait le même problème:

#!/bin/bash
read -s -p "Password: " pass
while true
do
    sshpass -p "$pass" ssh user@address -p port
    sleep 1
done
1
Brainfloat

J'ai eu besoin de maintenir un tunnel SSH à long terme. Ma solution fonctionnait à partir d'un serveur Linux, et il ne s'agit que d'un petit programme en C qui rappelle ssh en utilisant une authentification par clé.

Je ne suis pas sûr de la pendaison, mais des tunnels sont morts suite à des délais trop longs.

J'adorerais fournir le code au répondant, mais je n'arrive pas à le trouver pour le moment.

1
baumgart

bien qu'il existe des outils comme autossh qui aident à redémarrer la session SSH ... ce que je trouve vraiment utile, c'est de lancer la commande "screen". Il vous permet de reprendre vos sessions SSH même après votre déconnexion. Particulièrement utile si votre connexion n’est pas aussi fiable qu’elle devrait l’être.

... n'oubliez pas de cocher la réponse "correcte" si cela vous aide à k! ;-)

1
koss

Comme autossh ne répond pas à nos besoins (il existe une erreur s'il ne parvient pas à se connecter au serveur dès la première tentative), nous avons écrit une application pure bash: https://github.com/aktos-io/link-with-server

Il crée un tunnel inverse pour le port sshd (22) du NODE sur le serveur par défaut. Si vous devez effectuer d'autres opérations (telles que le transfert de ports supplémentaires, l'envoi de mails en connexion, etc.), vous pouvez placer vos dossiers de scripts on-connect et on-disconnect.

0
ceremcem

J'ai eu des problèmes similaires avec mon précédent fournisseur de services Internet. Pour moi, c'était la même chose avec n'importe quelle connexion TCP, visite de sites Web ou envoi de courrier.

La solution consistait à configurer une connexion VPN sur UDP (j'utilisais OpenVPN). Cette connexion était plus tolérante vis-à-vis de la cause des déconnexions. Ensuite, vous pouvez exécuter n'importe quel service via cette connexion.

Il peut toujours y avoir des problèmes avec la connexion, mais puisque le tunnel sera plus tolérant, toute session SSH ressentira un bref blocage plutôt que d'être déconnectée.

Pour ce faire, vous aurez besoin d’un service VPN en ligne que vous pouvez configurer sur votre propre serveur.

0
hultqvist