expect非交互式批量分发sshkey秘钥
expect非交互式批量分发sshkey秘钥
1.什么是Expect?
Expect是一个用来实现自动交互功能的软件套件,基于Tcl的免费脚本编程工具语言
用于实现自动对交互式任务程序进行通信,无需人手工干预,
例如ssh,ftp等这些程序正常需要手工进行交互,使用expect就可以模拟手工交互的过程,实现自动和远端程序的交互,从而达到自动化运维的目的
虽然使用c,perl等语言一样可以实现交互功能,但是expect更加简单,专业,出色,而且支持linux,unix,windows平台,是为系统管理和软件测试方面的自动交互需求而产生的
2.Expect程序的工作流程
- spawn启动进程 ssh
- expect期待关键字 要密码
- send向程序发送字符 提供密码
- 退出结束 退出结束
3.使用yum安装安装Expect软件
yum install expect -y
手工连接测试
[nice@zstest1 ~]$ ssh -p22 root@192.168.1.72 /sbin/ifconfig eth0
root@192.168.1.72's password:
eth0 Link encap:Ethernet HWaddr 00:0C:29:A8:09:67
inet addr:192.168.1.72 Bcast:192.168.1.255 Mask:255.255.255.0
inet6 addr: fe80::20c:29ff:fea8:967/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:10056911 errors:0 dropped:0 overruns:0 frame:0
TX packets:19760 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:666475843 (635.6 MiB) TX bytes:2661121 (2.5 MiB)
expect脚本测试
[nice@zstest1 ~]$ vim expect1.exp
-----------------------------------------------
#!/usr/bin/expect
spawn ssh -p22 root@192.168.1.72 /sbin/ifconfig eth0
set timeout 60
expect "*password"
send "123456\n"
expect eof
exit
-----------------------------------------------
[nice@zstest1 ~]$ chmod 700 expect1.exp
[nice@zstest1 ~]$ ll expect1.exp
-rwx------ 1 nice nice 137 12月 12 18:00 expect1.exp
[nice@zstest1 ~]$ ./expect1.exp
spawn ssh -p22 root@192.168.1.72 /sbin/ifconfig eth0
root@192.168.1.72's password:
eth0 Link encap:Ethernet HWaddr 00:0C:29:A8:09:67
inet addr:192.168.1.72 Bcast:192.168.1.255 Mask:255.255.255.0
inet6 addr: fe80::20c:29ff:fea8:967/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:10057781 errors:0 dropped:0 overruns:0 frame:0
TX packets:19801 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:666544863 (635.6 MiB) TX bytes:2668445 (2.5 MiB)
或者用expect直接执行
[nice@zstest1 ~]$ expect expect1.exp
spawn ssh -p22 root@192.168.1.72 /sbin/ifconfig eth0
root@192.168.1.72's password:
eth0 Link encap:Ethernet HWaddr 00:0C:29:A8:09:67
inet addr:192.168.1.72 Bcast:192.168.1.255 Mask:255.255.255.0
inet6 addr: fe80::20c:29ff:fea8:967/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:10058392 errors:0 dropped:0 overruns:0 frame:0
TX packets:19832 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:666596473 (635.7 MiB) TX bytes:2673360 (2.5 MiB)
5.Expect语法
5.1.spawn
用于启动一个进程,没有就无法执行
spawn ssh root@192.168.1.72
在spawn后面直接加上要启动的进程命令等信息
- -open 启动文件进程
- -ignore 忽略某些信号
5.2.expect
用于等候一个匹配的内容,一旦匹配就执行expect后面的动作
使用方法:
expect 表达式 动作 表达式 动作
参数:
- -re 表示使用正则表达式的方式匹配
例如:
spawn ssh root@192.168.1.72
expect "password:"
send "123456\r" "\r"表示回车
或者,匹配动作放到下一行,动作需要加大括号"{}"
spawn ssh root@192.168.1.72
expect "password:" {send "123456\r" }
多次匹配关键字并给出不同的动作
spawn ssh root@192.168.1.72
expect {
"yes/no" { exp_send "yes\r"; exp_continue }
"password:" { exp_send "123456\r" }
}
5.3.send和exp_send
send的使用参数
- -i 制定spawn_id,用来向不同spawn_id的进程发送命令,用于进行多程序控制
- -s slowly,控制发送的速度,需要与变量send_slow相关联
exp_send可以发送一些特殊符号,例如
- \r 回车
- \n 换行
- \t 制表符
5.4.exp_continue
一般用在动作中,使用条件比较严格
如下脚本示例:
[nice@zstest1 ~]$ cat expect2.exp
#!/usr/bin/expect
spawn ssh -p22 root@192.168.1.72 /sbin/ifconfig eth0
set timeout 60
expect {
-timeout 10
"yes/no" { exp_send "yes\r";exp_continue }
"*password:" { exp_send "123456\r" }
timeout { puts "expect was timeout by oldboy.";return }
}
expect eof
exit
[nice@zstest1 ~]$ > ~/.ssh/known_hosts
[nice@zstest1 ~]$ expect expect2.exp
spawn ssh -p22 root@192.168.1.72 /sbin/ifconfig eth0
The authenticity of host '192.168.1.72 (192.168.1.72)' can't be established.
RSA key fingerprint is a3:35:af:8c:26:1a:f0:b0:9f:0a:5f:7c:c0:6c:92:06.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.1.72' (RSA) to the list of known hosts.
root@192.168.1.72's password:
eth0 Link encap:Ethernet HWaddr 00:0C:29:A8:09:67
inet addr:192.168.1.72 Bcast:192.168.1.255 Mask:255.255.255.0
inet6 addr: fe80::20c:29ff:fea8:967/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:10244521 errors:0 dropped:0 overruns:0 frame:0
TX packets:20149 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:678855345 (647.4 MiB) TX bytes:2702841 (2.5 MiB)
[nice@zstest1 ~]$
[nice@zstest1 ~]$
[nice@zstest1 ~]$ cat ~/.ssh/known_hosts
192.168.1.72 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAtJ4gTJmW3g/9fqovdImKk87yH+BQKZNihOkCcJFUhHSVWL6da6Cr9yI4CwxbHc6p2Sf1b+l3jcJkVjFJfheNc/nf8OyQZgdCHix0eHE1656XGsRUNRP1kUwiL/Fuv7Adlt1Eto43dqH6yfjW3KWS+mTOWTBzSHbXMUj5dKCEe3femZ5DeVbCJrOIiiTjpwrsIDuoC+BoLwcJeMqj/60YSwb3CgYgCqgqW+dpo/lqwu8kA6SesYC45DJ8+VwWg80MqkBRmPjg2Z44AEIQNcXnOPUibGtoAdB6+P5iTcMGJx9v30Es8OwNMt38rDrwR8T5jjX3EczEFoLxXv/arTp5fQ==
5.5.send_user
把后面的参数输出到标准输出中去,就是向屏幕中打印字符,相当于shell中的printf,echo等,默认的send,exp_send命令都是将参数输出到程序中去,例如:
send_user "Please imput passwd:"
以上语句就尅在标准输出中打印"Please imput passwd:"字符了
[nice@zstest1 ~]$ cat fenfa_sshkey.exp
#!/usr/bin/expect
if { $argc !=2 } {
send_user "USAGE: expect fenfa_sshkey.exp file host\n"
exit
}
# define var
set file [lindex $argv 0]
set host [lindex $argv 1]
set password "123456"
#spawn scp /etc/hosts root@10.0.0.8:/etc/hosts
#spawn scp -P52113 $FILE oldboy@$HOST:$DIR
spawn ssh-copy-id -i $file "-p 22 nice@$host"
expect {
"yes/no" {send "yes\r";exp_continue}
"*password" {send "$password\r"}
}
expect eof
exit -onexit {
send_user "zhaoshuai say good bye to you!\n"
}
[nice@zstest1 ~]$
[nice@zstest1 ~]$ ./fenfa_sshkey-zs.exp
USAGE: expect fenfa_sshkey.exp file host
5.6.exit
退出脚本,可以利用该命令对脚本做一些扫尾工作。例如
exit -onexit {
exec rm $tmpfile
send_user "Good bye\n"
}
6.Expect变量
set 变量名 变量值 # 设置变量
puts $变量名 # 调用变量
# define var
set file [lindex $argv 0] # 接收命令行的参数
set host [lindex $argv 1]
set password "123456"
7.Expect关键字
expect中的特殊关键字用于匹配过程,代表某些特殊含义或状态,一般用于expect族命令中而不能在外面单独使用,可以理解为事件,使用方法
expect eof { }
7.1.eof
end-of-file 关键字用于匹配结束符,例如文件结束,ftp传输停止等情况,后面接动作来做进一步控制,例如
[nice@zstest1 ~]$ cat expect3.exp
#!/usr/bin/expect
spawn ftp nice@ftp.coinnice.cn
expect {
"password" { exp_send "who am I" }
eof { ftp connect close }
}
interact { }
[nice@zstest1 ~]$
7.2.timeout
是一个全局性的使劲控制开关,可以通过为这个变量赋值来规定整个expect操作得时间,
注意,这个变量时全局的,他不会纠缠于某一条命令,即使命令没有任何错误,到时见仍然会激活这个变量,但是时间到大吼除了激活一个开关之外不会做其他的事情
timeout变量中设置为0表示立即超时,设为-1则表示永不超时
用法如下:
set timeout 60
spawn ssh -p22 root@192.168.1.72 /sbin/ifconfig eth0
expect "yes/no" { exp_send "yes\r" }
expect "password:" { exp_send "123456\r" }
timeout { puts "expect was timeout";return }
另一种expect格式
在expect命令中间加上横杠“-”,用于设置timeout
spawn ssh -p22 root@192.168.1.72 /sbin/ifconfig eth0
set timeout 60
expect {
-timeout 60
-re "yes/no" { exp_send "yes\r" }
-re "password:" { exp_send "123456\r" }
timeout { puts "expect was timeout";return }
}
8.生产实例
实例1:
使用expect批量分发/etc/hosts文件
vim fenfa_file.exp
----------------------------------------------------------------
#!/usr/bin/expect
if { $argc !=3 } { # 判断脚本后面跟的参数数量,部委2则提示以下信息
send_user "USAGE: expect fenfa_file.exp file host dir\n"
exit
}
# define var
set file [lindex $argv 0] # 定义变量file
set host [lindex $argv 1] # 定义变量host
set dir [lindex $argv 2] # 定义变量dir
set password "123456" # 定义变量password
#spawn scp /etc/hosts root@10.0.0.8:/etc/hosts
#spawn scp -P52113 $FILE oldboy@$HOST:$DIR
spawn ssh-copy-id -i $file "-p 22 nice@$host"
expect {
-timeout 5
"yes/no" {send "yes\r";exp_continue}
"*password" {send "$password\r"}
timeout {puts "expect connect timeout";return}
}
expect eof
exit -onexit {
send_user "Good Bye!\n"
}
# script usage
# expect oldboy-6.exp file host dir
# example:
# expect oldboy-6.exp /etc/hosts 10.0.0.11 /etc/hosts
# expect oldboy-6.exp /etc/hosts 10.0.0.12 /etc/hosts
----------------------------------------------------------------
分发脚本:一次分发多个IP
vim fenfa_hosts.sh
--------------------------------------------------------------------
#!/bin/sh
. /etc/init.d/functions
for ip in `cat ip.list`
do
expect fenfa_file.exp /etc/hosts $ip /etc/hosts>/dev/null 2>&1
if [ $? -eq 0 ];then
action "$ip" /bin/true
else
action "$ip" /bin/false
fi
done
--------------------------------------------------------------------
vim ip.list
--------------------------------------------------------------------
10.0.0.11
10.0.0.12
10.0.0.13
10.0.0.14
--------------------------------------------------------------------
fenfa_file.exp文件用于交互,fenfa_hosts.sh脚本用于分发文件,ip.list用于确定目标主机
如果想分发其他文件需要修改fenfa_hosts.sh脚本里面的文件和目录
实例2:
使用expect实现批量分发ssh秘钥文件(首次分发秘钥)
由于公钥文件和文件夹有固定的权限所以可以直接复制.ssh文件夹
将私钥移出~/.ssh文件夹
修改公钥的名字为sshd_config里面指定的
注意scp复制文件夹时需要使用-p参数保持原有属性
cat fenfa_file.exp
----------------------------------------------------------------------------
#!/usr/bin/expect
if { $argc !=3 } {
send_user "USAGE: expect fenfa_file.exp file host dir\n"
exit
}
# define var
set file [lindex $argv 0]
set host [lindex $argv 1]
set dir [lindex $argv 2]
set password "123456"
spawn scp -P22 -r -p $file root@$host:$dir
expect {
"yes/no" {send "yes\r";exp_continue}
"*password" {send "$password\r"}
}
expect eof
exit
-----------------------------------------------------------------------
vim fenfa_sshkey.sh
--------------------------------------------------------------
#!/bin/sh
. /etc/init.d/functions
for ip in `cat ip.list`
do
expect fenfa_file.exp /root/.ssh $ip /root/.ssh #>/dev/null 2>&1
if [ $? -eq 0 ];then
action "$ip" /bin/true
else
action "$ip" /bin/false
fi
done
-----------------------------------------------------------------
vim ip.list
----------------------------
192.168.1.72
192.168.1.73
192.168.1.74
192.168.1.75
----------------------------
实验测试
################################################################
[root@zstest1 ~]# ./fenfa_sshkey.sh
spawn scp -P22 -r -p /root/.ssh root@192.168.1.72:/root/.ssh
The authenticity of host '192.168.1.72 (192.168.1.72)' can't be established.
RSA key fingerprint is a3:35:af:8c:26:1a:f0:b0:9f:0a:5f:7c:c0:6c:92:06.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.1.72' (RSA) to the list of known hosts.
root@192.168.1.72's password:
known_hosts 100% 394 0.4KB/s 00:00
authorized_keys 100% 602 0.6KB/s 00:00
192.168.1.72 [确定]
spawn scp -P22 -r -p /root/.ssh root@192.168.1.73:/root/.ssh
The authenticity of host '192.168.1.73 (192.168.1.73)' can't be established.
RSA key fingerprint is 30:97:bc:a0:31:e6:24:50:68:08:6e:82:83:ce:0d:25.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.1.73' (RSA) to the list of known hosts.
root@192.168.1.73's password:
known_hosts 100% 788 0.8KB/s 00:00
authorized_keys 100% 602 0.6KB/s 00:00
192.168.1.73 [确定]
spawn scp -P22 -r -p /root/.ssh root@192.168.1.74:/root/.ssh
ssh: connect to host 192.168.1.74 port 22: No route to host
lost connection
expect: spawn id exp4 not open
while executing
"expect eof"
(file "fenfa_file.exp" line 16)
192.168.1.74 [失败]
spawn scp -P22 -r -p /root/.ssh root@192.168.1.75:/root/.ssh
ssh: connect to host 192.168.1.75 port 22: No route to host
lost connection
expect: spawn id exp4 not open
while executing
"expect eof"
(file "fenfa_file.exp" line 16)
192.168.1.75 [失败]
################### 分发前 ######################
[root@zstest2 ~]# rm -rf .ssh/
[root@zstest2 ~]# ll .ssh
ls: 无法访问.ssh: 没有那个文件或目录
###### 分发后 ######
[root@zstest2 ~]# ll .ssh
总用量 8
-rw-r--r-- 1 root root 602 3月 6 18:33 authorized_keys
-rw-r--r-- 1 root root 394 3月 6 19:30 known_hosts
################### 分发前 ######################
[root@1073-zstest3 ~]# rm -rf .ssh/
[root@1073-zstest3 ~]# ll .ssh
ls: 无法访问.ssh: 没有那个文件或目录
###### 分发后 ######
[root@1073-zstest3 ~]# ll .ssh
总用量 8
-rw-r--r-- 1 root root 602 3月 6 18:33 authorized_keys
-rw-r--r-- 1 root root 788 3月 6 19:30 known_hosts
##########################################################3
免密钥连接测试
[root@zstest1 ~]# ll
总用量 56
-rw-------. 1 root root 1061 3月 4 2016 anaconda-ks.cfg
-rwxr-xr-x 1 root root 369 3月 6 19:22 fenfa_file.exp
-rwxr-xr-x 1 root root 231 3月 6 19:18 fenfa_sshkey.sh
-rw-r--r-- 1 root root 602 3月 6 17:46 id_dsa.pub
-rw-r--r--. 1 root root 22717 3月 4 2016 install.log
-rw-r--r--. 1 root root 6082 3月 4 2016 install.log.syslog
-rw-r--r-- 1 root root 52 3月 6 19:14 ip.list
[root@zstest1 ~]# mv id_dsa .ssh/
[root@zstest1 ~]# ll .ssh/
总用量 12
-rw-r--r-- 1 root root 602 3月 6 18:33 authorized_keys
-rw------- 1 root root 668 3月 6 17:46 id_dsa
-rw-r--r-- 1 root root 788 3月 6 19:30 known_hosts
[root@zstest1 ~]# ssh -p22 root@192.168.1.72 free -m
total used free shared buffers cached
Mem: 1869 837 1032 0 173 487
-/+ buffers/cache: 176 1693
Swap: 2047 0 2047
[root@zstest1 ~]# ssh -p22 root@192.168.1.73 free -m
total used free shared buff/cache available
Mem: 985 110 712 43 162 708
Swap: 4095 0 4095
[root@zstest1 ~]#
如果禁止了root远程登录,可以使用sudo的方式结合expect来达到免密码分发文件
实例3:
批量查看远程主机的内存
###########################
show_client_status.sh
-----------------------------------------------
#!/bin/sh
. /etc/init.d/functions
for ip in `cat ip.list`
do
expect show_expect.exp $ip free #>/dev/null 2>&1
done
------------------------------------------------------
vim show_expect.exp
-------------------------------------------------------
#!/usr/bin/expect
if { $argc !=2 } {
send_user "USAGE: expect show_expect.exp $host $cmd\n"
exit
}
# define var
set host [lindex $argv 0]
set cmd [lindex $argv 1]
set password "123456"
spawn ssh -p22 root@$host $cmd
expect {
"yes/no" {send "yes\r";exp_continue}
"*password" {send "$password\r"}
}
expect eof
exit
--------------------------------------------------
vim ip.list
----------------------------
192.168.1.72
192.168.1.73
192.168.1.74
192.168.1.75
----------------------------
其中:
1.72上面删除了know_hosts文件中1.72的记录
1.72上面清空了.ssh目录下的文件
1.72上面还保留有公钥文件
#############################################
[root@zstest1 ~]# ./show_client_status.sh
spawn ssh -p22 root@192.168.1.72 free
The authenticity of host '192.168.1.72 (192.168.1.72)' can't be established.
RSA key fingerprint is a3:35:af:8c:26:1a:f0:b0:9f:0a:5f:7c:c0:6c:92:06.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.1.72' (RSA) to the list of known hosts.
root@192.168.1.72's password:
total used free shared buffers cached
Mem: 1914496 857440 1057056 0 177608 499068
-/+ buffers/cache: 180764 1733732
Swap: 2097144 0 2097144
spawn ssh -p22 root@192.168.1.73 free
total used free shared buff/cache available
Mem: 1009280 112988 729788 44680 166504 725288
Swap: 4194300 0 4194300
expect: spawn id exp4 not open
while executing
"expect eof"
(file "show_expect.exp" line 16)
spawn ssh -p22 root@192.168.1.74 free
ssh: connect to host 192.168.1.74 port 22: No route to host
expect: spawn id exp4 not open
while executing
"expect eof"
(file "show_expect.exp" line 16)
spawn ssh -p22 root@192.168.1.75 free
ssh: connect to host 192.168.1.75 port 22: No route to host
expect: spawn id exp4 not open
while executing
"expect eof"
(file "show_expect.exp" line 16)
###########################################
本文版权归作者和博客园共有,如果感觉有用可以随意打赏,感谢支持,欢迎转载

浙公网安备 33010602011771号