How to use bash/expect to check if an SSH login works
My team manages many servers, and company policy dictates that the passwords on these servers must be changed every couple of weeks. Sometimes, our official database of passwords gets out of date for whatever reason (people forget to update it, usually), but we cannot identify this sometimes until months later, since we don’t consistently use every server. I want to write a script that will scrape the passwords from the database, and use those passwords to attempt an (ssh) login to each server every night, and send an email with the results to the team. I am able to scrape the database for login information, but I’m not sure how to check whether ssh login was successful or not in expect. I cannot use public key authentication for this task. I want password authentication so I can verify the passwords. I disable public-key authentication by specifying the following file:
PasswordAuthentication=yes PubkeyAuthentication=no
# $1 = host, $2 = user, $3 = password, $4 = config file expect -c "spawn ssh $2@$1 -F $4 expect -re \".*?assword.*?\" send \"$3\n\" . send \'^D\'"
I thought maybe exit status could indicate the success? Couldn’t find anything in the man pages though.
Who changes the password? Perhaps they should also be responsible for updating the database. Putting the password into this sort of script seems to defeat the purpose of changing the password frequently.
The password does not go into the script. The passwords are scraped from a database and passed as command-line arguments to the script, which makes perfect sense to me. And even though people have the responsibility to update the database, they often do not. This is a sanity check to make sure all the passwords in the database are correct.
Linux expect ssh примеры
В предыдущей статье я уже рассказал как с помощью несложного bash скрипта автоматизировать процесс telnet подключения к группе хостов c последующим запуском команд. Однако нашлось оборудование на котором разрешено подключение только по ssh. Давайте попробуем переделать наш скрипт под ssh и поможет нам в этом expect.
Expect — программная оболочка дающая возможность запрограммировать диалог с утилитами, которые в процессе использования запрашивают ввод информации у пользователя. В нашем случае такой утилитой будет выступать ssh клиент.
Bash script ssh с использованием expect
Краткая постановка задачи:
Есть три маршрутизатора cisco c ip-адресами 192.168.10.10, .11 и .12. Нужно подключить к ним по ssh и выполнить команду «show ver | include IOS».
Первым делом на надо установить expect.
Для ОС RedHat, CentOS, Fedora и т.п.
Для ОС Debian, Ubuntu, Mint и т.п.
sudo apt-get install expect
Ну а теперь приведу текст самого скрипта.
#!/bin/bash #Включение отладки bash: set -x #Учетные данные: USER="admin" PASSWD="123456" #Файл логов: LOG="ssh_conn.log" #Список хостов: HOSTS=" 192.168.10.10 192.168.10.11 192.168.10.12 " #Цикл переборки хостов: for H in $HOSTS do #Вывод даты старта скрипта: echo START SCRIPT: >> $LOG date +%x-%R >> $LOG #Команды для expect: COMM=" #Включение и вывод отладки expect: #log_file debug.log #exp_internal 1 #Время ожидание expect set timeout 1 #Соедиение ssh: spawn ssh $USER@$H expect \"*(yes/no)?*\" expect \"Password:\" send \"$PASSWD\r\" #Выполняемые команды: expect \"*>\" send \"show ver | include IOS\r\" expect \"*>\" send \"exit\r\" #Завершение выполнения expect: expect eof " #Запуск expect с набором команд: expect -c "$COMM" >> $LOG #Вывод разделителя: echo ========================================================================= >> $LOG done
Описание ssh скрипта
Полное описание скрипта делать не буду, так как уже описывал в предыдущей статье «Bash скрипт для автоматического telnet соединения и ввода команд», ну и плюс краткое описание я оставил в комментариях текста скрипта. Отличие этого скрипта — это использование expect. Вот его работу и разберем подробнее.
1. spawn — запуск утилиты (программы). В нашем случае мы запускаем ssh клиент, но можно также запускать к примеру ftp, telnet, scp и т.п.
2. expect — ожидание выводимых программой информации (данных). При первом подключение по протоколу ssh всегда запрашивается приглашение вида.
RSA key fingerprint is b6:66:c7:b2:9e:18:1e:9e:69:af:9e:3c:06:59:e8:8d. Are you sure you want to continue connecting (yes/no)?
Данное приглашение просит ввести «yes» для продолжения соединения. Однако при повторной попытке подключения, данное сообщение выводиться уже не будет. Поэтому и получаем в скрипте конструкцию вида:
Таким образом, если есть в выводе утилиты ssh текст «(yes/no)» то отправляем согласие в виде «yes». Если нет, то переходим по таймауту дальше.
Время таймаута также задано в скрипте строкой «set timeout 1».
send — как вы уже поняли, это отправка входных данных программе. С помощью нее мы и отправляем пароль и запрос на вывод версии IOS «show ver | include IOS».
При отладки скрипта можно раскомментировать следующие строки:
log_file debug.log exp_internal 1
При запуске скрипта, будет создан файл «debug.log» содержащий в себе отладочную информацию по работе expect-а.
Создать файл можно, используя команду touch имя_файла.
Дать максимум привилегий можно используя chmod 777 имя_файла.
Запустить bash-скрипт можно используя перед именем файла «./»
Скрипт отработает и создаст файл с названием ssh_conn.log, в котором и будет храниться вывод выполняемых на железяках команд.
Пример содержания файла ssh_conn.log
START SCRIPT: 06.11.2017-12:22 spawn ssh Адрес электронной почты защищен от спам-ботов. Для просмотра адреса в вашем браузере должен быть включен Javascript. Password: R1>show ver | include IOS Cisco IOS Software, 7200 Software (C7200-ADVIPSERVICESK9-M), Version 15.2(4)S5, RELEASE SOFTWARE (fc1) R1>exit Connection to 192.168.10.10 closed by remote host. Connection to 192.168.10.10 closed. ========================================================================= START SCRIPT: 06.11.2017-12:22 .
На этом все. Нам удалось создать bash-скрипта с применением в нем программной оболочки expect, который автоматизирует процесс подключения к нескольким удаленным хостам по протоколу ssh, выполняет ввод заданных нами команд и собирает результат их выполнения в файл. Комментируем, подписываемся ну и всем пока:)
Expect примеры Linux
Expect — инструмент для автоматизации интерактивных приложений таких, как telnet, ftp, passwd, fsck, rlogin, tip, Настройка и использование SSH и других. Expect поддерживает механизм регулярных выражений и основные возможности программирования, позволяющие простым скриптам эффективно управлять такими программами, не обладающими встроенным скрипт-языком, макросами, или другими механизмами программирования. Эффективен при работе с сетевым оборудованием — массовое обновление конфигураций управляемого (активного) сетевого оборудования с дифференцированным выполнением команд.
Одним из главных применений Expect являются коммерческие приложения. Многие из этих приложений предоставляют интерфейс командной строки, но, как правило, его недостаточно для написания скриптов. Они созданы для обеспечения пользователя средствами администрирования, но производители зачастую не тратят денег на создание полноценного скриптового языка.
Expect унаследовал синтаксис Tcl, который не похож на другие скриптовые языки, такие как Основы BASH скрипты, циклы, горячие клавиши, C shell (csh), и Perl в командной строке — примеры использования.
Expect портирован в языки Python и Perl в виде различных дополнительных модулей. Подмножество команд Expect-а портировано в Java и доступно в SwitchTermJ (java-based Terminal Emulator). Реализация процедур в этих модулях это в основном интерпретация оригинальной версии с эквивалентной функциональностью.
apt install expect-dev expect
expect_autoexpect
Скрипт expect_autoexpect позволяет создать скрипт с командами из текущей сессии. Например, создадим скрипт, который применяет изменения настройки для Softswitch VoIP платформа MVTS (Мера) Pro.
# expect_autoexpect autoexpect started, file is script.exp # telnet 127.0.0.1 7000 Trying 127.0.0.1. Connected to 127.0.0.1. Escape character is '^]'. ****************************************************************************** * Multiprotocol VoIP Transit Softswitch * * * ****************************************************************************** mvts3g|> config /etc/mvts3g/system-1.conf Step 1: Parsing a configuration file. Step 2: Configuring the system. Step 3: Done. mvts3g|> exit Connection closed by foreign host.
Жмем Ctrl-D для завершения работы скрипта expect_autoexpect
# exit autoexpect done, file is script.exp
Теперь у нас получился запускаемый скрипт script.exp, который позволяет вместо набора трех команд просто запустить его:
Примеры использования
ftp_expect.sh
#!/usr/bin/expect -f ###################################################################################### #$remote_server - сервер, к которому осуществляется доступ # #$my_user_id - имя пользователя на сервере # #$my_password - пароль пользователя на сервере # #$my_command - команда, которая будет запущена на сервере set remote_server xxx.xxx.xxx.225 set my_user_id testuser set my_password testpass # Открыть ftp-сессию на удалённом сервере, и ждать запроса имени пользователя. spawn ftp $remote_server expect "username:" # Послать имя пользователя, и ждать приглашения ввода пароля. send "$my_user_id\r" expect "password:" # Послать пароль, и ждать приглашения ввода ftp. send "$my_password\r" expect "ftp>" # Переключиться в бинарный режим, и снова ждать приглашения ввода ftp. send "bin\r" expect "ftp>" # Выключить приглашение ввода. send "prompt\r" expect "ftp>" # Получить все файлы send "mget *\r" expect "ftp>" # Закончить ftp-сессию и ждать спецсимвол конца файла (eof). send "bye\r" expect eof
ssh_expect.sh
#!/usr/bin/expect -f #set timeout 100 set PASS "testpass" set USER "testuser" spawn ssh -T $USER@[lrange $argv 0 0]; expect "password:" send "$PASS\r" expect "$" send "ls\r" expect "$" send "exit\r" expect eof