Використовуйте очікувати в bash скрипті, щоб вказати пароль для команди SSH


131

Тим, хто хоче відповісти, що я повинен використовувати SSH-ключі, будь ласка, утримайтеся

Я намагаюся використовувати очікувати в скрипті bash для надання пароля SSH. Надання пароля працює, але я не закінчуюсь на сесії SSH як слід, він повертається до протоку.

Мій сценарій:

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

Вихід мого сценарію:

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

Мені б хотілося провести сеанс SSH, і тільки коли я вийду з нього, повернусь до свого скрипту bash. Причина, по якій я використовую bash, перш ніж очікувати, полягає в тому, що в мене є меню, яке я можу вибрати, до якого блоку підключитися.

Дякую


49
будь ласка, дивіться перший рядок: Для тих, хто хоче відповісти, що я повинен використовувати SSH-ключі, будь ласка, утримайтеся
Макс

54
Я б редагував ваш перший рядок, щоб бути трохи дружнішим. Ви можете розглянути щось на кшталт "Через обмеження, я просто не можу використовувати SSH ключі, я мушу знайти спосіб змусити його працювати з очікуванням". Ви можете очікувати, що людям може бути цікаво, чому ви не використовуєте ключі, а просто намагаєтесь бути корисними :) @Ignacio не запропонував вам їх використовувати, він просто підтвердив це як обмеження, а не недогляд.
Тім Пост

Я б спробував використовувати kermit в цьому випадку. Він має дуже надійну мову сценаріїв columbia.edu/kermit/skermit.html#scripts
f3xy

Відповіді:


86

Змішування баш та очікувань - не гарний спосіб досягти бажаного ефекту. Я б спробував використовувати лише очікувані:

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

Зразок розчину для bash може бути:

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

Це зачекає на введення та потім повернеться (на мить) інтерактивного сеансу.


1
це чудово працює, дякую. Що робити, якщо я хочу ввести команду після входу в систему через SSH, що мені потрібно зробити?
Макс

Цей скрипт повинен повертати неефективну оболонку з авторизованим користувачем. Я не розумію питання. Якщо ви абсолютно хочете використовувати той самий скрипт у bash, подивіться відредагований запис.
Piotr Król

Таким же чином, коли я надсилаю пароль, коли буде запропоновано, я хотів би надіслати системні команди після входу в систему.
Макс

Зразок коду додано до публікації вище. Звичайно, це буде працювати, поки my_commandX не змінить повернуту підказку, якщо це трапиться, змінна зміна повинна бути змінена.
Piotr Król

@pietrushnic Ви можете трохи пояснити, чому використовуєте "interact -o -nobuffer -re $ prompt return", а не "очікуйте $ prompt"? останній виглядає частіше вживаним ..
Річард

53

Найпростіший спосіб - використовувати sshpass . Це доступно в репортах Ubuntu / Debian, і вам не доведеться мати справу з інтеграцією очікування з bash.

Приклад:

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

Вищевказана команда може бути легко інтегрована за допомогою сценарію bash.

Примітка. Будь ласка, прочитайте розділ Міркування безпеки, щоб man sshpassотримати повне розуміння наслідків безпеки.


Я не знаю, чи це гарне рішення, але воно, безумовно, значно спрощує. Спасибі
erikbwork

9
Дуже небезпечно з точки зору безпеки - аргументи командного рядка можна прочитати будь-яким іншим процесом у системі. Можна їх перезаписати, і, сподіваємось, sshpassце зробимо, але навіть тоді є період, поки він ще починається, перш ніж він зможе це зробити, коли пароль буде доступний для будь-якого процесу.
Чарльз Даффі

1
@CharlesDuffy Звичайно, ви маєте рацію. sshpassвикористовується у сценарії, коли у вас є прості тестові сценарії, які виконуються в локальній мережевій обстановці, коли безпека не є головним питанням. Насправді є розділ, man sshpassде пояснюється цілий розділ з міркувань безпеки. Додав це до відповіді, Дякую
dotnix

