如何将我的 SSH pub 密钥传播到服务器列表,而不必一遍又一遍地输入密码?

slm*_*slm 28 scripting ssh shell-script

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

这样就很清楚了:

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

slm*_*slm 34

您可以使用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
Run Code Online (Sandbox Code Playgroud)

上面的脚本一般结构如下:

$ cat <pubkey> | pssh -h <ip file> -l <remote user> -A -I -i '...cmds to add pubkey...'
Run Code Online (Sandbox Code Playgroud)

高级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                \
'
Run Code Online (Sandbox Code Playgroud) 为了:
  • 将远程用户的 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
    
    Run Code Online (Sandbox Code Playgroud)
  • 创建目录~/.ssh并忽略警告我们,如果它已经存在

  • $afile使用authorized_keys文件的路径设置变量
  • cat - >> $afile - 从 STDIN 获取输入并附加到 authorized_keys 文件
  • sort -u $afile -o $afile - 对authorized_keys文件进行唯一排序并保存

注意:最后一点是处理针对同一台服务器多次运行上述内容的情况。这将消除您的公钥多次附加。

注意单个刻度!

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

'               \
   ..cmds...    \
'
Run Code Online (Sandbox Code Playgroud)

我已经扩展了上面的内容,所以在这里更容易阅读,但我通常在一行上运行它,如下所示:

$ 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'
Run Code Online (Sandbox Code Playgroud)

奖励材料

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

例如:

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

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

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

例如:

$ printf "%s\n" srv0{0..9}
srv00
srv01
srv02
srv03
srv04
srv05
srv06
srv07
srv08
srv09
Run Code Online (Sandbox Code Playgroud)

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

参考资料和类似工具 pssh

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

  • 三个小补充: (1) `pssh` 是一个 Python 脚本,可以通过 `pip install pssh` 安装。(2) 你也可以通过`pssh`运行`ssh-keygen`,在所有服务器上同时生成`ssh`密钥。(3) 生成密钥后,您可以通过将所有公钥循环复制到本地机器,将它们组装在一个公共的“authorized_keys”中,然后将其复制到每台机器来“全部对全部”分发密钥。`ssh_agent` / `ssh_add` 可以帮助设置密码。 (2认同)

Flo*_*elf 7

替代使用xargs,sshpassssh-copy-id

假设您的凭据以格式保存在credentials.txtuser:password@server

$ cat credentials.txt
root:insecure@192.168.0.1
foo:insecure@192.168.0.2
bar:realsecure@192.168.0.3
Run Code Online (Sandbox Code Playgroud)

你可以这样做:

tr ':@' '\n' < credentials.txt \
| xargs -L3 sh -c 'sshpass -p $1 ssh-copy-id $0@$2'
Run Code Online (Sandbox Code Playgroud)

注意:使用后记得删除credentials.txt

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

小智 7

使用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)'"        
Run Code Online (Sandbox Code Playgroud)


Ole*_*nge 6

ClusterSSH 为您在每台机器上提供一个窗口,并使用一个通用窗口来控制所有窗口。

如果我们说的是 10 台机器,这将起作用。如果我们谈论 100 台机器,就会有很多窗口。

ClusterSSH 的美妙之处在于,如果一台机器与其他机器 100% 不一样,您只需单击窗口,然后在返回向所有机器发送击键之前只将击键发送到该机器。