SSH第一次连接远程主机

公钥交换原理

1.客户端发起链接请求
2.服务端返回自己的公钥,以及一个会话ID(这一步客户端得到服务端公钥)
3.客户端生成密钥对
4.客户端用自己的公钥异或会话ID,计算出一个值Res,并用服务端的公钥加密
5.客户端发送加密后的值到服务端,服务端用私钥解密,得到Res
6.服务端用解密后的值Res异或会话ID,计算出客户端的公钥(这一步服务端得到客户端公钥)
最终:双方各自持有三个秘钥,分别为自己的一对公、私钥,以及对方的公钥,之后的所有通讯都会被加密

ssh 批量免密登陆_服务端

 

 

首次登录提示信息

如果是第一次向远程主机发起SSH连接,系统会提示不能确认主机真实性,但知道它通过ECDSA算法加密的公钥指纹,是否继续连接。

ssh 批量免密登陆_客户端_02

 

 

在/etc/ssh目录下有几种密钥,这些文件在安装openssh-server后生成,SSH服务就是使用这些密钥与客户端进行加密通信。

ssh 批量免密登陆_字符串_03

 

 

可在服务端查看sha256及md5生成的指纹,与第一次ssh登陆返回的对比是否一致。

[root@myhost4 ~]# ssh-keygen -E sha256 -lf /etc/ssh/ssh_host_ecdsa_key.pub
256 SHA256:ztpC4229m/nFRSOh6xDrqr+31xWrhXshHe652aGDmW8 no comment (ECDSA)
[root@myhost4
~]# ssh-keygen -E md5 -lf /etc/ssh/ssh_host_ecdsa_key.pub 256 MD5:60:74:30:1b:da:e1:0b:a7:8b:da:c9:0a:a0:30:b4:af no comment (ECDSA)

 

禁止首次连接询问

若确认远程主机可信。要禁止第一次ssh提示确认,可使用以下两种方法:

修改ssh客户端配置文件:/etc/ssh/ssh_config

sed -i.bak '/StrictHostKeyChecking/s/.*/StrictHostKeyChecking no/' /etc/ssh/ssh_config

 

ssh时使用-o选项

  -o StrictHostKeyChecking=no

 

 

SSH登录方式

基于用户名密码

1. 客户端发起ssh请求,服务器把自己的公钥发送给客户端
2. 客户端根据服务器发来的公钥对密码进行加密
3. 加密后的信息回传给服务器,服务器用自己的私钥解密,如果密码正确,则用户登录成功

ssh 批量免密登陆_字符串_04

 

 

 

基于公匙

1. 首先在客户端生成一对密钥(ssh-keygen)
2. 将客户端的公钥ssh-copy-id 拷贝到服务端
3. 客户端发送一个连接请求
4. 服务端得到客户端的请求后,会到authorized_keys中查找,如果有响应的IP和用户,就会随机生成一个字符串
5. 服务端将此字符串使用客户端的公钥进行加密,然后发送给客户端
6. 得到服务端发来的消息后,客户端使用私钥进行解密,然后将解密后的字符串发送给服务端
7. 服务端接受到客户端发来的字符串后,跟之前的字符串进行对比,如果一致,就允许免密码登录

ssh 批量免密登陆_ssh_05

 

基于密钥的登录方式实现

在客户端后成密钥对:ssh-keygen  [-t rsa]  [-P 'password']  [-f “~/.ssh/id_rsa"]

使用默认方式,回车后会在当前用户家目录生成.ssh文件夹

ssh-keygen 

ssh 批量免密登陆_服务器_06

 

 

 

 

将公钥文件传输至远程服务器对应用户的家目录
ssh-copy-id   [-i [identity_file]]   [user@]host

ssh-copy-id 10.0.0.4

ssh 批量免密登陆_服务器_07

 

 

私钥加密

ssh-keygen –p

 

批量免密登陆

expect

  expect 是由Don Libes基于 Tcl(Tool Command Language)语言开发的,主要应用于自动化交互式操作的场景,借助 expect 处理交互的命令,可以将交互过程如:ssh登录,ftp登录等写在一个脚本上,使之自动化完成。尤其适用于需要对多台服务器执行相同操作的环境中,可以大大提高系统管理人员的工作效率。

  默认expect是交互地执行的。

  首行shebang机制为    #!/usr/bin/expect

expect中相关命令

  spawn 启动新的进程
  expect 通常是用来等待一个进程的反馈,与send相反。expect可以接收一个字符串参数,也可以接收正则表达式参数
  send  接收一个字符串参数,并将该参数发送到进程
  interact 允许用户交互
  exp_continue 执行多个命令

expect语法:与标准输入输出进行交互

      单一分支模式语法: 

              expect “hello” {send “is hello\n"}           匹配到hello后,会输出“is hello”,并换行

        多分支模式语法: 

              expect "hello" {send "is hello\n"} "hehe" {send "is hehe\n"} "haha" {send "is haha\n"}        匹配hehe、hello、haha中任意一个时,执行相应输出。等同如下:   

    expect {
    "hello" { send "is hello\n"}
    "hehe" { send "is hehe\n"}
    "haha" { send "is haha\n"}
    }

spawn:与进程进行交互

  spawn后的send和expect命令都是和spawn打开的进程进行交互。

interact:用户交互

  expect如果只交互一次如拷贝文件,结尾就使用expect eof
  如果需要连续交互如登录远程主机执行各种命令结尾就需使用interact

示例

#!/usr/bin/expect
spawn ssh 10.0.0.79
    expect {
        "yes/no" { send "yes\n";exp_continue }
        "password" { send "mima\n" }
    }
interact   


#!/usr/bin/expect
spawn scp /etc/hosts 10.0.0.79:/tmp
expect {
  "yes/no" { send "yes\n";exp_continue }
  "password" { send "mima\n" }
}
expect eof

 

expect实现:shell脚本调用expect

 

#!/bin/bash
user=sshuser
passwd=sshuser
port=1022
IPLIST="10.0.0.3 10.0.0.4"

rpm -q expect &> /dev/null || yum -y install expect &> /dev/null

#生产环境中基本都禁用root登陆
#所有主机上新建登陆帐号,如sshuser,家目录/home/sshuser
#若需要生成其它用户的key,切换到该用户后执行
#su - sshuser

[ -e ~/.ssh/id_rsa ] && echo -e  '\033[1;31m ssh key exists\033[0m' || { ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa &>/dev/null && echo -e  '\033[1;32m ssh key create\033[0m'; }

for ip in $IPLIST;do
expect <<EOF
        #若使用非root,修改对应用户家目录
        #spawn ssh-copy-id -i /home/sshuser/.ssh/id_rsa.pub -p $port $user@$ip 
        spawn ssh-copy-id -i /root/.ssh/id_rsa.pub -p $port $user@$ip
        expect {
                "yes/no" { send "yes\n";exp_continue }
                "password" { send "$passwd\n" }
                }
        expect eof
EOF
echo "$ip is ok"
done