Comment puis-je propager ma clé de publication SSH vers une liste de serveurs sans avoir à taper mon mot de passe encore et encore?

26

J'ai récemment obtenu un nom d'utilisateur / mot de passe pour accéder à une liste de serveurs et je souhaite propager ma clé publique SSH vers ces serveurs, afin de pouvoir me connecter plus facilement.

Pour que ce soit clair:

  • Il n'y a pas de clé publique préexistante sur les serveurs distants que je puisse utiliser pour automatiser cela
  • C'est la toute première fois que je me connecte à ces serveurs, et je ne voudrais pas avoir à taper constamment mes informations d'identification pour y accéder
  • Je ne veux pas non plus taper mon mot de passe encore et encore en utilisant ssh-copy-idune boucle for.
slm
la source
1
C'est le même nom d'utilisateur et mot de passe pour tous les serveurs?
roaima
@roaima - yup! Ce détail m'a également surpris, mais c'est la configuration de ce centre de données en particulier et c'est ainsi qu'ils le font.
slm
@ ott-- - revérifiez le Q. Je déclare explicitement que je ne veux pas faire de boucle ssh-copy-id, pompant mon mot de passe encore et encore.
slm
Voir aussi le script pour automatiser scp en réseau
Gilles 'SO- arrête d'être méchant'
2
C'est un cas d'utilisation parfait pour la gestion de la configuration. Regardez la marionnette, le chef, l'ansible ou le sel.
spuder

Réponses:

31

Plutôt que de taper votre mot de passe plusieurs fois, vous pouvez utiliser psshet son -Acommutateur pour le demander une fois, puis envoyer le mot de passe à tous les serveurs d'une liste.

REMARQUE: l' utilisation de cette méthode ne vous permet pas d'utiliser ssh-copy-id, cependant, vous devrez donc rouler votre propre méthode pour ajouter votre fichier de clé de publication SSH au fichier de votre compte distant ~/.ssh/authorized_keys.

Exemple

Voici un exemple qui fait le travail:

$ 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

Le script ci-dessus est généralement structuré comme suit:

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

