#################以下所有的命令脚本都是在centos7系统上实现,centos6略有不同
客户端使用公钥连接服务器的步骤:
提起ssh我们就能想到的是远程连接,平时我们都是通过密码来登录linux主机,其实我们还是可以通过密钥来登录linux的,那么它的实现步骤是怎样的呢?
第一步:客户端通过ssh-keygen生成一对密钥,会自动存放在家目录的.ssh/authorized_keys文件下
第二步:客户端通过ssh-copy-id把公钥上传到服务器,会自动保存在目的用户家目录下的.ssh/
这样以后客户端再连接服务器时,就不用使用密码了。
上面的步骤有一个疑惑:客户端和服务器的用户要对应起来吗?不需要对应起来,比如客户端当前账户是zhanghe,而服务器上的账户是root,我们也可以把zhanghe的公钥通过ssh-copy-id放置到服务器上的root家目录下,这样客户端的zhanghe用户再登录服务器端的root就不用再输入密码了。
交互式登录服务器系统:
交互式登录服务器效率太低,不适合大批量分发,但是有些步骤非得交互不可,为了避免这种尴尬,可以使用expect程序代替我们进行交互,解放双手!正面我们就来介绍一下expect的使用方法.
expect的使用方法和解释(用户名和密码登录):
#!/bin/bash #author zhanghe spawn ssh [email protected] expect { "yes/no" { send "yes\r"; exp_continue } "password:" { send cba-123\r } } interact
注意:
第一行的解释器不再是/bin/bash,而不是/usr/bin/expect
spawn是“产生”的意思,就是产生一个会话,会话的就是通过root @192.168.80.7发起的。
expect {
} 这是固定的格式,注意expect整个脚本不能有空格,只能使用tab来缩进,不然会出问题!
"yes/no"是关键词,这个非常的重要,你还记得我们通过交互式连接远程主机是会提示你是否要继续连接,这个yes/no就是从那个结尾复制过来的,这样expect程序就可以定位到在什么地方帮助我们输入原本我们要输入的内容,那么要输入什么内容呢?当然是要输入yes,所以我们在“yes/no”后面加了一个中括号,括号里面内容就是发送yes\r(\r是回车的意思),注意,中括号两端都是有空格的,那么那个exp_continue是什么意思呢?就是为了防止万一没有让我们输入"yes/no"时我们来要继续连接。好了,那么下面的password也是关键词,后面就是发送的密码。最后一点是那个interact的意思是当连接成功之后就停留在服务器端先不要断开的意思。
注意:即使这样登录了之后,然后你退出来再次登录的时候,如果不调用此脚本片断还是要手动与之交互的,此脚本片断只不过是代替你完成了交互,是一次性的,用过一次之后下次再用时,还要再次调用!而密钥认证就不是这样了,密钥认证登录过一次之后,以后登录再也不需要交互了。
非交互式登录系统:(expect代替我们发送公钥与远程主机)
如果想通过密钥登录的话,我们就是先生成密钥,然后再把公钥发送给远程服务器,生成密钥时我们使用ssh-keygen命令,此命令可以交互,也可以不交互,但是通过ssh-copy-id时就必需得交互了,这时我们就得用到expect了。
[[email protected] ~]# vim 1.sh #!/bin/bash #author zhanghe SERVER_ADDR=192.168.80.7 SERVER_PAWD=cba-123 expect () { #在这里面定义了一个函数expect,作用是用来把已经生成好的公钥推送到服务器 /usr/bin/expect <<-EOF spawn ssh-copy-id $SERVER_ADDR expect { "yes/no" { send "yes\r"; exp_continue } "password:" { send "$SERVER_PAWD\r" } } expect eof EOF } #函数在此结束 test -f ~/.ssh/id_rsa #测试密钥是否存在?存在为0,不存在为1. if [ $? -ne 0 ];then #如果不存在,就创建 ssh-keygen -P "" -f ~/.ssh/id_rsa &>/dev/null expect #然后推送到服务器 echo "keygen alreadly send!" else expect #如果密钥文件存在,就直接推送 echo "keygen alreadley send2" fi
解释:
在脚本的开头我们定义了两个变量,一个变量是服务器的地址,另一个变量的服务器的密码
之后我们我们定义一个函数,这个函数其实就是调用了expect来帮助我们完成交互。
最后,我们通过一个id判断当前家目录有没有密钥文件,如果没有话,我们就创建,并且调用expect函数代替我们交互;如果有的话,就不用创建了,直接代替我们交互就可以了。
注意1:
ssh-keygen里面,-P“”的意思是空密码,-f是指定文件名,ssh-keygen不使用这两个选项时是交互的,使用了这两个选项就不用再交互了,也不用expect的帮忙,有的同学可能注意到了后面的文件是.ssh/id_rsa,为什么是这个路径呢?id_rsa是私钥,生成私钥会一块生成公钥的,所以我们在这里指定私钥就可以了。
注意2:
ssh-copy-id也是可以使用[email protected]的,上文当中没有写,默认就是当前用户了。
再加大一点难度,怎样批量给多台服务器推送公钥呢?在上面我们给一台服务器推送脚本会了,给多台服务器推送脚本也不难在上面的脚本里面再加一个for循环就可以了,下面我们就来实现一下。假设我们已经知道和服务器的IP列表和各个密码,然后再给这台服务器推送公钥,IP列表和密码在此:
[[email protected] tmp]# cat serverhost.txt
192.168.80.7 cba-123 #服务器的地址和密码都是用空格隔开的
192.168.80.8 abc-123
[[email protected] tmp]# vim send_key.sh
#!/bin/bash expect () { #同上,一开始就定义了一个expect的函数 /usr/bin/expect <<-EOF spawn ssh-copy-id [email protected]$ADDR expect { "yes/no" { send "yes\r"; exp_continue } "password:" { send $PASSWD\r } } expect eof EOF } #函数在此结束 SERVERHOST=/tmp/serverhost.txt for ADDR in `cut -d" " -f1 $SERVERHOST`;do #这一cut把所有的ip全都列出来了 PASSWD=$(grep $ADDR $SERVERHOST | cut -d" " -f2) test -f ~/.ssh/id_rsa if [ $? -ne 0 ];then ssh-keygen -P "" -f ~/.ssh/id_rsa &>/dev/null expect echo "key already send!" else expect echo "key already send!!" fi done
原文地址:https://www.cnblogs.com/yizhangheka/p/11038960.html