Назад | Перейти на главную страницу

Автоматизация ssh-copy-id

У меня есть произвольное количество серверов с одной и той же комбинацией пользователь / пароль. Я хочу написать сценарий (который я вызываю один раз), чтобы

ssh-copy-id user@myserver

вызывается для каждого сервера. Поскольку у всех один и тот же пользователь / пропуск, это должно быть легко, но ssh-copy-id хочет, чтобы я вводил пароль отдельно каждый раз, что противоречит цели моего сценария. Нет возможности ввести пароль, т.е. ssh-copy-id -p mypassword user@myserver.

Как мне написать скрипт, который автоматически заполняет поле пароля при ssh-copy-id просит об этом?

Взгляни на sshpass. Поместите свой пароль в текстовый файл и сделайте что-то вроде этого:

$ sshpass -f password.txt ssh-copy-id user@yourserver

Вы можете использовать ожидание, чтобы прослушать запрос пароля и отправить свой пароль:

#!/usr/bin/expect -f
spawn ssh-copy-id $argv
expect "password:"
send "YOUR_PASSWORD\n"
expect eof

Сохраните сценарий, сделайте его исполняемым и назовите его так: ./login.expect user@myserver

Ответ Quanta довольно хорош, но он требует, чтобы вы поместили свой пароль в текстовый файл.

На странице руководства "sshpass":

Если опция не указана, sshpass считывает пароль со стандартного ввода.

Итак, что вы можете сделать, так это захватить пароль один раз во время выполнения сценария, сохранить его в переменной, отобразить пароль и передать его sshpass в качестве входных данных.

Я делаю это постоянно, и все работает нормально. Пример: echo "Please insert the password used for ssh login on remote machine:" read -r USERPASS for TARGETIP in $@; do echo "$USERPASS" | sshpass ssh-copy-id -f -i $KEYLOCATION "$USER"@"$TARGETIP" done

Это проблема с ssh-copy-id; он также добавляет ключ каждый раз, когда вы его запускаете. Если вы автоматизируете процесс, ваш файл authorized_keys быстро забивается дублирующимися ключами. Вот программа на Python, которая позволяет избежать обеих проблем. Он запускается с управляющего сервера и помещает ключи с одного удаленного сервера на другой удаленный сервер.

import subprocess
def Remote(cmd,IP):
    cmd = '''ssh root@%s '''%(IP)+cmd
    lines = subprocess.check_output(cmd.split())
    return '\n'.join(lines)
source = '123.456.78.90'
target = '239.234.654.123'
getkey = 'cat /root/.ssh/id_rsa.pub'
getauth = 'cat /root/.ssh/authorized_keys'
sourcekey = Remote(getkey, source).replace('\n','').strip()
authkeys = Remote(getauth, target).replace('\n','').strip()
if sourcekey not in authkeys: 
    keycmd=''' echo "%s" >>/root/.ssh/authorized_keys; 
    chmod 600 /root/.ssh/authorized_keys '''%(sourcekey) # A compound shell statement
    print 'Installed key', Remote(keycmd,target)
else: print 'Does not need key'

Вместо того, чтобы вводить пароль несколько раз, вы можете использовать pssh и это -A переключитесь, чтобы запросить его один раз, а затем введите пароль на все серверы в списке.

НОТА: Использование этого метода не позволяет использовать ssh-copy-id, однако вам нужно будет использовать свой собственный метод для добавления файла ключа публикации SSH в файл удаленной учетной записи. ~/.ssh/authorized_keys файл.

пример

Вот пример, который работает:

$ cat ~/.ssh/my_id_rsa.pub                    \
    | pssh -h ips.txt -l remoteuser -A -I -i  \
    '                                         \
      umask 077;                              \
      mkdir -p ~/.ssh;                        \
      afile=~/.ssh/authorized_keys;           \
      cat - >> $afile;                        \
      sort -u $afile -o $afile                \
    '
Warning: do not enter your password if anyone else has superuser
privileges or access to your account.
Password:
[1] 23:03:58 [SUCCESS] 10.252.1.1
[2] 23:03:58 [SUCCESS] 10.252.1.2
[3] 23:03:58 [SUCCESS] 10.252.1.3
[4] 23:03:58 [SUCCESS] 10.252.1.10
[5] 23:03:58 [SUCCESS] 10.252.1.5
[6] 23:03:58 [SUCCESS] 10.252.1.6
[7] 23:03:58 [SUCCESS] 10.252.1.9
[8] 23:03:59 [SUCCESS] 10.252.1.8
[9] 23:03:59 [SUCCESS] 10.252.1.7

Приведенный выше сценарий обычно имеет такую ​​структуру:

$ cat <pubkey> | pssh -h <ip file> -l <remote user> -A -I -i '...cmds to add pubkey...'

Высокий уровень pssh подробности

  • cat <pubkey> выводит файл открытого ключа в pssh
  • pssh использует -I переключиться на получение данных через STDIN
  • -l <remote user> - это учетная запись удаленного сервера (мы предполагаем, что у вас одно и то же имя пользователя на всех серверах в IP-файле)
  • -A говорит pssh чтобы запросить ваш пароль, а затем повторно использовать его для всех серверов, к которым он подключается
  • -i говорит pssh для отправки любого вывода в STDOUT, а не для сохранения его в файлах (поведение по умолчанию)
  • '...cmds to add pubkey...' - это самая сложная часть того, что происходит, поэтому я разберу сам (увидеть ниже)

