Use expect no script bash para fornecer senha ao comando SSH

131

Para aqueles que querem responder que eu deveria usar as chaves SSH, abstenha-se

Estou tentando usar o expect em um script bash para fornecer a senha SSH. Desde que a senha funcione, mas eu não terminei a sessão do SSH como deveria, ela volta diretamente ao bash.

Meu script:

#!/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"

A saída do meu script:

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

Gostaria de ter minha sessão SSH e somente quando a sair para voltar ao meu script bash. A razão pela qual estou usando o bash antes do esperado é porque usei um menu no qual posso escolher a qual unidade conectar.

obrigado

Máx.
fonte
49
consulte primeira linha: Para aqueles que querem responder que eu deveria usar chaves SSH agradar abster
Max
54
Eu editaria sua primeira linha para ser um pouco mais amigável. Você pode considerar algo como "Devido a restrições, simplesmente não consigo usar chaves SSH, preciso encontrar uma maneira de fazê-lo funcionar com expect". Você deve esperar que as pessoas possam estar naturalmente curiosas por que você não está usando chaves e só está tentando ser útil :) @Ignacio não sugeriu que você as usasse, ele estava simplesmente confirmando isso como uma restrição e não uma supervisão.
Tim Post
Eu tentaria usar o kermit neste caso. Tem um muito robustas de linguagem de script columbia.edu/kermit/skermit.html#scripts
f3xy

Respostas:

86

Misturar bash e expect não é uma boa maneira de obter o efeito desejado. Eu tentaria usar apenas o Expect:

#!/usr/bin/expect
eval spawn ssh -oStrictHostKeyChecking=no -oCheckHostIP=no usr@$myhost.example.com
#use 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

A solução de amostra para o bash pode ser:

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

Isso aguardará a entrada e, em seguida, a sessão interativa de retorno (por um momento).

Piotr Król
fonte
1
funciona muito bem, obrigado. E se eu quiser digitar o comando depois de fazer login via SSH, o que preciso fazer?
Max
Este script deve retornar shell inerativo com o usuário conectado. Eu não entendo a pergunta. Se você deseja absolutamente usar o mesmo script no bash, consulte a entrada editada.
Piotr Król
Da mesma maneira que envio a senha quando solicitado, gostaria de enviar comandos do sistema uma vez logado.
Max
O código de amostra foi adicionado para postar acima. É claro que isso funcionará até que my_commandX não mude o prompt retornado, se isso acontecer, a variável de prompt deverá ser alterada.
Piotr Król
@pietrushnic, você pode explicar um pouco por que usar "interact -o -nobuffer -re $ prompt return", em vez de "esperar $ prompt"? o último parece ser mais usado ..
Richard
53

A maneira mais fácil é usar o sshpass . Isso está disponível nos repositórios Ubuntu / Debian e você não precisa lidar com a integração do expect com o bash.

Um exemplo:

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

O comando acima pode ser facilmente integrado a um script bash.

Nota: Leia considerações de segurança seçãoman sshpass para entender completamente as implicações de segurança.

dotnix
fonte
Não sei se é uma boa solução, mas certamente simplifica muito. Graças
erikbwork
9
Muito perigoso do ponto de vista da segurança - os argumentos da linha de comando podem ser lidos por qualquer outro processo no sistema. É possível sobrescrevê-los, e espero sshpassque faça isso, mas mesmo assim há um período enquanto ainda está sendo inicializado antes que seja possível fazê-lo quando a senha estiver disponível para qualquer processo.
Charles Duffy
1
@CharlesDuffy Claro, você está correto. sshpassé usado em um cenário em que você possui scripts de teste simples que são executados em um ambiente de rede local em que a segurança não é a principal preocupação. De fato, há uma seção em man sshpassque uma seção inteira sobre considerações de segurança é explicada. Adicionado isto para responder, Obrigado.
dotnix 22/05
@ erikb85 Normalmente, um pacote faz todo o material sujo para você, mas, em todos os casos, esses scripts são construídos apenas para esse uso, então é MELHOR que adicionar seu próprio material. Este comentário é sobre não reinventar a roda. Lide com coisas difíceis apenas se nenhuma pessoa tiver lidado com isso ainda. sshpass é uma boa função.
M3nda
2
Para completar, mencionei que "man sshpass" envia avisos de segurança adequados ao usuário em potencial, ressalta que "-p" é a maneira menos segura de usá-lo e oferece a opção "-e" para obter a senha por meio da variável de ambiente , que pelo menos o mantém fora da linha de comando.
precisa
22

