全自动化SSH免密脚本建立过程详解 郝伟 2021/06/23 [TOC]
1. 1 功能说明
1.1. 1.1 功能简介
本脚本主要实现以下两个过程:
- 自动化创建免密过程,给定IP和登陆密码建立自动化免密过程;
- 自动化删除免密过程,从指定IP上删除已经配置好的内容。
1.2. 1.2 主要难点
这两个内容在自动化的过程中会有很多交互内容,造成无法自动化的主要原因,所以核心的要求是如何取消这些交互过程。
2. 2 SSH密码生成
2.1. 2.1 密钥无交互生成
首先需要理解密钥产生的机制。SSH是基于密钥的,所以系统提供了SSH的命令 ssh-keygen用于生成密钥。 我们可以直接使用命令指定RSA生成一对密钥。
但是在自动过程中,为了避免交互,可以使用以下命令:
ssh-keygen -f id_rsa -t rsa -N ""
其中
-f
是输入文件名,会生成id_rsa
和id_rsa.pub
两个文件分别表示密钥和公钥;-t
是密钥内容,文件名称为 RSA;-N
解密的密码,默认为空。
2.2. 2.2 注意事项
在执行此代码后,会在控制台输出以下内容:
Your identification has been saved in id_rsa.
Your public key has been saved in id_rsa.pub.
The key fingerprint is:
SHA256:G4u9JtXE2NhFEF6JXGfcgeUkxwea9UnJ3O0gKO7+nHk root@instance-j33hvw56
The key's randomart image is:
+---[RSA 2048]----+
| .oB++@O=|
| ..+.+BO**|
| . B..o. =o|
| + = .|
| .So |
| oo+. |
| .o+ |
| . oo oE |
| o..=. |
+----[SHA256]-----+
如果不希望输出,可以生定向输出至 /dev/null
:
ssh-keygen -f id_rsa -t rsa -N "" > /dev/null
另外还有一个问题就是如果文件已经存在,则会出现:
root@instance-j33hvw56:~# ssh-keygen -f id_rsa -t rsa -N ""
Generating public/private rsa key pair.
id_rsa already exists.
Overwrite (y/n)?
所以,为了避免这个问题,可以加上删除命令,如:
rm id_rsa*; ssh-keygen -f id_rsa -t rsa -N "" > /dev/null
3. 3 SSH登陆确认
使用SSH登陆时第一次登陆会出现以下内容,进行确认是否登陆,如下所示:
root@server00:~/hao# ssh user@host
The authenticity of host '106.12.31.101 (106.12.31.101)' can't be established.
ECDSA key fingerprint is SHA256:SRQLrDAimMXE8tRTMyELTgOL9r+tvcJX4ZmwOQZ2d+Q.
Are you sure you want to continue connecting (yes/no)?
以上的内容是从安全角度让用户进行确认,所以不显示此内容,可以通过配置实现:
ssh -o StrictHostKeyChecking=no user@host
注:
- 一定登陆以后,登陆的机器的SHA256会保存在本机的
~/.ssh/known_hosts
中。 - 以后在登陆时使用以下命令即可:
ssh -i ssum_key.pem user@host
; - 若要避免每次使用
-i
参数,可在~/.ssh/config
添加IdentityFile ~/.ssh/ssum_key.pem
; - 若密钥路径为
~/.ssh/id_rsa
,也可省去-i
参数。
4. 4 SSH登陆输入密码
输入密码有两种方法:sshpass
或 expect
。这两种工具只需要在本机安装好即可,目标机器无需安装。
4.1. 4.1 sshpass
sshpass 命令可以用于 ssh 和 scp 命令,如:
sshpass -p 'password' ssh -o StrictHostKeyChecking=no user@host
4.2. 4.2 expect
安装时也可以免交互,只需要在install后加上 -y
即可,如下所示:
apt install -y expect
示例脚本
#!/usr/bin/expect
set timeout 30
spawn ssh -l root 106.12.31.101
expect "password*"
send "\password\r"
interact
5. 5 自动化脚本(基于 sshpass)
5.1. 5.1 建立本地密码
此脚本在本机执行,只需在本地1次:
ssh-keygen -f id_rsa -t rsa -N ""
5.2. 5.2 安装 sshpass
apt install -y sshpass
5.3. 5.3 上传公钥并追加
使用以下基于 sshpass
的脚本可以实现自动化上传公钥的脚本。
#!/usr/bin/expect
# Step 1: upload mykey.pub to server
sshpass -p 'password' scp mykey.pub user@host:
# Step 2: Add mykey.pub to authorized_keys
sshpass -p 'password' ssh user@host "cat mykey.pub >> ~/.ssh/authorized_keys"
6. 6 整体架构
整体框架以下所示。
@startuml
left to right direction
actor Manager as g
artifact ControlServer as cs {
folder accounts {
file "root@host1" as f1
file "hao@host2" as f2
file "jack@host3" as f3
file "lucy@host4" as f4
file "bruce@host5" as f5
}
}
package CloudServers {
rectangle "host1" as UC1
rectangle "host2" as UC2
rectangle "host3" as UC3
rectangle "host4" as UC4
rectangle "host5" as UC5
}
g --> cs:initialize
f1 --> UC1: manage
f2 --> UC2: manage
f3 --> UC3: manage
f4 --> UC4: manage
f5 --> UC5: manage
@enduml
解释
- Manager:系统管理员
- ControlServer:用于管理所有机器的云服务器
- CouldServers: 待管理的云主机
- initialize: 初始化操作,在机器上安装
sshpass
服务器上存储了所有通过SSH登陆的文件,每个文件中的内容是密码,文件名为 登陆名@HostIP
,如 root@106.12.31.101
,内容是 $erver2019
。
这样,只需使用 sshpass -f $1 ssh $1 "ls"
即可执行相关命令。
批量执行任务
#!/bin/bash
cmd="cd /opt; ls"
for file in $1/*;
do
name=$(basename $file)
echo "------------------------------------------------------------------"
echo "sshpass -f $name ssh $name \"$cmd\""
sshpass -f $file ssh -o StrictHostKeyChecking=no $name "$cmd"
echo ""
done
执行结果
root@server00:~# sh sh1.sh task1/
------------------------------------------------------------------
sshpass -f root@106.12.31.101 ssh root@106.12.31.101 "cd /opt; ls"
avalokita
bcm-agent
containerd
hosteye
java
tomcat8
------------------------------------------------------------------
sshpass -f root@121.199.10.158 ssh root@121.199.10.158 "cd /opt; ls"
apache-tomcat-8.5.57
jdk-11.0.8
jdk1.8.0_261
7. 参考资料
7.1. 1 在bash循环执行命令示例
# 示例1:循环输出编号
for a in {1..10}; do echo "ID:$a"; done
# 示例2:使用for循环,注:格式上必需为两层括号
for((i=1;i<=10;i+=2)); do echo "Welcome $i times"; done
# 示例3:文件循环遍历
for i in /etc/*.conf; do cp $i /backup; done
7.2. 2 测试内容
以下内容测试功能
# add public key
sshpass -p 'password' scp mykey.pub user@host:; sshpass -p 'password' ssh user@host "cat mykey.pub >> ~/.ssh/authorized_keys"
# remove public key
ssh -i mykey user@host "cat ~/.ssh/authorized_keys | sed '/root@server00/d' >> v1.txt; rm -f ~/.ssh/authorized_keys; mv v1.txt ~/.ssh/authorized_keys"
编写成脚本
# password pubkey user ip
#!/bin/bash
sshpass -p '$1' scp $2 $user@$ip:; sshpass -p '$1' ssh $user@$ip "cat $pk >> ~/.ssh/authorized_keys"
# remove public key
V1: ssh -i mykey user@host "cat ~/.ssh/authorized_keys | sed '/root@server00/d' >> v1.txt; rm -f ~/.ssh/authorized_keys; mv v1.txt ~/.ssh/authorized_keys"
V2: ssh -i mykey user@host "cat ~/.ssh/authorized_keys | sed -i '/root@server00/d' ~/.ssh/authorized_keys"
7.3. 6.3 其他材料
1. Make data: for a in {1..10}; do echo "ID:$a" >> v0.txt; done; cat v0.txt
2. cat v0.txt | sed '/1/d' >> v1.txt; rm -f v0.txt; mv v1.txt v0.txt
sshpass -f $1 ssh $1 "ls"
# 使用
# 根据ip列表指定的程序类型,将程序上传至 ip:/etc/fsy 目录下
cat $2 | while read line #读取iplist.txt中的每一行
do
if [ ${line:0:2} == 'gw' ];then # 根据是否是gw开头,判断是否为网关
scp -r $1/gateway root@${line:3:20}:$tarpath # 上传网关程序
elif [ ${line:0:2} == 'tm' ];then # 根据是否是tm开头,判断是否为远控
scp -r $1/terminal root@${line:3:20}:$tarpath # 上传远控程序程序
else # 否则为路由程序,上传路由程序
scp -r $1/rcontrol root@${line:0:2}:$tarpath
fi
done