如何将SSH发布密钥分发到服务器列表,而不必一遍又一遍地输入密码?


26

最近,我获得了用户名/密码访问服务器列表的权限,并希望将我的SSH公钥传播到这些服务器,以便我可以更轻松地登录。

这样很清楚:

  • 远程服务器上没有任何可用于自动执行此操作的公钥
  • 这是我第一次登录这些服务器,并且我不想经常输入我的凭据来访问它们
  • 我也不想一遍又一遍地ssh-copy-id在for循环中输入密码。

1
所有服务器的用户名和密码都相同吗?
roaima 2015年

@roaima-是的!这个细节也让我感到惊讶,但这就是特定数据中心设置的方式,这就是他们的工作方式。
slm

@ ott---仔细检查Q。我明确声明我不想进行for循环ssh-copy-id,一遍又一遍地输入密码。
slm


2
这是配置管理的理想用例。看木偶,厨师,红宝石或盐。
spuder

Answers:


31

无需多次输入密码,您可以利用pssh及其-A开关进行一次提示,然后将密码提供给列表中的所有服务器。

注意:ssh-copy-id但是,使用此方法不允许您使用,因此您需要滚动自己的方法来将SSH pub密钥文件附加到远程帐户的~/.ssh/authorized_keys文件中。

这是完成工作的示例:

$ 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

上面的脚本通常是这样构造的:

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

高级pssh细节

  • cat <pubkey> 将公钥文件输出到 pssh
  • pssh使用-I开关通过STDIN提取数据
  • -l <remote user> 是远程服务器的帐户(假设IP文件中各服务器的用户名相同)
  • -A告诉pssh您输入密码,然后将其重新用于连接到的所有服务器
  • -i告诉pssh将任何输出发送到STDOUT而不是将其存储在文件中(默认行为)
  • '...cmds to add pubkey...'-这是正在发生的事情中最棘手的部分,所以我将自己分解(见下文)

在远程服务器上运行的命令

这些是pssh将在每台服务器上运行的命令:

'                                         \
  umask 077;                              \
  mkdir -p ~/.ssh;                        \
  afile=~/.ssh/authorized_keys;           \
  cat - >> $afile;                        \
  sort -u $afile -o $afile                \
'
为了:
  • 将远程用户的umask设置为077,这样我们将要创建的任何目录或文件都将相应地设置其权限,如下所示:

    $ 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
    
  • 创建目录~/.ssh,如果目录已经存在,请忽略警告我们

  • 设置一个变量,$afile其路径为authorized_keys文件
  • cat - >> $afile -接收来自STDIN的输入并附加到authorized_keys文件中
  • sort -u $afile -o $afile -对authorized_keys文件进行唯一排序并保存

注意:最后一点是要处理对同一台服务器多次运行上述操作的情况。这样可以避免多次添加您的发布密钥。

注意单the!

还应特别注意所有这些命令都嵌套在单引号内的事实。这很重要,因为我们要$afile等到它在远程服务器上执行后才能进行评估。

'               \
   ..cmds...    \
'

我已经扩展了上面的内容,因此在这里更容易阅读,但是我通常将它们全部运行在一行上,如下所示:

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

奖金材料

通过使用,pssh您可以不必构造文件并使用来提供动态内容-h <(...some command...),也可以使用的另一个pssh开关创建IP列表-H "ip1 ip2 ip3"

例如:

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

以上内容可用于从我的~/.ssh/config文件中提取IP列表。当然,您也可以printf用于生成动态内容:

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

例如:

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

您也可以seq用来生成格式化的数字序列!

参考和类似工具 pssh

如果您不想像pssh我上面那样使用,可以使用其他一些选项。


2
三个小的补充:(1)pssh是Python脚本,可以与一起安装pip install pssh。(2)您也可以生成ssh通过同时运行所有服务器上的按键ssh-keygen通过pssh。(3)生成密钥后,可以通过将循环中的所有公共密钥复制到本地计算机,将它们组合成一个公共计算机authorized_keys,然后将其复制到每台计算机,来“全部分配”所有密钥。 ssh_agent/ ssh_add可以帮助您输入密码。
lcd047

@ lcd047-谢谢,我今天晚些时候将它们合并到A中!
slm

1
我认为此脚本符合对cat奖赏(旧)的无用使用的条件:要开始使用文件内容的管道,您只需重定向该文件的输入即可。
Marc van Leeuwen

1
@MarcvanLeeuwen-我倾向于同意,但是我希望对于以后通过搜索可能遇到的任何人来说都更容易,以清楚地了解公钥如何传递给pssh
slm

1
@MarcvanLeeuwen:如果你不喜欢这样它不再是无用的:cat ~/.ssh/*.pub | ...。在这种情况下,可能不是您想要的。
lcd047

7

替代使用xargssshpassssh-copy-id

假设您的凭据以以下格式存在于certificate.txtuser:password@server

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

您可以这样做:

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

注意:使用后,请记住删除credentials.txt


2
如果所有服务器的用户名和密码都相同,则可以直接对其进行硬编码,并且仅读取IP地址列表:-)
Falco

6

ClusterSSH在每台计算机上为您提供一个窗口,并具有一个公共窗口来控制所有窗口。

如果我们正在谈论10台机器,这将起作用。如果我们要谈论100台机器,那么会有很多窗口。

ClusterSSH的优点在于,如果一台计算机与其他计算机不是100%一样,您可以单击窗口,然后仅向该计算机发送击键,然后再返回向所有计算机发送击键。


6

使用Ansible非常简单。只需替换<USER>为真实的登录名

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


-1

您在这里有两个选择:

  • 您可以使用所有服务器的IP地址创建一个文件,然后执行以下操作

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

假设servers.txt该文件具有IP /主机名。

  • 您可以将所有IP /主机名放在一个循环中,然后按ssh-copy-id以下方式运行:

    for i in hostname1 hostname2
      do ssh-copy-id -i .ssh/id_rsa.pub $i
    done
    

这完全违反了OP的要求:“我也不想ssh-copy-id在for循环中反复使用我的密码。”
OldTimer 2015年

我认为没有其他方法,除非OP愿意物理复制到所有服务器。
Tolga Ozses 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.