SSH предлагает несколько форм аутентификации, в том числе пароли и открытые ключи. Последние считаются более безопасными. Однако аутентификация по паролю по-прежнему остаётся самой популярной, особенно в сетевом оборудовании.
Чтобы не вводить пароль каждый раз вручную, есть специальные инструменты для автоматизации логина, то есть для неинтерактивной SSH-аутентификации. Это классическая утилита sshpass и её «исправленный» вариант passh (подробнее о причине «исправления» см. здесь).
▍ Парольный менеджер pass
Например, в случае
passh
применяется следующая конструкция с обёрткой для консоли Zsh. Пароль извлекается напрямую из парольного менеджера pass, где он хранится в зашифрованном виде:pssh() {
passh -p <(pass show network/ssh/password | head -1) ssh "$@"
}
compdef pssh=ssh
В данном случае пароль в открытом виде не появляется ни в командной строке, ни в окружении, ни на диске, что затрудняет его перехват третьим лицом без повышенных привилегий. В Linux пароль передаётся через дескриптор файла.
Pass
считается стандартным парольным менеджером, который соответствует философии Unix. Каждый пароль хранится в зашифрованном gpg-файле, имя которого — название сайта или ресурса, для которого предназначен пароль:zx2c4@laptop ~ $ pass
Password Store
├── Business
│ ├── some-silly-business-site.com
│ └── another-business-site.net
├── Email
│ ├── donenfeld.com
│ └── zx2c4.com
└── France
├── bank
├── freebox
└── mobilephone
Эти зашифрованные файлы можно организовывать в иерархии папок, копировать с компьютера на компьютер и работать с ними с помощью стандартных утилит управления файлами командной строки:
zx2c4@laptop ~ $ pass -c Email/zx2c4.com
Copied Email/jason@zx2c4.com to clipboard. Will clear in 45 seconds.
Pass
очень просто управляет этими файлами. Все они хранятся в ~/.password-store
, а в парольном менеджере есть несколько удобных команд для добавления, редактирования, генерации и получения паролей: zx2c4@laptop ~ $ pass generate Email/jasondonenfeld.com 15
The generated password to Email/jasondonenfeld.com is:
$(-QF&Q=IN2nFBx
Можно редактировать хранилище паролей, используя обычные команды юникс-консоли с командой pass. То есть не используется дополнительные форматы файлов или новые парадигмы, которые нужно изучать. Сообщество создало множество клиентов, графических интерфейсов и расширений для самого pass. Например, на КДПВ скриншоты клиента passforios под iOS. А ниже QtPass, мультиплатформенный GUI для pass:
▍ Продвинутая работа с паролями
Швейцарский разработчик Винсент Бернат (Vincent Bernat) разработал более продвинутый скрипт для неинтерактивной аутентификации по SSH: см. его репозиторий ssh.zsh. Он поясняет, что начиная с версии OpenSSH 8.4 мы можем использовать методы
SSH_ASKPASS
и SSH_ASKPASS_REQUIRE
. Это устраняет некоторые недостатки стандартной команды passh
: здесь отсутствует парсинг выдачи ssh
и не вызывается парольный менеджер, когда пароль не требуется:ssh() {
set -o localoptions -o localtraps
local passname=network/ssh/password
local helper=$(mktemp)
trap "command rm -f $helper" EXIT INT
> $helper <<EOF
#!$SHELL
pass show $passname | head -1
EOF
chmod u+x $helper
SSH_ASKPASS=$helper SSH_ASKPASS_REQUIRE=force command ssh "$@"
}
Если пароль неправильный, на втором экране выводится подсказка:
ssh() {
set -o localoptions -o localtraps
local passname=network/ssh/password
local helper=$(mktemp)
trap "command rm -f $helper" EXIT INT
> $helper <<EOF
#!$SHELL
if [ -k $helper ]; then
{
oldtty=\$(stty -g)
trap 'stty \$oldtty < /dev/tty 2> /dev/null' EXIT INT TERM HUP
stty -echo
print "\rpassword: "
read password
printf "\n"
} > /dev/tty < /dev/tty
printf "%s" "\$password"
else
pass show $passname | head -1
chmod +t $helper
fi
EOF
chmod u+x $helper
SSH_ASKPASS=$helper SSH_ASKPASS_REQUIRE=force command ssh "$@"
}
Разные варианты ввода пароля в зависимости от удалённого узла:
ssh() {
# Grab login information
local -A details
details=(${=${(M)${:-"${(@f)$(command ssh -G "$@" 2>/dev/null)}"}:#(host|hostname|user) *}})
local remote=${details[host]:-details[hostname]}
local login=${details[user]}@${remote}
# Get password name
local passname
case "$login" in
admin@*.example.net) passname=company1/ssh/admin ;;
bernat@*.example.net) passname=company1/ssh/bernat ;;
backup@*.example.net) passname=company1/ssh/backup ;;
esac
# No password name? Just use regular SSH
[[ -z $passname ]] && {
command ssh "$@"
return $?
}
# Invoke SSH with the helper for SSH_ASKPASS
# […]
}
Скрипт целиком можно взять здесь.
Почему пароли до сих пор доминируют в качестве основной формы аутентификации? Дело в том, что отдельные сетевые устройства затрудняют привязку ключа SSH к пользователю. Многие просто не поддерживают аутентификацию на основе ключей/сертификатов. Таким образом, сертификаты не всегда можно использовать.
Способы неинтерактивной аутентификации SSH помогают автоматизировать ввод паролей, которые хранятся в стандартном парольном менеджере
pass
.