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上面分享自己的心得,若有问题希望各路大神多多海涵和指正!