Adicione o comando de espera 'interact' antes do seu 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"

Isso deve permitir que você interaja com a máquina remota até fazer o logout. Então você voltará ao bash.

dr-jan
fonte
Ele entra e sai imediatamente. "você saiu" é impresso.
Emmanuel
8
Substituí "interagir" e "EOD" por "esperar eof" e funcionou para mim. Isso está em um Mac.
Emmanuel
2
Nenhuma das respostas desta página funcionou para mim, mas a sugestão de usar expect eofo @ Emmanuel resolveu o problema.
Moertel
Retire o 'de usr@$myhost.example.com'e deve funcionar. E talvez você precise substituir \ncom \r, mas YMMV
Tino
20

Depois de procurar uma resposta para a pergunta por meses, finalmente encontro uma solução realmente melhor: escrever um script simples.

#!/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

Coloque /usr/bin/exp, então você pode usar:

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

Feito!

damn_c
fonte
expect "assword:"você quis dizer expect "password:"?
usuário
1
@user "assword"irá combinar ambos Passworde password.
Ferdinand.kraft
8

Certifique-se também de usar

send -- "$PWD\r" 

em vez disso, como senhas que começam com um traço (-) falharão caso contrário.

O exemplo acima não interpretará uma sequência que começa com um traço como uma opção para o comando send.

Timmah
fonte
8

Um script de expectativa simples

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

Exemplo:

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

Use a ferramenta auxiliar fd0ssh(do hxtools, não do pmt), ela funciona sem ter que esperar um prompt específico do programa ssh.

user562374
fonte
Isso é ótimo! É um pouco difícil fazê-lo funcionar (pelo menos no servidor ubuntu), mas funciona sem problemas! A configuração que fizemos: echo "yoursshpass" | fd0ssh ssh -c -L$port:$ip:$remote_port [email protected] & OBRIGADO!
JP Illanes
1
Muito mais seguro do que passar a senha na linha de comando, como sshpassfaz.
Charles Duffy
5

Outra maneira que achei útil para usar um pequeno script esperado de um script bash é a seguinte.

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

Isso funciona porque ...If the string "-" is supplied as a filename, standard input is read instead...

Jimbo
fonte
Você não precisa do -aqui, como expectstdinpor padrão, se o invocar sem argumento. No entanto, é útil se você deseja executá-lo interativamente sem o prompt de comando ( expectvs. expect -) ou caso faça algo como expect -f "$@"onde o primeiro argumento deve ser um arquivo, mesmo que pareça uma opção (começa com -). Nesse caso, se $1(o arquivo fornecido) for -lido por stdin.
Tino
1

sshpassestá quebrado se você tentar usá-lo dentro do destino de criação de Texto Sublime, dentro de um Makefile. Em vez de sshpassvocê pode usar passh: https://github.com/clarkwang/passh

Com sshpassvocê faria:

sshpass -p pa$$word ssh user@host

Com passhvocê faria:

passh -p pa$$word ssh user@host

Nota: Não se esqueça de usar -o StrictHostKeyChecking=no , caso contrário, a conexão travará na primeira vez em que você a usar. Por exemplo:

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

Referências:

  1. O comando Enviar para senha não funciona usando o script expect na conexão ssh
  2. /ubuntu/87449/how-to-disable-strict-host-key-checking-in-ssh
  3. https://linuxcommando.blogspot.com/2008/10/how-to-disable-ssh-host-key-checking.html
  4. /server/330503/scp-without-known-hosts-check
  5. https://debian-administration.org/article/587/pam_mount_and_sshfs_with_password_authentication
do utilizador
fonte