Automatizando ssh-copy-id

22

Eu tenho um número arbitrário de servidores com a mesma combinação de usuário / senha. Eu quero escrever um script (que eu chamo uma vez) para que

ssh-copy-id user@myserver

é chamado para cada servidor. Uma vez que todos eles têm o mesmo usuário / passe, isso deve ser fácil, mas ssh-copy-id quer que eu digite a senha em separado a cada vez que anula o propósito do meu script. Não há opção para colocar uma senha, ou seja, ssh-copy-id -p mypassword user@myserver .

Como posso escrever um script que preenche automaticamente o campo de senha quando ssh-copy-id o solicita?

    
por devin 30.08.2011 / 20:17

8 respostas

22

Dê uma olhada em sshpass . Coloque sua senha em um arquivo de texto e faça algo assim:

$ sshpass -f password.txt ssh-copy-id user@yourserver
    
por 31.08.2011 / 04:33
18

Você pode usar esperar para ouvir o prompt de senha e enviar sua senha:

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

Salve o script, torne-o executável e chame como: ./login.expect user@myserver

    
por 30.08.2011 / 21:21
2

Em vez de digitar sua senha várias vezes, é possível usar a opção pssh e sua -A para solicitar uma vez e, em seguida, alimentar a senha para todos os servidores em uma lista.

OBSERVAÇÃO: No entanto, o uso desse método não permite que você use ssh-copy-id , então você precisará aplicar seu próprio método para anexar o arquivo de chave do seu SSH à% da sua conta remota~/.ssh/authorized_keys file.

Exemplo

Veja um exemplo que faz o trabalho:

$ 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

O script acima é geralmente estruturado da seguinte forma:

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

Alto nível pssh detalhes

  • cat <pubkey> envia o arquivo de chave pública para pssh
  • pssh usa a opção -I para ingerir dados via STDIN
  • -l <remote user> é a conta do servidor remoto (presumimos que você tenha o mesmo nome de usuário nos servidores no arquivo IP)
  • -A informa pssh para pedir sua senha e reutilizá-la para todos os servidores aos quais ela se conecta
  • -i informa pssh para enviar qualquer saída para STDOUT em vez de armazená-la em arquivos (seu comportamento padrão)
  • '...cmds to add pubkey...' - esta é a parte mais complicada do que está acontecendo, então eu vou dividir isso por si mesmo (veja abaixo)

Comandos sendo executados em servidores remotos

Estes são os comandos que pssh executará em cada servidor:

'                                         \
  umask 077;                              \
  mkdir -p ~/.ssh;                        \
  afile=~/.ssh/authorized_keys;           \
  cat - >> $afile;                        \
  sort -u $afile -o $afile                \
'
Em ordem:
  • defina a umask do usuário remoto para 077, para que quaisquer diretórios ou arquivos que criarmos tenham suas permissões definidas da seguinte forma:

    $ 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
    
  • crie o diretório ~/.ssh e ignore o aviso se já estiver lá

  • definir uma variável, $afile , com o caminho para o arquivo authorized_keys
  • cat - >> $afile - recebe entrada de STDIN e anexa ao arquivo authorized_keys
  • sort -u $afile -o $afile - classifica exclusivamente o arquivo authorized_keys e salva-o

OBSERVAÇÃO: Esse último bit é para lidar com o caso em que você executa o exemplo acima várias vezes em relação aos mesmos servidores. Isso eliminará o seu pubkey de ser adicionado várias vezes.

Observe o único carrapato!

Preste também atenção especial ao fato de que todos esses comandos estão aninhados dentro de aspas simples. Isso é importante, já que não queremos que $afile seja avaliado até que esteja sendo executado no servidor remoto.

'               \
   ..cmds...    \
'

Expandi o acima, para facilitar a leitura aqui, mas geralmente executo tudo em uma única linha da seguinte forma:

$ 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'

Material bônus

Ao usar pssh , você pode não ter que construir arquivos e fornecer conteúdo dinâmico usando -h <(...some command...) ou pode criar uma lista de IPs usando outro dos comutadores pssh , -H "ip1 ip2 ip3" .

Por exemplo:

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

O acima pode ser usado para extrair uma lista de IPs do meu arquivo ~/.ssh/config . Você também pode usar printf para gerar conteúdo dinâmico também:

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

Por exemplo:

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

Você também pode usar seq para gerar sequências de números formatados também!

Referências e amp; ferramentas semelhantes para pssh

Se você não quiser usar pssh como eu fiz acima, há algumas outras opções disponíveis.

por 21.07.2016 / 04:02
1

Uma das ferramentas paralelas do SSH (clusterssh, mssh, pssh) pode ser apropriada para você.

Por exemplo, use o cssh para efetuar login em todas as máquinas e anexar a chave você mesmo.

    
por 30.08.2011 / 20:24
1

Este é um problema com o ssh-copy-id; Ele também adiciona uma chave toda vez que você o executa. Se você estiver automatizando o processo, seu arquivo authorized_keys ficará rapidamente cheio de chaves duplicadas. Aqui está um programa em Python que evita ambos os problemas. Ele é executado a partir do servidor de controle e coloca as chaves de um servidor remoto em outro servidor remoto.

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'
    
por 24.01.2015 / 20:34
1

A resposta do quanta é muito boa, mas requer que você coloque sua senha em um arquivo de texto.

Na página do manual "sshpass":

If no option is given, sshpass reads the password from the standard input.

Então, o que você pode fazer é capturar a senha uma vez durante o script, armazená-la em uma variável, ecoar a senha e canalizar isso para sshpass como uma entrada.

Eu faço isso o tempo todo e tudo funciona bem. Exemplo: 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

    
por 21.11.2018 / 22:48
0

Algumas coisas que podem se encaixar na fatura:

Como mencionado em outras respostas, o sshpass é provavelmente a solução mais fácil.

    
por 27.02.2016 / 19:45
0

Eu quero enfatizar o quão ruim é uma idéia:

  1. Use uma senha codificada em seus scripts
  2.  
  3. Use a mesma senha em TODOS os seus servidores ... como ... por quê!?
  4.  
  5. NÃO use SSH public_key + autenticação de senha se você insistir neste
  6.  
  7. Salve a senha em um arquivo de texto

Aqui está uma implementação que é um pouco mais segura ...

#!/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 [email protected]

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 
    
por 13.10.2017 / 20:59