Automatizzare ssh-copy-id


30

Ho un numero arbitrario di server con la stessa combinazione utente / pass. Voglio scrivere una sceneggiatura (che chiamo una volta) in modo che

ssh-copy-id user@myserver

viene chiamato per ciascun server. Dal momento che tutti hanno lo stesso utente / passaggio, questo dovrebbe essere facile, ma ssh-copy-idvuole che io scriva la password separatamente ogni volta che vanifica lo scopo del mio script. Non è possibile inserire una password, ad es ssh-copy-id -p mypassword user@myserver.

Come posso scrivere uno script che compila automaticamente il campo della password quando lo ssh-copy-idrichiede?


perché usi l'identificazione utente / pass anziché l'identificazione utente / publickey?
Kagali-san,

16
perché sto usando questo script per impostare l'utente / publickey.
Devin,

Risposte:


28

Dai un'occhiata a sshpass . Inserisci la tua password in un file di testo e fai qualcosa del genere:

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

non funziona su Centos7 appena eseguito senza errori e nessuna chiave sul server remoto
ImranRazaKhan

19

Puoi usare prevede di ascoltare la richiesta della password e inviare la tua password:

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

Salva lo script, rendilo eseguibile e chiamalo come: ./login.expect user@myserver


Hai bisogno di una versione più recente di bash da usare spawn? Per motivi che non riesco a controllare sono bloccato con bash v3.2.
Devin,

La versione di Bash non dovrebbe importare. Ho provato con prevedono 5.44.1.15, ma ho usato simili con le versioni precedenti di prevedono. Stai riscontrando problemi nell'uso dello script?
MonkeeSage,

spawn: command not found
Devin,

spawnè una parola chiave aspettarsi (vedi il manuale aspettarsi (1)). Sembra che la sceneggiatura sia interpretata come shell piuttosto che aspettarsi. Ti aspetti installato? Cosa succede se corri aspettati direttamente:expect -f login.expect user@myserver
MonkeeSage

1
@Envek Stavo per aggiungere questo, ma è bello vedere che l'ultimo commento è una domanda diretta per la cosa che stavo per scrivere. Usa questa linea invece:spawn ssh-copy-id -o StrictHostKeyChecking=no $argv
Steven Lu

4

La risposta di Quanta è piuttosto buona, ma richiede di inserire la password in un file di testo.

Dalla pagina man "sshpass":

Se non viene fornita alcuna opzione, sshpass legge la password dall'input standard.

Quindi, ciò che puoi fare è catturare la password una volta durante lo script, memorizzarla in una variabile, fare eco alla password e reindirizzarla a sshpass come input.

Lo faccio sempre e funziona benissimo. Esempio: 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


2

Questo è un problema con ssh-copy-id; inoltre aggiunge una chiave ogni volta che lo esegui. Se si sta automatizzando il processo, il file authorized_keys viene rapidamente ingombra di chiavi duplicate. Ecco un programma Python che evita entrambi i problemi. Funziona dal server di controllo e inserisce le chiavi da un server remoto a un altro server 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'

my ssh-copy-id lo fa già: ATTENZIONE: tutte le chiavi sono state ignorate perché già esistenti sul sistema remoto. È questo il tuo tentativo di rubare le chiavi? :)
Mihai Stanescu,

2

Anziché digitare la password più volte è possibile utilizzare psshe il relativo -Ainterruttore per richiederla una volta, quindi inviare la password a tutti i server in un elenco.

NOTA: l' utilizzo di questo metodo non ti consente di utilizzarlo ssh-copy-id, tuttavia, dovrai eseguire il rollup del tuo metodo per aggiungere il file della chiave pub SSH al file del tuo account remoto ~/.ssh/authorized_keys.

Esempio

Ecco un esempio che fa il lavoro:

$ 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

Lo script sopra è generalmente strutturato in questo modo:

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

psshDettagli di alto livello

  • cat <pubkey> genera il file della chiave pubblica su pssh
  • psshutilizza l' -Iinterruttore per inserire i dati tramite STDIN
  • -l <remote user> è l'account del server remoto (supponiamo che tu abbia lo stesso nome utente tra i server nel file IP)
  • -Adice psshdi chiedere la password e di riutilizzarla per tutti i server a cui si connette
  • -iindica psshdi inviare qualsiasi output a STDOUT anziché memorizzarlo in file (comportamento predefinito)
  • '...cmds to add pubkey...'- questa è la parte più delicata di ciò che sta succedendo, quindi la analizzerò da sola (vedi sotto)

Comandi in esecuzione su server remoti

Questi sono i comandi che psshverranno eseguiti su ciascun server:

'                                         \
  umask 077;                              \
  mkdir -p ~/.ssh;                        \
  afile=~/.ssh/authorized_keys;           \
  cat - >> $afile;                        \
  sort -u $afile -o $afile                \
'
In ordine:
  • imposta umask dell'utente remoto su 077, in modo che tutte le directory o i file che creeremo, abbiano le autorizzazioni impostate di conseguenza in questo modo:

    $ 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
    
  • crea la directory ~/.sshe ignora avvisandoci se è già lì

  • imposta una variabile, $afilecon il percorso del file authorized_keys
  • cat - >> $afile - accetta input da STDIN e accoda al file authorized_keys
  • sort -u $afile -o $afile - ordina in modo univoco il file authorized_keys e lo salva

NOTA: l' ultimo bit è quello di gestire il caso in cui si esegue più volte sopra con gli stessi server. Questo eliminerà il tuo pubkey dall'essere aggiunto più volte.

Nota le singole zecche!

Prestare inoltre particolare attenzione al fatto che tutti questi comandi sono nidificati all'interno di virgolette singole. Questo è importante, dal momento che non vogliamo $afileessere valutati fino a quando non viene eseguito sul server remoto.

'               \
   ..cmds...    \
'

Ho ampliato quanto sopra, quindi è più facile da leggere qui, ma in genere eseguo tutto su una sola riga in questo modo:

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

Materiale bonus

Utilizzando psshsi può rinunciare dover costruire i file e sia di fornire contenuti dinamici utilizzando -h <(...some command...)oppure è possibile creare un elenco di IP utilizzando un altro di pssh's interruttori, -H "ip1 ip2 ip3".

Per esempio:

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

Quanto sopra potrebbe essere utilizzato per estrarre un elenco di IP dal mio ~/.ssh/configfile. Ovviamente puoi anche usare printfper generare contenuti dinamici:

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

Per esempio:

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

Puoi anche usare seqper generare sequenze di numeri formattati!

Riferimenti e strumenti simili a pssh

Se non si desidera utilizzare psshcome ho già fatto sopra, ci sono alcune altre opzioni disponibili.


Ansible's authorized_key_modulesembra non funzionare per la nuova macchina. Devo prima ssh-copy-id xxx, quindi sto cercando un modo per usare ansible aggiungere ssh-key per la nuova macchina, qualche idea?
Mithril,

@mithril - sembra un bug, lo chiederei nei forum Ansible a riguardo.
slm,

1

Uno degli strumenti SSH paralleli (clusterssh, mssh, pssh) potrebbe essere adatto a te.

Ad esempio, utilizzare cssh per accedere a tutte le macchine e aggiungere la chiave da soli.


1
Ho già un set di strumenti personalizzati per fare tutto ciò di cui ho bisogno, tranne per copiare la chiave che è.
Devin,

Esatto ... quindi usa questo strumento per fare l'unica attività che manca. Anche se questa sarà una cosa in corso, lo script pubblicato da MonkeeSage (adattato per leggere la password da stdin e lavorare su più server) sarebbe probabilmente la soluzione migliore.
MikeyB,


0

Voglio sottolineare quanto sia cattiva l'idea di:

  1. Usa una password hardcoded nei tuoi script
  2. Usa la stessa password su TUTTI i tuoi server ... come ... perché !?
  3. NON usare SSH public_key + autenticazione password se insisti su questo
  4. Salva la password in un file di testo

Ecco un'implementazione un po 'più sicura ...

#!/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 
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.