Shell脚本实现多台机器SSH互信免密登录

SSH服务密钥登录交互原理概述

🍀🏵️🍉🍇🍭
🍀标识定义
C---Client---客户端---发起远程连接的主机
S---Server---服务端---被远程连接的主机

🍀过程描述
🏵️
C  客户端使用ssh-keygen生成公钥和私钥
   语法: ssh-keygen -t 加密算法类型 -b 密码二进制位长度
   说明加密算法一般选择rsa加密, 密码位长可以选择1024,2048,4096, 一般选择2048
C  客户端对用户发起人机交互, 回车即可. 人机交互内容如下
   🍉密钥文件生成位置: 默认为~/.ssh/
   🍉对私钥文件设置密码<空表示不设密码>
   🍉确认密码
C  客户端使用ssh-copy-id命令将刚生成的公钥上传给服务端
   语法: ssh-copy-id 【-i $DFile】 $ServerUser@$ServerIP
   说明: 不加任何选项时, ssh-copy-id 命令通常默认使用位于 ~/.ssh/id_rsa.pub 的公钥
         -i选项用于指定私钥文件, 指定后会自动检测并发送与私钥成对的公钥文件
         如果不指定ServerUser, 则默认以登录客户端当前终端的用户名进行登录  
C  客户端对用户发起人机交互
   主机验证: 第一次连接到该SSH服务器的时候会有该步骤, 输入yes表示确认连接, 确认后客户端会获得服务端的公钥文件
   密码提示: 客户端要求用户输入SSH服务端的用户登录密码
S  服务端收到密码后, 与/etc/shadow中的密码进行匹配, 匹配成功后, 将客户端的公钥和对应的登录用户存到~/.ssh/authorized_keys中, 格式为: 
   加密算法类型 公钥内容 $ClientUser@$hostname
C  密码验证成功后, 此后每次使用ssh命令登录SSH服务端都不需要密码, 而是进行一个认证过程
   ssh $ServerUser@$ServerIP
   🍭认证过程: 
   step 1    客户端尝试连接到服务端
   step 2    服务端随机产生一个字符串并使用客户端的公钥对其加密,然后将其发送给客户端
   step 3    客户端使用自己的私钥对服务器发来的随机字符串进行解密, 然后使用服务器的公钥对其重新加密并发送给服务器
   step 4    服务端使用自己的私钥对客户端发来的随机字符串进行解密,然后将其与之前随机产生的字符串进行对比
   step 5    如果字符串匹配成功, 服务端则认为客户端是可信的, 并允许连接
🍀免密过程针对主机上的单个用户, 相同主机不同用户发送给服务器的authorized.keys不同

SSH免密登录脚本

功能:实现了能够互相通信的不同主机之间的SSH免密远程登录,,只要主机之间能互相通信,则可以在其中一台机器上面实现多主机之间的SSH互信(注:能够互相通信指能够互相ping通)

操作环境:Linux CentOS7.6

编程语言:Shell

重难点:expect的使用

代码:Linux网络服务整体代码的一部分,采用脚本文件引用和函数封装的思维方式编写,不喜请划走

功能脚本

总加载脚本 Function.sh
#!/bin/bash

. ./f_IP_check.sh
. ./f_Replace.sh
. ./f_CMD_check.sh
IP检查脚本 f_IP_check.sh
#!/bin/bash

