![自动SSH提示输入](https://linux22.com/image/199751/%E8%87%AA%E5%8A%A8SSH%E6%8F%90%E7%A4%BA%E8%BE%93%E5%85%A5.png)
我正在尝试将一组 RSA 密钥复制到特定用户的多个服务器。每当我发出ssh-copy-id
命令时,它都会要求我输入“yes”进行确认,然后要求我输入密码。我想避免磨损我的手臂和手指,因此,我决定为此任务创建一个脚本,如下所示:
#!/bin/bash
runuser -u $RMTUSER -- ssh-copy-id [email protected]
runuser -u $RMTUSER -- ssh-copy-id [email protected]
(...)
runuser -u $RMTUSER -- ssh-copy-id [email protected]
runuser -u $RMTUSER -- ssh-copy-id [email protected]
我似乎找不到自动执行该任务的好方法。似乎没什么作用。如何自动输入“是”和密码?
我意识到我最初的问题相当乏味。对此我感到抱歉...但它仍然在上面。
我已将脚本改进为与马库斯提议的类似的内容。我陷入了“for”循环,想知道如何为不同的服务器阵列传递该密码。
我的主机集都是静态的,而且还有更多。
#!/bin/bash
LOCUSER="$1" # USER FOR REMOTE ACCESS
RMTUSER="$2" # REMOTE USER
PASSWD="$3" # SITE PASSWORD
SITE="$4" # SERV SITE
function uras() {
for IP in "$@"; do
runuser -u "${LOCUSER}" -- sshpass "-p${PASSWD}" ssh-copy-id "${RMTUSER}@${IP}"
[ "$?" -eq "0" ] && echo "OK - $IP" || echo "FAIL! - $IP"
done
}
case $SITE in
"sa")
ARRAY_A=( $(cat ./serv_a.txt) )
uras "${ARRAY_A[@]}"
;;
"sb")
ARRAY_B=( $(cat ./serv_b.txt) )
uras "${ARRAY_B[@]}"
;;
"sc")
ARRAY_C=( $(cat ./serv_c.txt) )
uras "${ARRAY_C[@]}"
;;
*)
echo "INVALID SITE"
;;
esac
尽管如此,该脚本对于每个主机都会失败。
# ./auto_ssh_copy.sh [user] root [pass] [site]
/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/var/lib/zabbix/.ssh/id_rsa.pub"
FAIL! - 172.24.168.48
/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/var/lib/zabbix/.ssh/id_rsa.pub"
FAIL! - 172.24.168.49
/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/var/lib/zabbix/.ssh/id_rsa.pub"
FAIL! - 172.24.168.50
(...)
我也尝试使用“-f”,但结果是相同的。
我同意使用像 Ansible 这样强大的工具可能是完成这项工作的更好工具,但不幸的是它目前在我的工作集中不可用。这是我到目前为止想到的。
最后我成功复制了所有密钥。上面的脚本缺少 option -o StrictHostKeyChecking=no
,因此sshpass
返回退出代码 6。生成的命令是这样的:
runuser -u ${LOCUSER} -- sshpass -v -p${PASSWD} ssh-copy-id -o StrictHostKeyChecking=no ${RMTUSER}@${IP}
马库斯·昂瑟帮了很多忙。谢谢大家。
答案1
您可以使用选项禁用yes
检查。-f
ssh-copy-id
密码大概应该是不是成为该脚本的一部分,假设该脚本最终位于其他人可能可读的位置。相反,我建议编写这样的脚本:
#!/bin/sh
# Usage: myscript user password
RMTUSER=$1
PASSWORD=$2
# just an example, but to highlight you can use brace expansions.
hosts=("172.24.168.47" "172.24.168.48" 172.24.168.{200..213})
for host in ${hosts[@]}; do
runuser -u "${RMTUSER}" -- sshpass "-p${PASSWORD}" ssh-copy-id -f "root@${host}"
done
答案2
您可以添加-f
到力量复制或
StrictHostKeyChecking no
在文件内设置~/.ssh/config
,以便 ssh-copy-id 不会检查密钥是否已存在于服务器上。
然而,这些选项意味着如果您不小心,您可能会多次安装相同的密钥。
答案3
对此类问题的诚实回答是“停止构建带有各种有趣失败方式的定制工具,使用由其他人维护良好的强大工具”。
进入安西布尔。您会发现,维护您管理的主机及其“逻辑组”(ansible 称为“库存”)的列表以及这些主机需要发生的事情的列表(ansible 称为“playbook”)有助于很多更好、更一致,并且管理时间更少。
就您而言,您需要一个像这样的库存文件(我们称之为~/servers.ini
):
[rootservers]
172.24.168.47
172.24.168.48
172.24.168.[200:213]
[rootservers:vars]
ansible_password=f00bar
您还可以通过其他方式提供密码。
和一个剧本(比如~/playbook.yaml
):
hosts: rootservers
tasks:
- name: Set authorized key took from file
authorized_key:
user: root
state: present
key: "{{ lookup('file', '/home/mark/.ssh/id_rsa.pub') }}"
就是这样。您现在可以运行
ansible-playbook -i ~/servers.ini ~/playbook.yaml
进行ansible检查,对于rootservers
组中的每个主机,mark
rsa_id是否已经在authorized_keys
服务器上的文件中,如果没有,则将其添加到那里。
但你通常会想做更多;就像,完成之后,配置 SSHd 以禁止 root 密码登录(总是一个好主意,恕我直言),安装或更新一些软件包(“启用此第三方存储库并安装版本 10.1 中的 CUDA 驱动程序”),设置安装一些监控软件,清理一些用户目录,复制一些文件等。
对于所有这些任务,ansible 要么内置了类似authorized_key
(or apt
or copy
or ...) 的简单命令,要么有人编写了角色(就像“设置一个 Postfix 邮件服务器”)对于你可以使用的 ansible。
就我个人而言,我绝不在任何服务器上手动安装任何软件包,添加任何本地用户或更改任何配置,因为我不记得明天早上是否这样做了。优点是我不仅可以得到一份关于我对所述服务器所做的事情的书面声明,而且还可以设置一个新服务器来替换或补充该服务器,只需在正确组中的库存中添加一行即可。
所以,我的工作流程通常是:
- 在物理机上安装Linux/启动虚拟机;通常,甚至可以通过添加授权密钥来完成,只需要安装 SSH 服务器
- 如有必要,添加 root 的授权密钥
- 将该机器添加到适当组下的库存中
- 运行包含我想要在该机器上发生的事情的剧本
``你实际上应该不是将您的密码存储在库存中,使用拱顶相反,但为了说明,这可能就足够了。