Frage Ssh-copy-id automatisieren


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

ssh-copy-id user@myserver 

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

Wie kann ich ein Skript schreiben, das automatisch das Passwortfeld ausfüllt, wenn ssh-copy-id fragt danach?


21
2017-08-30 18:17


Ursprung


Warum verwenden Sie die Benutzer- / Ausweisidentifikation anstelle der Benutzer / Publickey-Identifikation? - kagali-san
weil ich dieses Skript verwende, um den Benutzer / publickey einzurichten. - devin


Antworten:


Sieh dir das an sshpass. Fügen Sie Ihr Passwort in eine Textdatei ein und tun Sie Folgendes:

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

21
2017-08-31 02:33





Sie können erwarten, auf die Passwortabfrage zu hören und Ihr Passwort 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 nennen Sie es wie folgt: ./login.expect user@myserver


18
2017-08-30 19:21



Brauchen Sie eine neuere Version von Bash zu verwenden? spawn? Aus Gründen, die ich nicht kontrollieren kann, bleibe ich bei Bash v3.2 stecken. - devin
Bash-Version sollte keine Rolle spielen. Ich habe mit 5.44.1.15 getestet, aber ich habe ähnliche mit älteren Versionen von expect verwendet. Haben Sie Probleme mit dem Skript? - MonkeeSage
spawn: command not found - devin
spawn ist ein Expect-Schlüsselwort (siehe Handbuch expect (1)). Klingt so, als würde das Skript eher als Shell interpretiert als erwartet. Hast du erwartet installiert? Was passiert, wenn Sie direkt erwarten: expect -f login.expect user@myserver - MonkeeSage
Das einzige Problem ist The authenticity of host can't be established. Are you sure you want to continue connecting (yes/no)? für neue Server. - Envek


Dies ist ein Problem mit ssh-copy-id; Es fügt auch jedes Mal einen Schlüssel hinzu, wenn Sie es ausführen. Wenn Sie den Prozess automatisieren, wird Ihre authorized_keys-Datei schnell mit doppelten Schlüsseln überladen. Hier ist ein Python-Programm, das beide Probleme vermeidet. Es läuft vom Control-Server und legt die Schlüssel von einem Remote-Server auf einen anderen Remote-Server.

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'

1
2018-01-24 19:34



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


Anstatt Ihr Passwort mehrmals einzugeben, können Sie es verwenden pssh und sein -A Wechseln Sie einmal zur Eingabeaufforderung und geben Sie dann das Kennwort an alle Server in einer Liste weiter.

HINWEIS: Mit dieser Methode können Sie nicht verwenden ssh-copy-idSie müssen jedoch Ihre eigene Methode zum Anhängen Ihrer SSH-Pub-Schlüsseldatei an Ihr Remote-Konto einrichten ~/.ssh/authorized_keys Datei.

Beispiel

Hier ist ein Beispiel, das die Aufgabe erfüllt:

$ 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 wie folgt strukturiert:

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

Hohes Level pssh Einzelheiten

  • cat <pubkey> gibt die öffentliche Schlüsseldatei an pssh
  • pssh nutzt die -I wechseln Sie, um Daten über STDIN aufzunehmen
  • -l <remote user> ist das Konto des Remote-Servers (wir nehmen an, dass Sie den gleichen Benutzernamen auf den Servern in der IP-Datei haben)
  • -A erzählt pssh um nach Ihrem Passwort zu fragen und es dann für alle Server wiederzuverwenden, mit denen es sich verbindet
  • -i erzählt pssh um eine Ausgabe an STDOUT zu senden, anstatt sie in Dateien zu speichern (Standardverhalten)
  • '...cmds to add pubkey...' - Das ist der heikelste Teil von dem, was vor sich geht, also werde ich das selbst auflösen (siehe unten)

Befehle werden auf entfernten Servern ausgeführt

Dies sind die Befehle, die pssh läuft auf jedem Server:

