批量自动化配置SSH免登陆

1 主要内容

2 SSH密码生成

首先需要理解密钥产生的机制。SSH是基于密钥的,所以系统提供了SSH的命令 ssh-keygen用于生成密钥。
我们可以直接使用命令指定RSA生成一对密钥。

但是在自动过程中,为了避免交互,可以使用以下命令:
ssh-keygen -f id_rsa -t rsa -N ''
其中

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
注:

4 SSH登陆输入密码

输入密码有两种方法:sshpassexpect。这两种工具只需要在本机安装好即可,目标机器无需安装。

4.1 sshpass

sshpass 命令可以用于 ssh 和 scp 命令,如:
sshpass -p 'password' ssh -o StrictHostKeyChecking=no user@host

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 自动化脚本(基于 sshpass)

5.1 建立本地密码

此脚本在本机执行,只需在本地1次:
ssh-keygen -f id_rsa -t rsa -N ''

5.2 安装 sshpass

apt install -y sshpass

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 整体架构

整体框架以下所示。

ControlServeraccountsCloudServersroot@host1hao@host2jack@host3lucy@host4bruce@host5host1host2host3host4host5Managerinitializemanagemanagemanagemanagemanage

解释

服务器上存储了所有通过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

参考资料

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

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"

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