Вопрос или проблема
Контекст:
- Рабочая станция Debian Stretch, пытающаяся установить SSH-соединение с многочисленными серверами GNU/Linux (в основном RH и Debian)
- Я не могу изменить SSH-конфигурацию удаленных серверов
- Я понимаю, что это далеко не идеально, но мне необходимо входить в систему с помощью логина и пароля. Без SSH-ключа, просто старый добрый логин/пароль. Я не могу изменить это (не нужно предлагать использование ключей + фраз-паролей)
- sshpass -V : “sshpass 1.06”
Этот ответ дает интересный намек на использование ‘sshpass’.
Что я настроил в ‘~/.ssh/config’ :
Host myServer
HostName 12.34.56.78
User bob
ProxyCommand sshpass -v -pmyPassword ssh %r@%h -W localhost:%p
Примечание: параметр ‘-v’ sshpass используется только для получения подробностей при задавании этого вопроса
Когда я пытаюсь подключиться через SSH:
me@myWorkstation$ ssh myServer
SSHPASS searching for password prompt using match "assword"
SSHPASS read: [email protected]'s password:
SSHPASS detected prompt. Sending password.
SSHPASS read:
[email protected]'s password:
И это ждет бесконечно 🙁
Если я редактирую ‘~/.ssh/config’ и заменяю ‘myPassword’ (который является реальным паролем для этого входа в SSH, он работает при ручном вводе):
Host myServer
HostName 12.34.56.78
User bob
ProxyCommand sshpass -v -pnotMyPasswordAnymoreOhNo ssh %r@%h -W localhost:%p
что дает:
me@myWorkstation$ ssh myServer
SSHPASS searching for password prompt using match "assword"
SSHPASS read: [email protected]'s password:
SSHPASS detected prompt. Sending password.
SSHPASS read:
Permission denied, please try again.
SSHPASS read: [email protected]'s password:
SSHPASS detected prompt, again. Wrong password. Terminating.
ssh_exchange_identification: Connection closed by remote host
На самом деле я получаю ответ (хотя и отрицательный). Можете объяснить, почему?
документация к sshpass говорит:
ВОПРОСЫ БЕЗОПАСНОСТИ
В первую очередь, пользователи sshpass должны понимать, что требование ssh к интерактивному вводу пароля не случайно. Почти невозможно безопасно хранить пароль, и пользователи sshpass должны рассмотреть возможность использования аутентификации по открытому ключу, которая обеспечивает тот же опыт пользователя и при этом безопаснее и доставляет меньше хлопот. Опция -p должна рассматриваться как наименее безопасная из всех опций sshpass. Все пользователи системы могут видеть пароль в командной строке при помощи простого "ps" команды. Sshpass делает минимальную попытку скрыть пароль, но такие попытки обречены создавать условия гонок и не решать проблему. Пользователи sshpass рекомендуются использовать один из других методов передачи пароля, которые более безопасны. В частности, людям, пишущим программы, которые должны передавать пароль программно, рекомендуется использовать безымянный канал и передавать конец чтения канала в sshpass с помощью опции -d.
Вы можете попробовать сохранить переменную ENV и хранить пароль там, но это плохая практика.
Если кому-то интересно заставить ssh
запрашивать пароль один раз, т.е. в то время, когда sshpass
предоставляет пароль и завершает работу в случае его неправильности, то что-то вроде этого работает отлично
sshpass -e ssh [email protected] -o NumberOfPasswordPrompts=1 whoami
Объяснение:
sshpass
берет пароль из переменной окружения$SSHPASS
при использовании опции-e
ssh
использует пароль, предоставленныйsshpass
, и если он успешный, то выполняет командуwhoami
на удаленном сервере- если пароль неверный, то он не запрашивает повторно пароль благодаря
-o NumberOfPasswordPrompts=1
, что заставляетssh
запрашивать только один раз, и этим 1 разом был уже использованный неправильный пароль, предоставленныйsshpass
, поэтому фокус возвращается к терминалу
Не совсем та же проблема, но это был один из немногих связанных пунктов, с которыми я столкнулся во время недавнего поиска.
Столкнулся с совершенно другой причиной, связанной с использованием Cygwin из-за расположения файла known_hosts
. При входе с помощью ssh
всё вёл себя нормально, но при входе через sshpass
всё происходило ошибка, и при выполнении sshpass -v
появлялась ошибка:
bash$ ./sshpass -v -p PASSWORD ssh REMOTEUSER@ADDRESS
SSHPASS searching for password prompt using match "assword"
The authenticity of host 'ADDRESS (ADDRESS)' can't be established.
ED25519 key fingerprint is SHA256:h5Pmc4/GLFmGXvZl3oPadzvAgmOVW5tD9hSOKRCfKes.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/n
SSHPASS detected host authentication prompt. Exiting.
bash$
Наконец, удалось обнаружить это, добавив также -vvv
к команде ssh
, что выявило следующее:
bash$ ./sshpass -v -p PASSWORD ssh -vvv REMOTEUSER@ADDRESS
OpenSSH_9.9p1, OpenSSL 3.0.15 3 Sep 2024
debug2: resolve_canonicalize: hostname ADDRESS is address
debug3: expanded UserKnownHostsFile '~/.ssh/known_hosts' -> '/home/USER/.ssh/known_hosts'
debug3: expanded UserKnownHostsFile '~/.ssh/known_hosts2' -> '/home/USER/.ssh/known_hosts2'
debug3: channel_clear_timeouts: clearing
debug3: ssh_connect_direct: entering
debug1: Connecting to ADDRESS [ADDRESS] port 22.
debug3: set_sock_tos: set socket 4 IP_TOS 0x48
debug1: Connection established.
...
debug1: Remote protocol version 2.0, remote software version OpenSSH_8.9
debug1: compat_banner: match: OpenSSH_8.9 pat OpenSSH* compat 0x04000000
debug2: fd 4 setting O_NONBLOCK
debug1: Authenticating to ADDRESS:22 as 'REMOTEUSER'
debug1: load_hostkeys: fopen /home/USER/.ssh/known_hosts: No such file or directory
debug1: load_hostkeys: fopen /home/USER/.ssh/known_hosts2: No such file or directory
debug1: load_hostkeys: fopen /etc/ssh_known_hosts: No such file or directory
debug1: load_hostkeys: fopen /etc/ssh_known_hosts2: No such file or directory
debug3: order_hostkeyalgs: no algorithms matched; accept original
debug3: send packet: type 20
debug1: SSH2_MSG_KEXINIT sent
debug3: receive packet: type 20
...
debug1: expecting SSH2_MSG_KEX_ECDH_REPLY
debug3: receive packet: type 31
debug1: SSH2_MSG_KEX_ECDH_REPLY received
debug1: Server host key: ssh-ed25519 SHA256:h5Pmc4/GLFmGXvZl3oPadzvAgmOVW5tD9hSOKRCfKes
debug1: load_hostkeys: fopen /home/USER/.ssh/known_hosts: No such file or directory
debug1: load_hostkeys: fopen /home/USER/.ssh/known_hosts2: No such file or directory
debug1: load_hostkeys: fopen /etc/ssh_known_hosts: No such file or directory
debug1: load_hostkeys: fopen /etc/ssh_known_hosts2: No such file or directory
debug3: hostkeys_find_by_key_hostfile: trying user hostfile "/home/USER/.ssh/known_hosts"
debug1: hostkeys_find_by_key_hostfile: hostkeys file /home/USER/.ssh/known_hosts does not exist
debug3: hostkeys_find_by_key_hostfile: trying user hostfile "/home/USER/.ssh/known_hosts2"
debug1: hostkeys_find_by_key_hostfile: hostkeys file /home/USER/.ssh/known_hosts2 does not exist
debug3: hostkeys_find_by_key_hostfile: trying system hostfile "/etc/ssh_known_hosts"
debug1: hostkeys_find_by_key_hostfile: hostkeys file /etc/ssh_known_hosts does not exist
debug3: hostkeys_find_by_key_hostfile: trying system hostfile "/etc/ssh_known_hosts2"
debug1: hostkeys_find_by_key_hostfile: hostkeys file /etc/ssh_known_hosts2 does not exist
SSHPASS searching for password prompt using match "assword"
The authenticity of host 'ADDRESS (ADDRESS)' can't be established.
ED25519 key fingerprint is SHA256:h5Pmc4/GLFmGXvZl3oPadzvAgmOVW5tD9hSOKRCfKes.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/n
SSHPASS detected host authentication prompt. Exiting.
bash$
Однако, подключение непосредственно с помощью ssh
вместо sshpass
делало следующее:
bash$ ssh -vvv remoteuser@ADDRESS
OpenSSH_for_Windows_9.5p1, LibreSSL 3.8.2
debug3: Failed to open file:C:/Users/USER/.ssh/config error:2
debug3: Failed to open file:C:/ProgramData/ssh/ssh_config error:2
debug2: resolve_canonicalize: hostname ADDRESS is address
debug3: expanded UserKnownHostsFile '~/.ssh/known_hosts' -> 'C:\\Users\\USER/.ssh/known_hosts'
debug3: expanded UserKnownHostsFile '~/.ssh/known_hosts2' -> 'C:\\Users\\USER/.ssh/known_hosts2'
debug3: ssh_connect_direct: entering
debug1: Connecting to ADDRESS [ADDRESS] port 22.
debug1: Connection established.
...
debug1: Local version string SSH-2.0-OpenSSH_for_Windows_9.5
debug1: Remote protocol version 2.0, remote software version OpenSSH_8.9
debug1: compat_banner: match: OpenSSH_8.9 pat OpenSSH* compat 0x04000000
debug2: fd 3 setting O_NONBLOCK
debug1: Authenticating to ADDRESS:22 as 'remoteuser'
debug3: record_hostkey: found key type ED25519 in file C:\\Users\\USER/.ssh/known_hosts:3
debug3: record_hostkey: found key type RSA in file C:\\Users\\USER/.ssh/known_hosts:4
debug3: record_hostkey: found key type ECDSA in file C:\\Users\\USER/.ssh/known_hosts:5
debug3: load_hostkeys_file: loaded 3 keys from ADDRESS
debug3: Failed to open file:C:/Users/USER/.ssh/known_hosts2 error:2
debug1: load_hostkeys: fopen C:\\Users\\USER/.ssh/known_hosts2: No such file or directory
debug3: Failed to open file:C:/ProgramData/ssh/ssh_known_hosts error:2
debug1: load_hostkeys: fopen __PROGRAMDATA__\\ssh/ssh_known_hosts: No such file or directory
debug3: Failed to open file:C:/ProgramData/ssh/ssh_known_hosts2 error:2
debug1: load_hostkeys: fopen __PROGRAMDATA__\\ssh/ssh_known_hosts2: No such file or directory
debug3: order_hostkeyalgs: have matching best-preference key type [email protected], using HostkeyAlgorithms verbatim
debug3: send packet: type 20
debug1: SSH2_MSG_KEXINIT sent
debug3: receive packet: type 20
...
debug3: send packet: type 30
debug1: expecting SSH2_MSG_KEX_ECDH_REPLY
debug3: receive packet: type 31
debug1: SSH2_MSG_KEX_ECDH_REPLY received
debug1: Server host key: ssh-ed25519 SHA256:h5Pmc4/GLFmGXvZl3oPadzvAgmOVW5tD9hSOKRCfKes
debug3: record_hostkey: found key type ED25519 in file C:\\Users\\USER/.ssh/known_hosts:3
debug3: record_hostkey: found key type RSA in file C:\\Users\\USER/.ssh/known_hosts:4
debug3: record_hostkey: found key type ECDSA in file C:\\Users\\USER/.ssh/known_hosts:5
debug3: load_hostkeys_file: loaded 3 keys from ADDRESS
debug3: Failed to open file:C:/Users/USER/.ssh/known_hosts2 error:2
debug1: load_hostkeys: fopen C:\\Users\\USER/.ssh/known_hosts2: No such file or directory
debug3: Failed to open file:C:/ProgramData/ssh/ssh_known_hosts error:2
debug1: load_hostkeys: fopen __PROGRAMDATA__\\ssh/ssh_known_hosts: No such file or directory
debug3: Failed to open file:C:/ProgramData/ssh/ssh_known_hosts2 error:2
debug1: load_hostkeys: fopen __PROGRAMDATA__\\ssh/ssh_known_hosts2: No such file or directory
debug1: Host 'ADDRESS' is known and matches the ED25519 host key.
debug1: Found key in C:\\Users\\USER/.ssh/known_hosts:3
debug3: send packet: type 21
debug1: ssh_packet_send2_wrapped: resetting send seqnr 3
debug2: ssh_set_newkeys: mode 1
debug1: rekey out after 134217728 blocks
...
debug3: receive packet: type 80
debug1: client_input_global_request: rtype [email protected] want_reply 0
debug3: client_input_hostkeys: received RSA key SHA256:gRIZdS/NcmA7JC7vxBDG63uhjuE9ZuKadl9XKU1yC0A
debug3: client_input_hostkeys: received ECDSA key SHA256:TJCsTQVSHrxE5DuWpG65F7tr3P7qDfknz9NLBQ/W+o0
debug3: client_input_hostkeys: received ED25519 key SHA256:h5Pmc4/GLFmGXvZl3oPadzvAgmOVW5tD9hSOKRCfKes
debug1: client_input_hostkeys: searching C:\\Users\\USER/.ssh/known_hosts for ADDRESS / (none)
debug3: hostkeys_foreach: reading file "C:\\Users\\USER/.ssh/known_hosts"
debug3: hostkeys_find: found ssh-ed25519 key at C:\\Users\\USER/.ssh/known_hosts:3
debug3: hostkeys_find: found ssh-rsa key at C:\\Users\\USER/.ssh/known_hosts:4
debug3: hostkeys_find: found ecdsa-sha2-nistp256 key at C:\\Users\\USER/.ssh/known_hosts:5
debug1: client_input_hostkeys: searching C:\\Users\\USER/.ssh/known_hosts2 for ADDRESS / (none)
debug3: Failed to open file:C:/Users/USER/.ssh/known_hosts2 error:2
debug1: client_input_hostkeys: hostkeys file C:\\Users\\USER/.ssh/known_hosts2 does not exist
debug3: client_input_hostkeys: 3 server keys: 0 new, 3 retained, 0 incomplete match. 0 to remove
debug1: client_input_hostkeys: no new or deprecated keys from server
debug3: client_repledge: enter
debug3: receive packet: type 91
debug2: channel_input_open_confirmation: channel 0: callback start
debug2: fd 3 setting TCP_NODELAY
debug2: client_session2_setup: id 0
debug2: channel 0: request pty-req confirm 1
debug3: send packet: type 98
debug2: channel 0: request shell confirm 1
debug3: send packet: type 98
debug3: client_repledge: enter
debug1: pledge: fork
debug2: channel_input_open_confirmation: channel 0: callback done
debug2: channel 0: open confirm rwindow 0 rmax 32768
debug3: receive packet: type 99
debug2: channel_input_status_confirm: type 99 id 0
debug2: PTY allocation request accepted on channel 0
debug2: channel 0: rcvd adjust 2097152
debug3: receive packet: type 99
debug2: channel_input_status_confirm: type 99 id 0
debug2: shell request accepted on channel 0
Last login: Tue Feb 11 15:40:24 2025 from HOST
REMOTEHOST$$
Обратите внимание, как логин ssh
использует Windows-домашний каталог для директории пользователя .ssh
, но sshpass
использует домашний каталог Cygwin.
Просто предположение, но это похоже на то, что они по-разному обрабатывают начальный ~/
в пути.
В любом случае, проблема была решена путем создания символеического ссылки для .ssh
в домашней директории Cygwin /home/USER
на Windows-домашний каталог C:\Users\USER
.
bash$ cd
bash$ ls -l .ssh
lrwxrwxrwx 1 USER Domain Users 29 Feb 11 15:56 .ssh -> /cygdrive/c/Users/USER/.ssh
Ответ или решение
Основной вопрос, который поднимается в этом обсуждении, заключается в том, почему sshpass
продолжает запрашивать пароль, несмотря на явное указание такового через команду или конфигурацию. Чтобы полностью понять эту проблему, надо рассмотреть несколько аспектов работы SSH и sshpass
.
Теория
SSH — это протокол для безопасного доступа к удалённым серверам, который в первую очередь рассчитан на использование ключевой авторизации. Однако, когда использование ключей невозможно, приходится работать с текстовыми паролями. Протокол SSH имеет определённые механизмы защиты, связанные с аутентификацией, включая необходимость ручного ввода пароля, чтобы уменьшить вероятность его компрометации.
sshpass
— это утилита, которая позволяет передавать пароль для SSH-сессии через командную строку или другие менее безопасные механизмы. Важно понимать, что она была создана для минимальной автоматизации процессов в обход стандартных требований безопасности SSH и несёт с собой определённые уязвимости.
Примеры
В рассматриваемом случае на Debian Stretch рабочей станции используется конфигурация с sshpass
для подключения без использования SSH-ключей. Конфигурация ~/.ssh/config
выглядит следующим образом:
Host myServer
HostName 12.34.56.78
User bob
ProxyCommand sshpass -v -pmyPassword ssh %r@%h -W localhost:%p
Когда попытка подключения осуществляется с помощью ssh myServer
, sshpass
должен автоматически передавать пароль, но этого не происходит.
Причины и решения
-
Проблемы с
ProxyCommand
: Анализ сообщений отладки показывает, чтоsshpass
не всегда корректно справляется сProxyCommand
, что часто связано с тем, что данная команда выполняется фактически как подзапрос, а не основное подключение, из чего могут возникать ошибки обработки. -
Проблемы с известными хостами:
- Проверка подлинности удаленного хоста может быть блокирующим фактором. Если хост неизвестен,
ssh
может остановить выполнение до тех пор, пока пользователь не подтвердит доверие к новому хосту, как это видно из логов отладки, где происходит неожиданный выходsshpass
при наличии запроса на установление подлинности хоста.
- Проверка подлинности удаленного хоста может быть блокирующим фактором. Если хост неизвестен,
-
Проблемы с обнаружением приглашения к вводу пароля:
sshpass
полагается на шаблон для обнаружения приглашения к вводу пароля (обычно "assword"). Если формулировка приглашения отличается или появляется неожиданное сообщение,sshpass
может не распознать момент для ввода пароля.
Применение решений
Настройка аутентификации хоста:
Убедитесь, что аутентификация хоста выполняется корректно. Для этого можно предварительно вручную подключиться к серверу, чтобы добавить хост в known_hosts
, что избавит sshpass
от необходимости обрабатывать дополнительные запросы.
Альтернативные флаги и параметры:
-
Используйте
-o StrictHostKeyChecking=no
в команде SSH, чтобы отключить проверку ключа хоста для тестовых или менее защищённых сред. Это может устранить блокировку на этапе подлинности хоста. -
Применение
-o NumberOfPasswordPrompts=1
в комбинированной команде сsshpass
может заставить SSH прервать попытку ввода правильного пароля после первой неудачной попытки, что избавит от излишних запросов.
Проблемы с Переменными Окружения:
Вместо непосредственного использования флага -p
, попробуйте передавать пароль через переменные окружения. Это может быть более гибким способом интеграции скриптов и утилит.
export SSHPASS='myPassword'
sshpass -e ssh -o StrictHostKeyChecking=no bob@12.34.56.78
Таким образом, такая сложная конфигурация SSH требует комплексного подхода и внимания к деталям, которые могут варьироваться от неудачи обработки аутентификации хоста до проблем с обнаружением приглашения к вводу пароля. Надёжное понимание механизмов работы позволит наиболее эффективно адаптировать инструменты для выполнения поставленной задачи.