'                                         \
  umask 077;                              \
  mkdir -p ~/.ssh;                        \
  afile=~/.ssh/authorized_keys;           \
  cat - >> $afile;                        \
  sort -u $afile -o $afile                \
'
In Ordnung:
  • setze die Umask des entfernten Benutzers auf 077, dies ist so, dass alle Verzeichnisse oder Dateien, die wir erstellen werden, ihre Berechtigungen entsprechend eingestellt haben werden:

    $ 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
    
  • Erstelle das Verzeichnis ~/.ssh und ignoriere uns, wenn es schon da ist

  • setze eine Variable, $afilemit dem Pfad zur Datei authorized_keys
  • cat - >> $afile - Nehmen Sie die Eingabe von STDIN und hängen Sie an die Datei authorized_keys an
  • sort -u $afile -o $afile - Sortiert die Datei authorized_keys eindeutig und speichert sie

HINWEIS: Dieses letzte Bit soll den Fall behandeln, in dem Sie das oben genannte mehrere Male gegen die gleichen Server laufen lassen. 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 einfache Anführungszeichen eingebettet sind. Das ist wichtig, weil wir nicht wollen $afile erst nach der Ausführung auf dem Remote-Server ausgewertet werden.

'               \
   ..cmds...    \
'

Ich habe das oben Erwähnte erweitert, so dass es einfacher ist, hier zu lesen, aber ich führe es in der Regel in einer einzigen Zeile:

$ 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 Nutzung pssh Sie können darauf verzichten, Dateien erstellen zu müssen und entweder dynamischen Inhalt mit Hilfe von -h <(...some command...) oder Sie können eine Liste von IPs mit einem anderen erstellen psshSchalter, -H "ip1 ip2 ip3".

Zum Beispiel:

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

Das obige könnte verwendet werden, um eine Liste von IPs von meinem zu extrahieren ~/.ssh/config Datei. Sie können natürlich auch verwenden printf um auch dynamischen Inhalt zu generieren:

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

Zum Beispiel:

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

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

Referenzen und ähnliche Tools zu pssh

Wenn Sie nicht verwenden möchten pssh Wie ich oben getan habe, gibt es einige andere Optionen.


1
2017-07-21 02:02



Ansible's authorized_key_module scheint nicht für neue Maschine zu arbeiten. Ich muss zuerst ssh-copy-id xxx, also suche ich nach einem Weg einfach benutze ansible add ssh-key für neue Maschine, irgendeine Idee? - Mithril
@mithril - klingt wie ein Bug, würde ich in den Ansible Foren danach fragen. - slm


Eines der parallelen SSH-Tools (clusterssh, mssh, pssh) kann für Sie geeignet sein.

Verwenden Sie zum Beispiel cssh, um sich bei allen Maschinen anzumelden, und hängen Sie den Schlüssel selbst an.


0
2017-08-30 18:24



Ich habe bereits eine Reihe von benutzerdefinierten Tools für alles, was ich brauche, außer das Kopieren des Schlüssels, der ist. - devin
Genau ... also nutze dieses eine Werkzeug, um die eine Aufgabe zu erledigen, die noch fehlt. Obwohl dies eine fortlaufende Sache sein wird, wäre das Skript, das MonkeeSage gepostet hat (angepasst, um das Passwort von stdin zu lesen und auf mehreren Servern zu arbeiten), wahrscheinlich die beste Wahl. - MikeyB


Ein paar Dinge, die zur Rechnung passen könnten:

Wie in anderen Antworten erwähnt, ist sshpass wahrscheinlich die einfachste Lösung.


0
2018-02-27 18:45





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

  1.  Verwenden Sie in Ihren Skripten ein fest codiertes Passwort
  2.  Benutze das gleiche Passwort auf ALLEN deinen Servern ... wie ... warum?
  3.  Verwenden Sie SSH public_key + Passwort-Authentifizierung NICHT, 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 

0
2017-10-13 18:59