Временно удалите пароль закрытого ключа ssh в сценарии оболочки. - PullRequest
2 голосов
/ 23 июня 2011

Мне необходимо развернуть некоторые файлы с сервера A на сервер B. Я подключаюсь к серверу A через SSH и оттуда подключаюсь через ssh к серверу B, используя закрытый ключ, хранящийся на сервере A, открытый ключ которого находится в файле author_keys сервера B. Соединение от A до B происходит в сценарии оболочки Bash, который находится на сервере A.

Это все работает хорошо, красиво и просто, пока администратор, заботящийся о безопасности, не указал, что мой закрытый ключ SSH, хранящийся на сервере A, не защищен парольной фразой, так что любой, кто может взломать мою учетную запись на сервере A, также получит доступ к серверу B, а также C, D, E, F и G. У него есть точка, я думаю.

Он предлагает сложный сценарий, при котором я бы добавил фразу-пароль, а затем изменил сценарий оболочки, добавив в начале строку, в которой я бы назвал

ssh-keygen -p -f {private key file}  

ответьте на приглашение для моей старой парольной фразы с помощью ключевой фразы и (два) запроса на мою новую парольную фразу с помощью только возврата, который удаляет парольную фразу, а затем в конце, после моей команды scp звонит

ssh-keygen -p -f {private key file} 

снова, чтобы поставить фразу обратно

На что я говорю «Еч!».

Ну, я могу немного улучшить это, сначала прочитав парольную фразу ONCE в скрипте с

read -s PASS_PHRASE

затем предоставляя его по мере необходимости, используя параметры -N и -P ssh-keygen.

Это почти пригодно для использования, но я ненавижу интерактивные подсказки в сценариях оболочки. Я хотел бы свести это к одной интерактивной подсказке, но часть, которая меня убивает, это та часть, где я должен дважды нажать клавишу ввода, чтобы избавиться от ключевой фразы

Это работает из командной строки:

ssh-keygen -p -f {private key file} -P {pass phrase} -N ''

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

Это лучшее, что я могу сделать. Кто-нибудь может улучшить это? Или есть лучший способ справиться с этим? Я не могу поверить, что нет.

Лучше всего было бы как-то безопасно справиться с этим без необходимости вводить парольную фразу, но это может потребовать слишком много. Я бы согласился на один вызов сценария.

Вот упрощенная версия всего скрипта в виде скелета

#! /bin/sh
KEYFILE=$HOME/.ssh/id_dsa
PASSPHRASE=''

unset_passphrase() {
        # params
        # oldpassword keyfile
        echo "unset_key_password()"
        cmd="ssh-keygen -p -P $1 -N '' -f $2"
        echo "$cmd"
        $cmd
        echo 
}

reset_passphrase() {
        # params
        # oldpassword keyfile
        echo "reset_key_password()"
        cmd="ssh-keygen -p -N '$1' -f $2" 
        echo "$cmd"
        $cmd
        echo
}

echo "Enter passphrase:"
read -s PASSPHRASE
unset_passphrase $PASSPHRASE $KEYFILE
# do something with ssh
reset_passphrase $PASSPHRASE $KEYFILE

Ответы [ 4 ]

4 голосов
/ 23 июня 2011

Проверьте ssh-agent. Он кэширует фразу-пароль, чтобы вы могли использовать файл ключей в течение определенного периода независимо от того, сколько сеансов у вас есть.

Подробнее о ssh-agent.

2 голосов
/ 23 июня 2011

OpenSSH поддерживает так называемый режим «master master», где вы можете подключиться один раз, оставить его запущенным в фоновом режиме, а затем заставить другие экземпляры ssh (включая scp, rsync, git и т. Д.) Повторно использовать это существующее соединение.Это позволяет вводить пароль только один раз (при настройке мастера управления), но выполнять несколько команд ssh для одного и того же места назначения.

Для получения подробной информации найдите ControlMaster в man ssh_config.

Преимущества перед ssh-agent:

  • Вам не нужно забывать запускать ssh-agent
  • Вам не нужно генерировать пару открытого и закрытого ключей ssh,что важно, если скрипт будет запускаться многими пользователями (большинство людей не понимают ssh-ключей, поэтому создание большой группы людей для их генерации - утомительное упражнение)
  • В зависимости от того, как он настроен,ssh-agent может привести к тайм-ауту ваших ключей в процессе выполнения скрипта;это не
  • Запускается только один сеанс TCP, поэтому гораздо быстрее, если вы подключаетесь снова и снова (например, копируете много маленьких файлов по одному)

Пример использования (простите за подсветку синтаксиса переполнения стека):

REMOTE_HOST=server

log() { printf '%s\n' "$*"; }
error() { log "ERROR: $*" >&2; }
fatal() { error "$*"; exit 1; }
try() { "$@" || fatal "'$@' failed"; }

controlmaster_start() {
    CONTROLPATH=/tmp/$(basename "$0").$$.%l_%h_%p_%r
    # same as CONTROLPATH but with special characters (quotes,
    # spaces) escaped in a way that rsync understands
    CONTROLPATH_E=$(
        printf '%s\n' "${CONTROLPATH}" |
        sed -e 's/'\''/"'\''"/g' -e 's/"/'\''"'\''/g' -e 's/ /" "/g'
    )
    log "Starting ssh control master..."
    ssh -f -M -N -S "${CONTROLPATH}" "${REMOTE_HOST}" \
        || fatal "couldn't start ssh control master"
    # automatically close the control master at exit, even if
    # killed or interrupted with ctrl-c
    trap 'controlmaster_stop' 0
    trap 'exit 1' HUP INT QUIT TERM
}

controlmaster_stop() {
    log "Closing ssh control master..."
    ssh -O exit -S "${CONTROLPATH}" "${REMOTE_HOST}" >/dev/null \
        || fatal "couldn't close ssh control master"
}

controlmaster_start
try ssh -S "${CONTROLPATH}" "${REMOTE_HOST}" some_command
try scp -o ControlPath="${CONTROLPATH}" \
    some_file "${REMOTE_HOST}":some_path
try rsync -e "ssh -S ${CONTROLPATH_E}" -avz \
    some_dir "${REMOTE_HOST}":some_path

# the control master will automatically close once the script exits
1 голос
/ 23 июня 2011

Я мог бы указать альтернативное решение для этого.Вместо того, чтобы хранить ключ на сервере A, я бы держал ключ локально.Теперь я бы создал локальный порт для пересылки на сервер B на порт 4000.

ssh -L 4000:B:22 usernam@A

, а затем в новом терминале подключился через туннель к серверу B.

ssh -p 4000 -i key_copied_from_a user_on_b@localhost

Я не знаю, насколько это возможно для вас.

0 голосов
/ 23 июня 2011

Создание команд в виде строки довольно сложно, как вы обнаружили.Гораздо надежнее использовать массивы:

cmd=( ssh-keygen -p -P "$1" -N "" -f "$2" )
echo "${cmd[@]}"
"${cmd[@]}"

Или даже использовать позиционные параметры

passphrase="$1"
keyfile="$2"
set -- ssh-keygen -p -P "$passphrase" -N "" -f "$keyfile"
echo "$@"
"$@"

Пустой аргумент не будет отображаться в кавычках, но он есть

...