首页 > linux, 中级 > ssh的免认证登录

ssh的免认证登录

2010年2月12日 ahei 发表评论 阅读评论

linux下用ssh登录别的机器的时候,需要通过交互方式手工输入密码,ssh不支持直接加密码的选项,它觉得这样不安全。 但是有时候要完成一些自动的任务,比如登录到别的机器上,并在那台机器上启动一些程序,这时候该怎么办呢?

我下面提供几种方法:

  1. 通过expect
    ?Download ssh.exp
    1
    2
    3
    4
    5
    6
    
    #!/usr/bin/expect
     
    spawn ssh -o StrictHostKeyChecking=no -l username hostname
    expect "*password:"
    send "password\r"
    interact

    把上面的代码中的username和hostname替换为你的用户名和ip,然后保存为ssh.exp,再执行下面的代码:

    1
    2
    
    chown +x ssh.exp
    ./ssh.exp

    就可以自动登录到目标机器上并执行一下ls命令。
    这个方法有个缺点,就是密码以明文的方式保存在文件里,不安全

  2. sshpass
    sshpass是专门为ssh的免认证登录设计的, 它可以通过标准输入读入密码, 也可以通过把密码放在它的”-p”选项后面, 还可以用”-f”选项来制定密码文件, 还可以用”-e”选项从环境变量”SSHPASS”来读入密码, ssh的命令跟在sshpass的选项后面, 例如:

    sshpass -p password ssh host -l username

    rsync是一个同步的命令, 它是通过ssh来同步的, 如果你想执行rsync的时候也不输入密码, 可以通过指定rsync的”–rsh”选项来实现, 比如:

    rsync --rsh='sshpass -p password ssh -l username' host.example.com:path

    如果想要scp也不输入密码的话,建立下面的文件:

    ?Download ssh.sh
    1
    2
    3
    
    #!/usr/bin/env bash
     
    sshpass -p password ssh "$@"

    然后这样使用scp:

    scp -S path-of-ssh.sh/ssh.sh file user@host:path

    该方法使用起来简单, 缺点也是密码以明文方式保存.

  3. 通过密钥文件来实现免认证登录
    1
    2
    3
    4
    5
    
    # 1. 生成密钥
    ssh-keygen -t rsa -P "" -f ~/.ssh/id_rsa
     
    # 2. 把本机的公钥拷到目标机器上
    scp ~/.ssh/id_rsa.pub username@remote-hostname:~/temp

    经过上面的操作,再登录到目标机器上执行:

    1
    2
    3
    4
    5
    6
    7
    
    mkdir -p ~/.ssh
    # 改变权限,必须
    chmod 700 .ssh
    cat temp >> ~/.ssh/authorized_keys
    # 改变权限,必须
    chmod 600 ~/.ssh/authorized_keys
    rm -rf temp

    注意:上面代码中的chmod修改权限的语句必须执行,有的ssh设置使得.ssh目录和authorized_keys的权限必须只能自己可读可写,如果权限没设对的话,照样不能免认证登录,这是为了安全考虑。
    经过上面的操作,你现在就可以不需要输入密码就可以登录到目标机器上了。


  4. 上面那个方法,虽然执行的命令不多,但是你想想,如果我们要让一台机器对100台机器都实现免认证登录,岂不是还是很麻烦。那我们把上面的命令写成一个脚本岂不甚好?好注意,不过不用你写了,-copy-id这个命令已经帮你写了,你可以去看看/usr/bin/-copy-id这个文件,它实际上就是一个shell脚本,帮你把你的公钥拷到目标主机的认证文件里,并修改权限,不过它不帮你生成公钥,还得你自己生成。使用方法:

    ssh-copy-id [username]@hostname

    很简单吧!

上面的方法3由于不需要把密码明文直接写到文件里面,所以比较安全,方法4和方法3本质上是一样的。

现在我们来考虑另外一个问题。

假如你通过方法2设置了免认证登录,这样, 只要别人拿到了你的私钥, 就可以登录所有已经认证你的机器了. 当然你也可以为你的私钥设置一个密码, 这是通过ssh-keygen的”-P”的来设置的. 但是现在又有一个问题, 那就是你每次登录到已经认证过你的机器的时候, 你都要输入一次你的私钥密码. keychain是解决这个问题的一个很好的工具, 它是ssh-agent的一个前端, 它会把已经认证过的密钥加入ssh-agent的高速缓存, 这样, 只有你第一次使用你的私钥登录别的机器的时候, 需要输入一下密码, 以后再次使用你的私钥的时候, 就不用输入密码了, 既保证了安全性, 又保证了便捷性.

讲完了上面说的免认证登录方法,我们现在可以很简单的让一个集群之间的每一台机器之间都互相免认证,而且完全自动化。
方法就是:先在集群中的某一台机器上生成好密钥,并且把这台机器自己的公钥添加到它自己的认证文件里面,这样就实现了这台机器免认证登录自己。然后利用expect向每一台机器拷贝刚才那台机器的公私钥和认证文件,这样这个集群中所有机器的公私钥和认证文件都一样了,而刚才那台机器已经可以免认证登录自己,它们之间也当然可以免认证登录了(:),是不是有点绕?)。这个方法会让每台机器的公私钥都一样,如果集群机器中已经配置了一些其他免认证登录的信息,不能破坏已有的公私钥,这个方法就不能凑效了,只能每两台机器之间互相调用ssh-copy-id命令。
上面的方法具体实现如下:
在集群中某一台机器上执行:

