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


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).


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.


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.


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!


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.


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>

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.


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 user@yourserver.com & 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...


Você não precisa do -aqui, como expectlê stdinpor 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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.