function IP_check(){
local IP=$1
if [[ "$IP" =~ ^([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\.([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])){3}$ ]]; then
    return 0
else
	return 1
fi
}
字符串替换脚本 f_Replace.sh
#!/bin/bash

function Replace(){
while true; do
    local ing=$1
	local ed=$2
	local DFile=$3
	if [ ! -f $DFile ]; then
	    echo "您所输入的目标文件不存在!"
    else
	    break
	fi
done		
sed -i "s/$ing/$ed/g" $DFile
}
命令安装检查脚本    f_CMD_check.sh
#!/bin/bash

CMD_check(){
    local cmd=$1
    a_cmd=($cmd)
    echo -e "检测中......"
    for i in "${a_cmd[@]}"; do
    { rpm -qa | grep "$i";}&> /dev/null
    if [ $? -eq 0 ]; then
    	echo -e "$i命令已安装"
    else
    	echo "命令$i未安装, 即将进行安装..."
			yum clean all && yum makecache
    		if [ $? -ne 0 ]; then
    			echo "yum源配置错误, 请检查配置文件以及对应的yum仓库! "
    			continue
    		fi
    		yum -y install $i
    		if [ $? -eq 0 ]; then
    			echo "命令$i安装成功!"
    		else
    			echo "未找到相关软件包, 安装失败. "
    		fi
    fi
    done
}

SSH主机互信(互相免密)脚本    SSH_nopasswd.sh

#!/bin/bash

. ./Function.sh

#设置要进行SSH免密的机器
function SSH_nopasswd(){
local ip user_name user_passwd
local n=0
declare -a IP UserName Password
while true; do
    read -p "请输入第$((n+1))个要进行免密的主机信息(格式: <IP 用户名 用户密码>)(输入exit表示设置完成): " ip user_name user_passwd
    if [[ "$ip" =~ ^exit$ ]]; then
        echo "主机信息设置完成! "
        break
    else
        IP_check $ip
        result1="$?"
        ping -c 2 $ip &> /dev/null
        result2="$?"
        if [ "$result1" -eq 0 ] && [ "$result2" -eq 0 ]; then
            if [ -n "$user_name" ] && [ -n "$user_passwd" ]; then
                IP[$n]="$ip"
                UserName[$n]="$user_name"
                Password[$n]="$user_passwd"
                ((n++))
            else
                echo "用户信息空缺,请重新输入! "
                continue
            fi
        else
            echo "IP格式不正确或不可达,或者用户信息空缺, 请重新输入! "
        fi
    fi
done
	
#调用函数检查命令是否存在
CMD_check expect ssh

#分发脚本给到所有机器上
for ((k=0; k<${#IP[@]}; k++)); do
    /usr/bin/expect << EOF
    set timeout 3
    spawn bash -c "scp ./*.sh ${UserName[$k]}@${IP[$k]}:/tmp/"
    expect {	
        "continue connecting (yes/no)?" { send "yes\r"; exp_continue }
        "password:" { send "${Password[$k]}\r"; exp_continue }
        eof
    }
EOF
done

#进行远程连接,然后分别执行脚本
for ((m=0; m<${#IP[@]}; m++)); do
    /usr/bin/expect << EOF
        set timeout 3
        spawn ssh ${UserName[$m]}@${IP[$m]}
        expect {
            "continue connecting (yes/no)?" { send "yes\r"; exp_continue }
            "password:" { send "${Password[$m]}\r"; exp_continue }
        }	
           
        expect { 	
            "~]# " { 
                send "cd /tmp/ && . ./Function.sh && CMD_check expect ssh && ssh-keygen -t rsa -b 2048\r"
            }
            "~]$ " { 
                send "cd /tmp/ && . ./Function.sh && CMD_check expect ssh && ssh-keygen -t rsa -b 2048\r"
            }
        }		
        expect {  
            "]# " { 
                send "exit\r"
            }  
            "]$ " { 
                send "exit\r"
            }
        } 
        expect eof
EOF

    /usr/bin/expect << EOF
    set timeout 3
    spawn ssh ${UserName[$m]}@${IP[$m]}
    expect {
        "continue connecting (yes/no)?" { send "yes\r"; exp_continue }
        "password:" { send "${Password[$m]}\r"; exp_continue }
    }
    expect { 	
        "~]# " { 
            send "ssh-keygen -t rsa -b 2048\r"
        }
        "~]$ " { 
            send "ssh-keygen -t rsa -b 2048\r"
        }
    }	
    expect {	
        ".ssh/id_rsa):" { 
            send "\r"
            exp_continue
        }
        "Overwrite (y/n)?" { 
            send "y\n"
            exp_continue
        }
        "(empty for no passphrase):" {	
            send "\r"
            exp_continue
        }
        "again:"  { 
            send "\r"
            exp_continue
        }
    }
    expect {  
        "]# " { 
			send "exit\r"
        }  
        "]$ " { 
            send "exit\r"
        }  
    }
    expect eof
EOF
    for ((i=0; i<${#IP[@]}; i++)); do	
        /usr/bin/expect << EOF
            set timeout 3
            spawn ssh ${UserName[$m]}@${IP[$m]}
            expect {	
                "continue connecting (yes/no)?" {
                    send "yes\r"
                    exp_continue
                }
                "password:" {
                    send "${Password[$i]}\r"
                    exp_continue
                }
            }
            send "ssh-copy-id -i /root/.ssh/id_rsa.pub ${UserName[$i]}@${IP[$i]}\r"
            expect {	
                "continue connecting (yes/no)?" {
                    send "yes\r"
                    exp_continue
                }
                "password:" {    
                    send "${Password[$i]}\r"
                    exp_continue
                }
                "#" {
                    send "exit\r"
                    exp_continue
                }
                eof
            }
EOF
        done
    done
}

#脚本主程序
SSH_nopasswd

写在最后:

本人第一次在CSDN上面分享自己的心得,若有问题希望各路大神多多海涵和指正! 

  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值