1
2
3
4
5
6
ssh-keygen -t rsa -P "" -f ~/.ssh/id_rsa
# 改变权限,必须
chmod 700 ~/.ssh
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
# 改变权限,必须
chmod 600 ~/.ssh/authorized_keys

然后拷贝该机器的公私钥和认证文件到其他的机器上:

?Download scp-auth.exp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/usr/bin/expect
 
proc scp {user password host} {
    global env
 
    set home $env(HOME)
 
    spawn ssh -o StrictHostKeyChecking=no $user@$host mkdir -p ~/.ssh
    expect "*password:" {send "$password\r"}
 
    spawn scp -r -o StrictHostKeyChecking=no $home/.ssh/id_rsa $user@$host:~/.ssh
    expect "*password:" {send "$password\r"}
 
    spawn scp -r -o StrictHostKeyChecking=no $home/.ssh/authorized_keys $user@$host:~/.ssh
    expect "*password:" {send "$password\r"}
 
    wait
}
 
set user [lindex $argv 0]
set password [lindex $argv 1]
set host [lindex $argv 2]
 
scp $user $password $host

把上面的scp-auth.exp文件保存后,执行下面的命令:

1
2
chmod +x scp-auth.exp
cat hostlist | xargs -l ./scp-auth.exp

其中hostlist文件为你的所有要拷贝认证文件的机器列表,每行一条记录, 每条记录的格式为:
<username> <password> <ip>
现在你可以在这个机器集群上自由的穿梭了, 不用输入任何密码!

expect很方便吧, 它最大的用处就是用来为那些需要交互的程序模拟用户的输入, 比如passwd, ssh, fsck, ftp等.

分类: linux, 中级
  1. transtone
    2010年2月13日00:33 | #1

    1.expect 还需要tcl/tk的支持,很不爽的,可以用pexpect来完成,这是一个 expect 的 python实现。
    2.ssh密钥的方式很好用,但rsa的方式也不够安全,还是dsa的要好一些,另外密钥也一定要有密码,不能图方便而不用。当然也有方便的方法可以可以避免每次登录都输入密码,就是用 keychain。这里有几个文档希望有帮助。http://www.gentoo.org/doc/en/keychain-guide.xml http://www.gentoo.org/proj/en/keychain/ http://www.gentoo.org/doc/en/articles/openssh-key-management-p1.xml

    [回复]

    ahei 回复:

    1. pexpect不需要tcl/tk的支持吗?
    2.
    2.1 呵呵,我查了一下,貌似rsa和dsa安全性差不多.
    2.2 你没看完我的文章吧,我的文中提到了keychain啊:
    假如你通过方法2设置了免认证登录,这样, 只要别人拿到了你的私钥, 就可以登录所有已经认证你的机器了. 当然你也可以为你的私钥设置一个密码, 这是通过ssh-keygen的”-P”的来设置的. 但是现在又有一个问题, 那就是你每次登录到已经认证过你的机器的时候, 你都要输入一次你的私钥密码. keychain是解决这个问题的一个很好的工具, 它是ssh-agent的一个前端, 它会把已经认证过的密钥加入ssh-agent的高速缓存, 这样, 只有你第一次使用你的私钥登录别的机器的时候, 需要输入一下密码, 以后再次使用你的私钥的时候, 就不用输入密码了, 既保证了安全性, 又保证了便捷性.

    [回复]

  2. 2010年3月30日08:19 | #2

    我现在是购买了一个具有ssh功能的国外主机进行代理,用于访问某些网站。
    命令为ssh -qTfnN -D 7070 username@hostname

    每次都要在ubuntu下面输入同样的命令,然后回车等待输入密码。上面的方法中有没有可以免于输入密码环节且能断线重拨的……

    [回复]

    ahei 回复:

    @limars, 我文章中说的方法不都是不需要手工输入密码的嘛,至于断线重拨,。。。,没有,只能自己写个shell,检测那个ssh进程在不在,不在的话,就重新连,而且你短线的频率没那么高吧,段了,再执行一下命令不就可以了吗

    [回复]

    limars 回复:

    @ahei,

    就是说后面的命令参数什么完全不影响么,等会去试试看。
    十分感谢。

    [回复]

    ahei 回复:

    @limars, 当然有影响阿,不过基本上也只是替换一下user,host

    [回复]

    大头阿当 回复:

    @limars,
    你可以在你的$HOME/.ssh目录中touch一个config文件,并且写入
    HOST
    USER
    Port //就是你-D后面的参数
    ….
    等等等等,关于可以使用的选项,你需要查看以下man ssh中option一节。
    -N -n选项应当不能省略,其他都有办法吧。好好看看手册吧。

    [回复]

    ahei 回复:

    呵呵,好像没有密码的选项吧?

    [回复]

  3. 2010年8月14日10:15 | #3

    用了您的第三种方法。谢谢 :lol:

    [回复]

  1. 本文目前尚无任何 trackbacks 和 pingbacks.

:wink: :-| :-x :twisted: :) 8-O :( :roll: :-P :oops: :-o :mrgreen: :lol: :idea: :-D :evil: :cry: 8) :arrow: :-? :?: :!: