Ssh-copy-id automatisieren


29

Ich habe eine beliebige Anzahl von Servern mit der gleichen Benutzer / Pass-Kombination. Ich möchte ein Skript schreiben (das ich einmal aufrufe) damit

ssh-copy-id user@myserver

wird für jeden Server aufgerufen. Da sie alle den gleichen Benutzer / Pass haben, sollte dies einfach sein, aber ssh-copy-idich möchte, dass ich das Passwort jedes Mal separat eingebe, was den Zweck meines Skripts zunichte macht. Es gibt keine Möglichkeit, ein Passwort einzugeben, dh ssh-copy-id -p mypassword user@myserver.

Wie kann ich ein Skript schreiben, das bei Aufforderung automatisch das Kennwortfeld ausfüllt ssh-copy-id?


Warum verwenden Sie die Benutzer- / Passidentifikation anstelle der Benutzer- / Publikationsidentifikation?
kagali-san

16
weil ich dieses Skript verwende, um den Benutzer / publickey einzurichten.
Devin

Antworten:


27

Schauen Sie sich sshpass an . Legen Sie Ihr Passwort in eine Textdatei und machen Sie so etwas:

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

Es funktioniert nicht auf Centos7 nur ohne Fehler und ohne Schlüssel auf dem Remote-Server
ImranRazaKhan

19

Sie können expect verwenden, um auf die Kennwortabfrage zu warten und Ihr Kennwort zu senden:

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

Speichern Sie das Skript, machen Sie es ausführbar und rufen Sie es wie folgt auf: ./login.expect user@myserver


Benötigen Sie eine neuere Version von Bash spawn? Aus Gründen, die ich nicht kontrollieren kann, bin ich mit Bash v3.2 festgefahren.
Devin

Bash-Version sollte keine Rolle spielen. Ich habe mit Expect 5.44.1.15 getestet, aber ich habe Ähnliches mit älteren Versionen von Expect verwendet. Haben Sie Probleme mit der Verwendung des Skripts?
MonkeeSage

spawn: command not found
Devin

spawnist ein Schlüsselwort expect (siehe Handbuch expect (1)). Klingt so, als würde das Skript eher als Shell interpretiert als erwartet. Hast du das schon installiert? Was passiert, wenn Sie erwarten, direkt ausgeführt:expect -f login.expect user@myserver
MonkeeSage

1
@Envek Ich wollte das gerade hinzufügen, aber es ist schön zu sehen, dass der letzte Kommentar eine direkte Frage für das ist, was ich schreiben wollte. Verwenden Sie stattdessen diese Zeile:spawn ssh-copy-id -o StrictHostKeyChecking=no $argv
Steven Lu

3

Die Antwort von quanta ist ziemlich gut, aber Sie müssen Ihr Passwort in eine Textdatei schreiben.

Aus der Manpage "sshpass":

Wenn keine Option angegeben ist, liest sshpass das Passwort von der Standardeingabe.

Sie können das Kennwort also einmal während des Skripts erfassen, in einer Variablen speichern, das Kennwort als Echo ausgeben und als Eingabe übergeben.

Ich mache das die ganze Zeit und es funktioniert gut. Beispiel: 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

Dies ist ein Problem mit der ssh-copy-id. Außerdem wird bei jeder Ausführung ein Schlüssel hinzugefügt. Wenn Sie den Vorgang automatisieren, wird Ihre authorized_keys-Datei schnell mit doppelten Schlüsseln überfüllt. Hier ist ein Python-Programm, das beide Probleme vermeidet. Es wird vom Steuerungsserver ausgeführt und speichert die Schlüssel von einem Remoteserver auf einem anderen Remoteserver.

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'

meine ssh-copy-id macht das schon: WARNUNG: Alle Schlüssel wurden übersprungen, weil sie bereits auf dem entfernten System existieren. Ist das Ihr Versuch, Schlüssel zu stehlen? :)
Mihai Stanescu

2

Anstatt Ihr Kennwort mehrmals einzugeben, können Sie mit psshund dessen -ASchalter einmal danach fragen und das Kennwort dann an alle Server in einer Liste weiterleiten.

ANMERKUNG: Mit dieser Methode können Sie diese jedoch nicht verwenden. Daher müssen Sie ssh-copy-idIhre eigene Methode zum Anhängen Ihrer SSH-Pub-Schlüsseldatei an die Datei Ihres Remote-Kontos rollen ~/.ssh/authorized_keys.

Beispiel

Hier ist ein Beispiel, das die Arbeit erledigt:

$ 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

Das obige Skript ist im Allgemeinen so aufgebaut:

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

psshDetails auf hohem Niveau

  • cat <pubkey> gibt die öffentliche Schlüsseldatei an aus pssh
  • psshverwendet den -ISchalter, um Daten über STDIN aufzunehmen
  • -l <remote user> ist das Konto des Remote-Servers (wir gehen davon aus, dass Sie auf allen Servern in der IP-Datei den gleichen Benutzernamen haben)
  • -Afordert Sie psshauf, nach Ihrem Kennwort zu fragen und es dann für alle Server zu verwenden, mit denen eine Verbindung hergestellt wird
  • -ierzählt pssheher eine Ausgabe an STDOUT zu senden als Speicher in Dateien (dessen Standardverhalten)
  • '...cmds to add pubkey...'- Das ist der schwierigste Teil des Geschehens, also werde ich das von selbst aufschlüsseln (siehe unten).

Befehle, die auf Remoteservern ausgeführt werden

Dies sind die Befehle, psshdie auf jedem Server ausgeführt werden:

'                                         \
  umask 077;                              \
  mkdir -p ~/.ssh;                        \
  afile=~/.ssh/authorized_keys;           \
  cat - >> $afile;                        \
  sort -u $afile -o $afile                \
'
In Ordnung:
  • Setzen Sie die umask des Remote-Benutzers auf 077, damit alle Verzeichnisse oder Dateien, die wir erstellen, die entsprechenden Berechtigungen haben, und zwar wie folgt:

    $ 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
    
  • Erstellen Sie das Verzeichnis ~/.sshund ignorieren Sie die Warnung, wenn es bereits vorhanden ist

  • Setzen Sie eine Variable $afilemit dem Pfad zur Datei authorized_keys
  • cat - >> $afile - Eingaben von STDIN nehmen und an authorized_keys-Datei anhängen
  • sort -u $afile -o $afile - Sortiert die authorized_keys-Datei eindeutig und speichert sie

ANMERKUNG: Das letzte Bit behandelt den Fall, dass Sie die obigen Schritte mehrmals auf denselben Servern ausführen. Dadurch wird verhindert, dass Ihr Pubkey mehrmals angehängt wird.

Beachten Sie die einzelnen Ticks!

Achten Sie auch besonders darauf, dass alle diese Befehle in einfachen Anführungszeichen stehen. Das ist wichtig, da wir erst $afileausgewertet werden möchten , nachdem es auf dem Remote-Server ausgeführt wurde.

'               \
   ..cmds...    \
'

Ich habe das Obige erweitert, damit es hier leichter zu lesen ist, aber ich führe es im Allgemeinen in einer einzigen Zeile aus:

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

Bonusmaterial

Durch die Verwendung von können psshSie darauf verzichten, Dateien erstellen zu müssen und entweder dynamischen Inhalt mithilfe von bereitzustellen, -h <(...some command...)oder Sie können eine Liste von IPs mithilfe eines anderen psshSwitches von erstellen -H "ip1 ip2 ip3".

Beispielsweise:

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

Das oben Genannte könnte verwendet werden, um eine Liste von IPs aus meiner ~/.ssh/configDatei zu extrahieren . Sie können natürlich auch verwenden printf, um dynamische Inhalte zu generieren:

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

Beispielsweise:

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

Sie können auch verwenden seq, um formatierte Zahlenfolgen zu generieren!

Referenzen & ähnliche Tools zu pssh

Wenn Sie nicht wie oben beschrieben verwenden möchten, stehen Ihnen pssheinige andere Optionen zur Verfügung.


Ansible's authorized_key_modulescheint für neue Maschine nicht zu funktionieren. Ich muss zuerst ssh-copy-id xxx, also suche ich nach einer Möglichkeit, einfach ansible add ssh-key für eine neue Maschine zu verwenden. Irgendeine Idee?
Mithril

@mithril - klingt wie ein Bug, ich würde in den Ansible-Foren danach fragen.
Slm

1

Eines der parallelen SSH-Tools (clusterssh, mssh, pssh) ist möglicherweise für Sie geeignet.

Verwenden Sie beispielsweise cssh, um sich bei allen Computern anzumelden und den Schlüssel selbst anzuhängen.


1
Ich habe bereits eine Reihe von benutzerdefinierten Tools, mit denen ich alles erledigen kann, bis auf das Kopieren des Schlüssels.
Devin

Genau ... also benutze dieses eine Werkzeug, um die eine Aufgabe zu erledigen, die fehlt. Wenn dies jedoch noch nicht abgeschlossen ist, ist das von MonkeeSage veröffentlichte Skript (angepasst, um das Kennwort von stdin zu lesen und auf mehreren Servern zu arbeiten) wahrscheinlich die beste Wahl.
MikeyB


0

Ich möchte betonen, wie schlecht eine Idee ist:

  1. Verwenden Sie in Ihren Skripten ein fest codiertes Kennwort
  2. Verwenden Sie auf ALLEN Servern dasselbe Passwort ... wie ... warum !?
  3. Verwenden Sie NICHT die SSH-Authentifizierung public_key + password, wenn Sie darauf bestehen
  4. Speichern Sie das Passwort in einer Textdatei

Hier ist eine Implementierung, die ein bisschen sicherer ist ...

#!/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 
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.