Неинтерактивная SSH-аутентификация

Добро пожаловать на наш форум!

Спасибо за посещение нашего сообщества. Пожалуйста, зарегистрируйтесь или войдите, чтобы получить доступ ко всем функциям.


Gibby

Автор
Команда проекта

Регистрация
Сообщений
1,645
Репутация
45
Сделок
1.png
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/[email protected] 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:

2.png


▍ Продвинутая работа с паролями​


Швейцарский разработчик Винсент Бернат (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.
 
Сверху