Utilisez Expect dans un script Bash pour fournir un mot de passe à une commande SSH

131

J'essaie d'utiliser Expect dans un script Bash pour fournir le mot de passe SSH. Fournir le mot de passe fonctionne, mais je ne me retrouve pas dans la session SSH comme je le devrais. Il remonte le détroit à Bash.

Mon scénario:

#!/bin/bash

read -s PWD

/usr/bin/expect <<EOD
spawn ssh -oStrictHostKeyChecking=no -oCheckHostIP=no usr@$myhost.example.com'
expect "password"
send "$PWD\n"
EOD
echo "you're out"

La sortie de mon script:

spawn ssh -oStrictHostKeyChecking=no -oCheckHostIP=no usr@$myhost.example.com
usr@$myhost.example.com's password: you're out

Je voudrais avoir ma session SSH et, seulement quand je la quitte, retourner à mon script Bash.

La raison pour laquelle j'utilise Bash avant Expect est que je dois utiliser un menu. Je peux choisir à quel appareil / appareil me connecter.

À ceux qui veulent répondre que je devrais utiliser des clés SSH, veuillez vous abstenir.

Max
la source
49
s'il vous plaît voir la première ligne: à ceux qui veulent répondre que je devrais utiliser les clés SSH s'il vous plaît abstenez-vous
Max
54
Je modifierais votre première ligne pour être un peu plus conviviale. Vous pourriez envisager quelque chose comme "En raison de contraintes, je ne peux tout simplement pas utiliser les clés SSH, je dois trouver un moyen de le faire fonctionner avec expect". Vous devriez vous attendre à ce que les gens soient naturellement curieux de savoir pourquoi vous n'utilisez pas de clés et essaient simplement d'être utiles :) @Ignacio n'a pas suggéré que vous les utilisiez , il le confirmait simplement comme une contrainte et non comme un oubli.
Tim Post
J'essaierais d'utiliser kermit dans ce cas. Il a un langage de script très robuste columbia.edu/kermit/skermit.html#scripts
f3xy

Réponses:

86

Mélanger Bash et Expect n'est pas un bon moyen d'obtenir l'effet souhaité. J'essaierais d'utiliser uniquement Expect:

#!/usr/bin/expect
eval spawn ssh -oStrictHostKeyChecking=no -oCheckHostIP=no usr@$myhost.example.com

# Use the correct prompt
set prompt ":|#|\\\$"
interact -o -nobuffer -re $prompt return
send "my_password\r"
interact -o -nobuffer -re $prompt return
send "my_command1\r"
interact -o -nobuffer -re $prompt return
send "my_command2\r"
interact

Exemple de solution pour bash:

#!/bin/bash
/usr/bin/expect -c 'expect "\n" { eval spawn ssh -oStrictHostKeyChecking=no -oCheckHostIP=no usr@$myhost.example.com; interact }'

Cela attendra Enter, puis reviendra (pendant un moment) à la session interactive.

Piotr Król
la source
1
cela fonctionne très bien, merci. Que faire si je souhaite saisir la commande une fois que je suis connecté via SSH, que dois-je faire?
Max
Ce script doit renvoyer un shell inéractif avec l'utilisateur connecté. Je ne comprends pas la question. Si vous voulez absolument utiliser le même script dans bash, regardez l'entrée modifiée.
Piotr Król
De la même manière que j'envoie le mot de passe lorsque vous y êtes invité, je voudrais envoyer des commandes système une fois connecté.
Max
Le code Samlple a été ajouté au message ci-dessus. Bien sûr, cela fonctionnera jusqu'à ce que my_commandX ne change pas l'invite renvoyée, si cela se produit, la variable d'invite doit être modifiée.
Piotr Król le
@pietrushnic pouvez-vous expliquer un peu pourquoi utiliser "interact -o -nobuffer -re $ prompt return", au lieu de "expect $ prompt"? ce dernier semble plus couramment utilisé.
Richard
53

Le moyen le plus simple est d'utiliser sshpass . Ceci est disponible dans les référentiels Ubuntu / Debian et vous n'avez pas à vous occuper de l'intégration expect avec Bash.

Un exemple:

sshpass -p<password> ssh <arguments>
sshpass -ptest1324 ssh user@192.168.1.200 ls -l /tmp

La commande ci-dessus peut être facilement intégrée à un script Bash.

Remarque: Veuillez lire la section Considérations relatives à la sécuritéman sshpass pour une compréhension complète des implications en matière de sécurité.

dotnix
la source
Je ne sais pas si c'est une bonne solution, mais cela simplifie certainement beaucoup. Merci
erikbwork
9
Très dangereux du point de vue de la sécurité - les arguments de ligne de commande peuvent être lus par tout autre processus du système. Il est possible de les écraser, et j'espère le sshpassfaire, mais même dans ce cas, il y a un certain temps pendant le démarrage avant qu'il ne puisse le faire lorsque le mot de passe est disponible pour tout / chaque processus à voir.
Charles Duffy
1
@CharlesDuffy Bien sûr, vous avez raison. sshpassest utilisé dans un scénario où vous avez des scripts de test simples qui s'exécutent dans un environnement de réseau local où la sécurité n'est pas la principale préoccupation. En fait, il y a une section dans man sshpasslaquelle une section entière sur les considérations de sécurité est expliquée. Ajouté ceci pour répondre, merci.
dotnix
@ erikb85 Habituellement, un paquet fait tout le sale truc pour vous, mais, dans tous les cas, ces scripts sont construits juste pour cet usage, alors ce serait mieux que d'ajouter vos propres trucs. Ce commentaire concerne ne pas réinventer la roue. Ne traitez les choses difficiles que si personne ne les a encore traitées. sshpass c'est une bonne fonction.
m3nda
2
Par souci d'exhaustivité, je mentionne que "man sshpass" délivre des avertissements de sécurité appropriés à l'utilisateur potentiel, souligne que "-p" est le moyen le moins sûr de l'utiliser et propose l'option "-e" pour prendre le mot de passe via la variable d'environnement , ce qui au moins le maintient hors de la ligne de commande.
Ron Burk
22

Ajoutez la commande 'interact' Expect juste avant votre EOD:

#!/bin/bash

read -s PWD

/usr/bin/expect <<EOD
spawn ssh -oStrictHostKeyChecking=no -oCheckHostIP=no usr@$myhost.example.com
expect "password"
send "$PWD\n"
interact
EOD
echo "you're out"

Cela devrait vous permettre d'interagir avec la machine distante jusqu'à ce que vous vous déconnectiez. Ensuite, vous serez de retour à Bash.

dr-jan
la source
Il entre et ressort immédiatement. "vous êtes absent" est imprimé.
Emmanuel
8
J'ai remplacé "interagir" et "EOD" par "expect eof" et cela a fonctionné pour moi. Ceci est sur un Mac.
Emmanuel
2
Aucune des réponses sur cette page n'a fonctionné pour moi, mais la suggestion d'utiliser @ Emmanuel a expect eofrésolu le problème.
moertel
Retirez le 'de usr@$myhost.example.com'et cela devrait fonctionner. Et peut-être que vous devez remplacer \npar \r, mais YMMV
Tino
20

Après avoir cherché une réponse à la question pendant des mois, je trouve enfin la meilleure solution: écrire un script simple.

#!/usr/bin/expect

set timeout 20

set cmd [lrange $argv 1 end]
set password [lindex $argv 0]

eval spawn $cmd
expect "Password:"
send "$password\r";
interact

Mettez-le /usr/bin/exp, alors vous pouvez utiliser:

  • exp <password> ssh <anything>
  • exp <password> scp <anysrc> <anydst>

Terminé!

damn_c
la source
expect "assword:"vouliez-vous dire expect "password:"?
utilisateur
1
@user "assword"correspondra à la fois Passwordet password.
Ferdinand.kraft
8

Assurez-vous également d'utiliser

send -- "$PWD\r"

à la place, les mots de passe commençant par un tiret (-) échoueront autrement.

Ce qui précède n'interprète pas une chaîne commençant par un tiret comme une option de la commande d'envoi.

Timmah
la source
8

Un simple script Expect:

Fichier Remotelogin.exp

    #!/usr/bin/expect
    set user [lindex $argv 1]
    set ip [lindex $argv 0]
    set password [lindex $argv 2]
    spawn ssh $user@$ip
    expect "password"
    send "$password\r"
    interact

Exemple:

./Remotelogin.exp <ip> <user name> <password>
Vijay SB
la source
7

Utilisez l'outil d'aide fd0ssh (de hxtools, pas de pmt). Cela fonctionne sans avoir à attendre une invite particulière du sshprogramme.

user562374
la source
C'est bien! C'est un peu difficile de le faire fonctionner (au moins sur le serveur ubuntu) mais ça fonctionne bien! La config que nous avons faite: echo "yoursshpass" | fd0ssh ssh -c -L$port:$ip:$remote_port [email protected] & MERCI!
JP Illanes
1
Beaucoup plus sûr que de passer le mot de passe sur la ligne de commande comme le sshpassfait.
Charles Duffy
5

Une autre façon que j'ai trouvée utile d'utiliser un petit script Expect à partir d'un script Bash est la suivante.

...
Bash script start
Bash commands
...
expect - <<EOF
spawn your-command-here
expect "some-pattern"
send "some-command"
...
...
EOF
...
More Bash commands
...

Cela fonctionne parce que ...If the string "-" is supplied as a filename, standard input is read instead...

Jimbo
la source
Vous n'avez pas besoin de -ici, car il expectlit stdinpar défaut si vous l'appelez sans argument. Cependant, il est utile si vous voulez l'exécuter de manière interactive sans invite de commande ( expectvs. expect -) ou si vous faites quelque chose comme expect -f "$@"où le premier argument doit être un fichier, même si cela ressemble à une option (commence par -). Dans ce cas, si $1(le fichier donné) est- -ce lu à partir de stdin.
Tino
1

sshpassest cassé si vous essayez de l'utiliser dans une cible de construction Sublime Text , dans un Makefile. Au lieu de sshpass, vous pouvez utiliser passh: https://github.com/clarkwang/passh

Avec sshpasstoi ferais:

sshpass -p pa$$word ssh user@host

Avec passhtoi ferais:

passh -p pa$$word ssh user@host

Remarque: n'oubliez pas d'utiliser -o StrictHostKeyChecking=no. Sinon, la connexion se bloquera la première fois que vous l'utiliserez. Par exemple:

passh -p pa$$word ssh -o StrictHostKeyChecking=no user@host

Références:

  1. La commande d'envoi de mot de passe ne fonctionne pas à l'aide du script Expect dans la connexion SSH
  2. Comment puis-je désactiver la vérification stricte de la clé d'hôte dans ssh?
  3. Comment désactiver la vérification de la clé d'hôte SSH
  4. scp sans vérification de known_hosts
  5. pam_mount et sshfs avec authentification par mot de passe
utilisateur
la source