【发布时间】:2010-12-20 10:11:41
【问题描述】:
我有一个需要安装公钥的主机列表。为此,我编写了一个 ruby 脚本,它调用一个期望脚本并将我的密码、主机名和公钥文件传递给它。这个期望脚本依次对每个主机执行 ssh-copy-id,方法是输入密码并对未知主机密钥回答“是”。
expect 脚本在命令行运行时运行良好。但是,当从 ruby 脚本执行时,对于未知的主机密钥确认,expect 无法回答“是”:“您确定要继续连接(是/否)吗?”。当向它抛出是/否问题时,expect 脚本就会冻结。
任何帮助将不胜感激。
这是我的红宝石脚本:
#!/usr/bin/env ruby -w
hosts=['test@blah1.edu','test2@blah2.edu','test3@blah3.edu']
password="blahblahblah"
key_file="/home/blah/.ssh/id_rsa.pub"
hosts.each{ |host|
command="expect sshcopy.exp #{host} #{key_file} #{password}"
`#{command}`
}
这是我的期望脚本sshcopy.exp:
set host [lrange $argv 0 0]
set key_file [lrange $argv 1 1]
set password [lrange $argv 2 2]
spawn ssh-copy-id -i $key_file $host
expect -nocase "*password: $" {send "$password\r"; interact} -nocase "*are you sure you want to continue connecting (yes/no)? $" {send "yes\r"} eof{exit}
expect -nocase "*password: $" {send "$password\r"; interact} eof{exit}
您将在上面看到两个期望语句。第一条语句处理通过 interacting 立即询问密码(即主机密钥已知)的情况。它还通过回答“是”来处理识别到未知主机的情况。
第二个 expect 语句在第一个 expect 回答“是”导致询问密码时执行。
【问题讨论】:
-
在你的期望脚本中,使用带有单个索引的
lindex,而不是带有两个索引的lrange。否则,如果任何参数包含 Tcl 列表元字符(例如,空格或花括号),您会得到“惊喜”;这些东西在文件名和密码中相对可能...... -
另外,在命令行上传递密码是不安全的。
ps命令(使用正确的参数)可以读取系统上任何进程的完整参数。环境变量也是如此(尽管需要不同的选项来获取它们)。安全的方法是在标准输入管道上发送它,或者把它放在一个文件中具有严格权限并在命令行上传递该文件的名称(因为知道文件名不会帮助黑客阅读它)。但是,如果您使用的系统可以保证没有入侵者(很棘手!),那么确保安全并不是很重要。