Команды, выполняемые на удаленных серверах

Это команды, которые pssh будет работать на каждом сервере:

'                                         \
  umask 077;                              \
  mkdir -p ~/.ssh;                        \
  afile=~/.ssh/authorized_keys;           \
  cat - >> $afile;                        \
  sort -u $afile -o $afile                \
'
Для того, чтобы:
  • установите umask удаленного пользователя на 077, это значит, что любые каталоги или файлы, которые мы собираемся создать, будут иметь соответствующие права доступа, например так:

    $ ls -ld ~/.ssh ~/.ssh/authorized_keys
    drwx------ 2 remoteuser remoteuser 4096 May 21 22:58 /home/remoteuser/.ssh
    -rw------- 1 remoteuser remoteuser  771 May 21 23:03 /home/remoteuser/.ssh/authorized_keys
    
  • создать каталог ~/.ssh и игнорировать предупреждение, если он уже там

  • установить переменную, $afile, с путем к файлу authorized_keys
  • cat - >> $afile - взять ввод из STDIN и добавить в файл authorized_keys
  • sort -u $afile -o $afile - однозначно сортирует файл authorized_keys и сохраняет его

НОТА: Этот последний бит предназначен для обработки случая, когда вы запускаете вышеуказанное несколько раз на одних и тех же серверах. Это избавит вас от многократного добавления вашего pubkey.

Обратите внимание на отдельные отметки!

Также обратите особое внимание на то, что все эти команды заключены в одинарные кавычки. Это важно, поскольку мы не хотим $afile чтобы получить оценку до тех пор, пока он не будет запущен на удаленном сервере.

'               \
   ..cmds...    \
'

Я расширил приведенное выше, чтобы его было легче читать, но я обычно запускаю все в одной строке, например:

$ cat ~/.ssh/my_id_rsa.pub | pssh -h ips.txt -l remoteuser -A -I -i 'umask 077; mkdir -p ~/.ssh; afile=~/.ssh/authorized_keys; cat - >> $afile; sort -u $afile -o $afile'

Бонусный материал

Используя pssh вы можете отказаться от создания файлов и предоставить динамический контент, используя -h <(...some command...) или вы можете создать список IP-адресов, используя другой из psshпереключатели, -H "ip1 ip2 ip3".

Например:

$ cat .... | pssh -h <(grep -A1 dp15 ~/.ssh/config | grep -vE -- '#|--') ...

Вышеупомянутое можно использовать для извлечения списка IP-адресов из моих ~/.ssh/config файл. Конечно, вы также можете использовать printf также для создания динамического контента:

$ cat .... | pssh -h <(printf "%s\n" srv0{0..9}) ....

Например:

$ printf "%s\n" srv0{0..9}
srv00
srv01
srv02
srv03
srv04
srv05
srv06
srv07
srv08
srv09

Вы также можете использовать seq для генерации форматированных числовых последовательностей!

Ссылки и аналогичные инструменты на pssh

Если вы не хотите использовать pssh как я сделал это выше, есть и другие варианты.

Вам может подойти один из параллельных инструментов SSH (clusterssh, mssh, pssh).

Например, используйте cssh для входа на все машины и добавьте ключ самостоятельно.

Пара вещей, которые могут соответствовать всем требованиям:

Как упоминалось в других ответах, sshpass, вероятно, является самым простым решением.

Я хочу подчеркнуть, насколько плохая идея:

  1. Используйте жестко запрограммированный пароль в своих скриптах
  2. Используйте один и тот же пароль на ВСЕХ своих серверах ... например ... почему !?
  3. НЕ используйте SSH public_key + аутентификацию с паролем, если вы настаиваете на этом
  4. Сохраните пароль в текстовый файл

Вот реализация, которая немного более безопасна ...

#!/usr/bin/python3
import os
import getpass
import argparse

parser = argparse.argument_parser()
parser.add_argument('-l','--login', action='store', help='username')
parser.add_argument('-p','--port', action='store', default='22', help='port')
parser.add_argument('-L','--list', action='store', help='file list of IPs')
parser.add_argument('-i','--ip-address', action='store', nargs='+', metavar='host' help='ip or list of ips')

args = parser.parse_args()
if not args.login:
    print("You need a login, broski!")
    return 0

if args.list:
    ips = [i for i in open(args.list, 'r').readlines()]
    passwd = getpass.getpass('Password: ')

    for ip in ips:
        cmd = 'ssh-id-copy {0}@{1} -p {2}'.format(ip,args.port,passwd)            
        os.system('sshpass -p ' + passwd + ' ' + cmd)
        print("Key added: ", ip)   # prints if successful
        # ex: sshpass -p passwd ssh-id-copy login@1.1.1.1

elif args.host:
    ip = args.host
    cmd = 'ssh-id-copy {0}@{1} -p {2}'.format(ip,args.port,passwd)
    os.system('sshpass -p ' + passwd + ' ' + cmd)
    print("Key added: ", ip)   # prints if successful
else:
    print("No IP addresses were given to run script...")
    return 0