使用ssh连接远程Linux时往往要输入密码,在开发和日常管理中可以建立信任关系,减少输入密码步骤。
使用ssh-keygen -t rsa命令,会在~/.ssh目录下生成id_rsa和id_rsa.pub文件,把id_rsa.pub文件中的内容添加到远程Linux主机目标用户的~/.ssh/authorized_keys文件中,然后就可以ssh免密码连接了,在文件需要批量部署时可以发挥更大作用。
下面是使用expect脚本实现一键建立信任关系
trust_ssh.exp
#!/usr/bin/expect -f
# variables
set prefix "\033\[1;31m>>>\033\[0m"
proc usage {} {
regsub ".*/" $::argv0 "" name
send_user "please usage: $name user@host password\n"
exit 1
}
proc check_id_pub_file {} {
if {! [file exists $::id_file]} {
send_user "$::prefix id_rsa.pub is not found, try creating...\n"
if {[catch {spawn ssh-keygen -t rsa} error]} {
send_error "$::prefix $error\n"
exit 1
}
expect -nocase -re "\(.*\):"
send -- "\r"
expect -nocase -re "passphrase.*:"
send -- "\r"
expect -nocase -re "passphrase.*again:"
send -- "\r"
expect eof
send_user "$::prefix id_rsa.pub create success\n"
}
}
proc remove_known_host_entry {host} {
regsub ".*/" $::argv0 "" name
set tmp_file "/tmp/$name.tmp"
set known_hosts "$::env(HOME)/.ssh/known_hosts"
send_user "$::prefix trying to remove '$host' from ~/.ssh/known_hosts...\n"
if {[catch {
set fd_known_hosts [open $known_hosts r]
set fd_tmp [open $tmp_file w]
while 1 {
gets $fd_known_hosts line
if [eof $fd_known_hosts] {
break
}
if [regexp "(\[^, ]+,)*${host}(,\[^, ]+)* " $line] {
continue
}
puts $fd_tmp $line
}
close $fd_known_hosts
close $fd_tmp
file rename -force $tmp_file $known_hosts
send_user "remove '$host' from ~/.ssh/known_hosts success\n"
} error]} {
send_user "$::prefix $error\n"
exit 1
}
}
# get user@host and password
if {[llength $argv] != 2} {
usage
}
set user@host [lindex $argv 0]
set password [lindex $argv 1]
# create public key file if not found
set id_file "$env(HOME)/.ssh/id_rsa.pub"
check_id_pub_file
# ssh to host
set yes_no 0
set ok_string success
set tomeout 120
set done 0
while {!$done} {
spawn ssh ${user@host} echo $ok_string
expect {
-nocase -re "yes/no" {
set yes_no 1
send -- "yes\r"
set done 1
}
-nocase -re "password: " {
set done 1
}
$ok_string {
send_user "$prefix ok\n"
}
"@@@@@@@@@@@@@@@@@@@@" {
expect eof
set indexofatsign [string first "@" ${user@host}]
incr indexofatsign
set hostname [string range ${user@host} $indexofatsign end]
remove_known_hosts_entry $hostname
}
eof {
send_error "$prefix failed\n"
exit 1
}
timeout {
send_error "$prefix timeour\n"
exit 1
}
}
}
if {$yes_no} {
expect {
$ok_string {
send_user "$prefix ok\n"
exit 0
}
-nocase -re "password: " {}
}
}
send -- "$password\r"
expect {
-nocase "try again" {
send_error "$prefix password error\n"
exit 1
}
-nocase "passwrord: " {
send_error "$prefix password error\n"
exit 1
}
$ok_string {}
}
expect eof
# append public key to remote hosts ~/.ssh/authorized_keys
if {[catch {
set idfile [open $id_file RDONLY]
set pub_key [read $idfile]
close $idfile
} error]} {
send_error "$prefix $error\n"
exit 1
}
set pub_key [string trimright $pub_key "\r\n"]
spawn ssh ${user@host} "cd; mkdir -p .ssh 2> /dev/null; echo '$pub_key' >> .ssh/authorized_keys"
expect -nocase -re "password:"
send -- "$password\r"
expect eof
send_user "$prefix authenticating relation success\n"
exit 0
执行结果