psshDétails de haut niveau

  • cat <pubkey> sort le fichier de clé publique vers pssh
  • psshutilise le -Icommutateur pour ingérer des données via STDIN
  • -l <remote user> est le compte du serveur distant (nous supposons que vous avez le même nom d'utilisateur sur les serveurs dans le fichier IP)
  • -Aindique psshde demander votre mot de passe, puis de le réutiliser pour tous les serveurs auxquels il se connecte
  • -iindique psshd'envoyer n'importe quelle sortie à STDOUT plutôt que de la stocker dans des fichiers (son comportement par défaut)
  • '...cmds to add pubkey...'- c'est la partie la plus délicate de ce qui se passe, donc je vais le décomposer par lui-même (voir ci-dessous)

Commandes exécutées sur des serveurs distants

Ce sont les commandes qui psshs'exécuteront sur chaque serveur:

'                                         \
  umask 077;                              \
  mkdir -p ~/.ssh;                        \
  afile=~/.ssh/authorized_keys;           \
  cat - >> $afile;                        \
  sort -u $afile -o $afile                \
'
En ordre:
  • définissez umask de l'utilisateur distant sur 077, afin que tous les répertoires ou fichiers que nous allons créer, leurs autorisations soient définies en conséquence, comme suit:

    $ 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
    
  • créer le répertoire ~/.sshet ignorer nous avertir s'il est déjà là

  • définir une variable,, $afileavec le chemin d'accès au fichier authorized_keys
  • cat - >> $afile - prendre l'entrée de STDIN et l'ajouter au fichier authorized_keys
  • sort -u $afile -o $afile - trie de manière unique le fichier authorized_keys et l'enregistre

Remarque: ce dernier bit est de gérer le cas où vous exécutez plusieurs fois ci-dessus sur les mêmes serveurs. Cela évitera que votre clé pub ne soit ajoutée plusieurs fois.

Remarquez les tiques simples!

Portez également une attention particulière au fait que toutes ces commandes sont imbriquées à l'intérieur de guillemets simples. C'est important, car nous ne voulons $afileêtre évalués qu'après son exécution sur le serveur distant.

'               \
   ..cmds...    \
'

J'ai développé ce qui précède, il est donc plus facile à lire ici, mais je le lance généralement sur une seule ligne comme ceci:

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

Matériel bonus

En utilisant , psshvous pouvez renoncer à avoir à construire des fichiers et soit fournir un contenu dynamique à l' aide -h <(...some command...)ou vous pouvez créer une liste d'adresses IP en utilisant un autre des psshcommutateurs de », -H "ip1 ip2 ip3".

Par exemple:

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

Ce qui précède pourrait être utilisé pour extraire une liste d'adresses IP de mon ~/.ssh/configfichier. Bien sûr, vous pouvez également utiliser printfpour générer du contenu dynamique:

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

Par exemple:

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

Vous pouvez également utiliser seqpour générer des séquences de nombres formatés aussi!

Références et outils similaires à pssh

Si vous ne souhaitez pas l'utiliser psshcomme je l'ai fait ci-dessus, d'autres options sont disponibles.

slm
la source
2
Trois ajouts mineurs: (1) psshest un script Python, et peut être installé avec pip install pssh. (2) Vous pouvez également générer des sshclés sur tous les serveurs simultanément en exécutant à ssh-keygentravers pssh. (3) Après avoir généré les clés, vous pouvez distribuer les clés "tout-à-tout" en copiant toutes les clés publiques en boucle sur la machine locale, en les assemblant dans un commun authorized_keyset en les copiant sur chaque machine. ssh_agent/ ssh_addpeut aider avec les mots de passe.
lcd047
@ lcd047 - merci, je les intégrerai dans le A plus tard dans la
journée
1
Je pense que ce script se qualifie pour l'utilisation inutile de cataward (of old): pour démarrer un pipeline avec le contenu d'un fichier, vous pouvez simplement rediriger l'entrée de ce fichier.
Marc van Leeuwen
1
@MarcvanLeeuwen - J'aurais tendance à être d'accord, mais je voulais que cela soit plus facile pour quiconque pourrait trouver cela via de futures recherches pour comprendre clairement comment la clé de pub est transmise pssh.
slm
1
@MarcvanLeeuwen: Il est plus inutile si vous le faites comme ceci: cat ~/.ssh/*.pub | .... Cela peut ou non être ce que vous voulez dans cette situation.
lcd047
7

En utilisant les autres xargs, sshpasset ssh-copy-id:

En supposant que vos informations d'identification vivent dans credentials.txt au format user:password@server:

$ cat credentials.txt
root:insecure@192.168.0.1
foo:insecure@192.168.0.2
bar:realsecure@192.168.0.3

Vous pourriez faire:

tr ':@' '\n' < credentials.txt \
| xargs -L3 sh -c 'sshpass -p $1 ssh-copy-id $0@$2'

Remarque: N'oubliez pas de supprimer credentials.txt après utilisation!

FloHimself
la source
2
Et s'il s'agit du même nom d'utilisateur et du même mot de passe pour tous les serveurs, vous pouvez simplement les coder en dur et lire uniquement une liste d'adresses IP :-)
Falco
6

ClusterSSH vous donne une fenêtre sur chaque machine et avec une fenêtre commune pour contrôler toutes les fenêtres.

Si nous parlons de 10 machines, cela fonctionnera. Si nous parlons de 100 machines, il y aura de nombreuses fenêtres.

La beauté de ClusterSSH est que si une machine n'est pas à 100% comme les autres, vous pouvez simplement cliquer sur la fenêtre et envoyer des frappes uniquement à cette machine avant de retourner à l'envoi de frappes à toutes les machines.

Ole Tange
la source
6

L'utilisation d' Ansible est assez simple. Remplacez simplement <USER>par le vrai nom de connexion

$ cd /path/to/public/key

$ cat<<END > hosts
  host1.example.com
  10.10.10.10
  END

$ ansible -i hosts all --ask-pass -u <USER> -m authorized_key \
      -a "user=<USER> key='$(cat id_rsa.pub)'"        
Daniel Wakefield
la source
0

Quelques choses qui pourraient potentiellement correspondre au projet de loi:

Comme mentionné dans d'autres réponses, sshpassest probablement la solution la plus simple.

Richlv
la source
-1

Vous avez deux options ici:

  • Vous pouvez créer un fichier avec toutes les adresses IP des serveurs, puis procédez comme suit

    while read -r ip;do
      ssh-copy-id -i .ssh/id_rsa.pub $ip
    done < servers.txt

En supposant que servers.txtle fichier contient des adresses IP / noms d'hôte.

  • Vous pouvez mettre toutes vos adresses IP / noms d'hôte dans une boucle et exécuter ssh-copy-idcomme ci-dessous:

    for i in hostname1 hostname2
      do ssh-copy-id -i .ssh/id_rsa.pub $i
    done
Tolga Ozses
la source
Ce qui va complètement à l'encontre des exigences des PO: "Je ne veux pas non plus taper mon mot de passe encore et encore en utilisant ssh-copy-idune boucle for."
OldTimer
Je ne pense pas qu'il existe un autre moyen, sauf si OP est disposé à copier physiquement sur tous les serveurs.
Tolga Ozses