@ erikb85 Зазвичай пакунок робить усі брудні речі для вас, але, у всіх випадках, ці сценарії побудовані саме для цього використання, тоді було б краще, ніж додавати свої речі. Цей коментар стосується того, щоб не винаходити колесо. Займайтеся важкими речами, лише якщо ще ніхто не вирішив це. sshpass - це хороша функція.
m3nda

2
Для повноти я зазначу, що "man sshpass" подає потенційному користувачу відповідні попередження щодо безпеки, вказує, що "-p" є найменш безпечним способом його використання, і пропонує варіант "-e" для отримання пароля через змінну середовища , що принаймні не відключає його від командного рядка.
Рон Берк

22

Додайте команду очікування "взаємодія" безпосередньо перед вашим 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"

Це повинно дозволяти вам взаємодіяти з віддаленою машиною до виходу з системи. Тоді ти повернешся в баш.


Він заходить і негайно повертається назад. друкується "ви поза"
Еммануель

8
Я замінив "взаємодію" та "EOD" на "очікуйте eof", і це працювало на мене. Це на Mac.
Еммануїл

2
Жодна відповідь на цій сторінці не працювала для мене, але пропозиція @ Еммануїла використовувати expect eofпроблему вирішила проблему.
moertel

Вийміть 'з, usr@$myhost.example.com'і це повинно працювати. І , можливо , вам необхідно замінити \nз \r, але YMMV
Tino

20

Шукаючи відповідь на питання протягом місяців, я нарешті знаходжу справді найкраще рішення: написання простого сценарію.

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

Покладіть його /usr/bin/exp, тоді ви можете використовувати:

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

Готово!


expect "assword:"ти мав на увазі expect "password:"?
користувач

1
@user "assword"буде відповідати обом Passwordі password.
Ferdinand.kraft

8

Також обов’язково використовуйте

send -- "$PWD\r" 

натомість, інакше паролі, що починаються з тире (-), вийдуть з ладу.

Вище не буде інтерпретувати рядок, починаючи з тире, як варіант команди команди.


8

Простий сценарій очікування

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

Приклад:

    ./Remotelogin.exp <ip> <user name> <password>

7

Використовуйте допоміжний інструмент fd0ssh(від hxtools, не pmt), він працює, не сподіваючись на особливу підказку від програми ssh.


Це чудово! Трохи важко змусити його працювати (принаймні на сервері ubuntu), але працює безперебійно! Конфігурація, яку ми зробили: echo "yoursshpass" | fd0ssh ssh -c -L$port:$ip:$remote_port user@yourserver.com & ДЯКУЄМО!
JP Illanes

1
Набагато безпечніше, ніж передавати пароль у командному рядку, як sshpassце робиться.
Чарльз Даффі

5

Інший спосіб, який мені здається корисним використовувати невеликий сценарій очікування від bash-скрипту, полягає в наступному.

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

Це працює, тому що ...If the string "-" is supplied as a filename, standard input is read instead...


Тут вам не потрібно -, як expectчитається stdinза замовчуванням, якщо ви посилаєтесь на нього без аргументів. Однак це корисно, якщо ви хочете запускати його в інтерактивному режимі без командного рядка ( expectпроти expect -) або якщо ви робите щось на зразок, expect -f "$@"де перший аргумент повинен бути файлом, навіть якщо він виглядає як варіант (починається з -). У такому випадку, якщо $1(даний файл) -це читається з stdin.
Тіно

1

sshpassпорушується, якщо ви намагаєтесь використовувати його всередині цілі збирання піднесеного тексту, всередині Makefile. Замість цього sshpassви можете використовувати passh: https://github.com/clarkwang/passh

З sshpassвами зробили б:

sshpass -p pa$$word ssh user@host

З passhвами зробили б:

passh -p pa$$word ssh user@host

Примітка. Не забувайте користуватися -o StrictHostKeyChecking=no, інакше з'єднання зависне під час першого використання. Наприклад:

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

Список літератури:

  1. Команда відправлення для пароля не працює, використовуючи сценарій очікування у з'єднанні 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- unknown-hosts-check
  5. https://debian-administration.org/article/587/pam_mount_and_sshfs_with_password_authentication
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.