把ssh-agent单拿出来说,是因为随着公司的跳板机方案的实施,ssh-agent将大规模被或暗地里被应用。理解它的原理有助于我知道相关的部署和操作,以及如何安全滴应用。

像其他linux软件一样,最好的资料是用英文写的,关于ssh的认证和用户管理,有个不错的系列:http://www.symantec.com/connect/articles/ssh-and-ssh-agent, 搜索Brian Hatch这个红客即可。

ssh-agent到底是怎么工作的?下面列举2段E文,从描述我们能窥一斑。

  1. 摘自Brian Hatch的文章 

    One of the nice things about the agent is that it can follow you as you SSH from machine to machine. The default in newer versions of OpenSSH is to disable agent forwarding by default, so you'll need to decide when it's correct for you to use and specify it appropriately.

    How does the agent forwarding actually work? In short, the agent is running on one machine, and each time you SSH with agent forwarding, the server creates a 'tunnel' back through the SSH connection to the agent so it's available for any further SSH connections.

    Let's say we're on our desktop, we SSH to a management server with agent forwarding, and from the management server SSH to our mail server. Here's what happens: 

    • /usr/bin/ssh on your desktop connects to the management server, authenticates, and requests agent forwarding.
    • /usr/sbin/sshd on the management server creates a socket in /tmp/ssh-XXXXXXX/agent.##### and sets the SSH_AUTH_SOCK environment variable to match.
    • The SSH daemon then starts up your shell, and you begin doing your work on the management server.
    • When you decide to SSH out to the mail server, the /usr/bin/ssh program (here on the management server) sees the SSH_AUTH_SOCK environment variable and connects to that local socket file.
    • The SSH daemon, who is the other end of the local socket /tmp/ssh-XXXXXXX/agent.#####, simply transfers data from /usr/bin/ssh on the management server to and from the ssh-agent running on your desktop. All the key mathematics are handled on the actual agent, which is running on your desktop, not on any of the intervening machines.
    • The agent authenticates you to the mail server, and you're in.

    Using agent forwarding can save you a lot of time and typing.

2.   摘自putty的manual

Agent forwarding is a mechanism that allows applications on your SSH server machine to talk to the agent on your client machine.

Note that at present, agent forwarding in SSH-2 is only available when your SSH server is OpenSSH. The ssh.com server uses a different agent protocol, which PuTTY does not yet support.

To enable agent forwarding, first start Pageant. Then set up a PuTTY SSH session in which ‘Allow agent forwarding’ is enabled (see section 4.20.6). Open the session as normal. (Alternatively, you can use the -A command line option; see section 3.8.3.10 for details.)

If this has worked, your applications on the server should now have access to a Unix domain socket which the SSH server will forward back to PuTTY, and PuTTY will forward on to the agent. To check that this has actually happened, you can try this command on Unix server machines:

unixbox:~$ echo $SSH_AUTH_SOCK /tmp/ssh-XXNP18Jz/agent.28794 unixbox:~$ 

If the result line comes up blank, agent forwarding has not been enabled at all.

Now if you run ssh on the server and use it to connect through to another server that accepts one of the keys in Pageant, you should be able to log in without a password:

unixbox:~$ ssh -v otherunixbox [...] debug: next auth method to try is publickey debug: userauth_pubkey_agent: trying agent key my-putty-key debug: ssh-userauth2 successful: method publickey [...] 

If you enable agent forwarding on that SSH connection as well (see the manual for your server-side SSH client to find out how to do this), your authentication keys will still be available on the next machine you connect to - two SSH connections away from where they're actually stored.

In addition, if you have a private key on one of the SSH servers, you can send it all the way back to Pageant using the local ssh-add command:

unixbox:~$ ssh-add ~/.ssh/id_rsa Need passphrase for /home/fred/.ssh/id_rsa Enter passphrase for /home/fred/.ssh/id_rsa: Identity added: /home/fred/.ssh/id_rsa (/home/simon/.ssh/id_rsa) unixbox:~$ 

and then it's available to every machine that has agent forwarding available (not just the ones downstream of the place you added it). 

再补充几句,加个图。

在最底client,就是你最开始使用的ssh client,把ssh-agent使能起来(linux的方法参见Brian Hatch的文章,或者我的后续文章),同时也把agent forwarding给使能了。注意这个是两码事,ssh-agent只存放解密后的密钥,如果ssh选用了publickey的认证方式,ssh client就自动会去(或者通过配置)ssh-agent里头取密钥,目的是省去敲解密私密的麻烦。而agent forwarding则会让ssh client向ssh server请求forwarding,进而能达到N次ssh跳跃而不用输入密码的目的。

在ssh client端把这两个整好以后,就可以用了。从A机器ssh到B机器再到C机器,畅通无阻,无需密码。如果要再从C到D呢,那就得在B上面使能agent forwarding了,目的是在ssh server C收到agent forwarding之后能在本地预先建一个local socket并设置SSH_AUTH_SOCK环境变量,为server C上再用ssh client时提供方便。最后,虚拟来看,产生了一条安全传送private key的通道,在device C上的ssh client看来,device A上面的ssh-agent好像就运行在本地一样。

对于ssh client来说,如果看到SSH_AUTH_SOCK的环境变量这个环境变量被设了,它就认为可以连接这个local socket并且能从ssh-agent取私钥了,而这个ssh-agent可能运行在本地也可能运行在其他机器上(key的传输依靠ssh tunnel)

看个图就明白了

第一步:启动ssh-agent,这个程序会创建一个socket用于ssh-agent跟ssh的通信,export了

SSH_AUTH_SOCK和SSH_AGENT_PID,这样ssh client就知道ssh-agent启动了,如果正确地配置了ssh client,它就会从ssh-agent里头拿密钥。

第二步:ssh到设备B,由于ssh用ssh-agent里头的密钥,就不用输入密码了。由于ssh client请求了agent forwarding,sshd会创建一个socket,这个socket暂时没用,等下第3步用到


第三步:从设备B再ssh到设备C,ssh注意到有SSH_AUTH_SOCK的存在,就连接到这个socket,至此SSH(A)->SSHD(B)->SSH(B)就形成了一个传输密钥的通道,SSH-B就好像再跟本地的ssh-agent一样跟A上面的SSH-AGENT打交道

第四步:SSH(B)与SSHD(C)进行publickey认证,由于private key是从DEVICE A 上面的SSH-AGENT拿的,所以也不用输入密码。

从中可以看出,要使能agent forwarding,所要进行的操作主要在ssh client端,中间的ssh server如果是opensshd就自动支持,不需要额外的改动。

使用指南

1.linux

  1. Start up ssh-agent. You can have it create a subprocess which inherits the SSH_AUTH_SOCK environment variable, or you can run it as a daemon.

    Since I run gdm on Debian, ssh-agent is started automatically when I log in. If you don't have this benefit, you can get it by putting the following line at the end of your .xsession file (You can substitute your window manager for gnome-session if that is what you use):

    ssh-agent gnome-session
          

    Which basically means that ssh-agent starts up, creates a socket, sets up a couple of environment variables and then starts up gnome-session. That way all of the programs run in Gnome have access to the agent.

    The above solution is the best one if you are logging in via GDM or another graphical login manager under *nix. However, if you login at the console, or want to use ssh-agent under Cygwin, you'll have to use one of the following solutions.

    If you want to, say, put it in your .profile, then you might try the following setup. In my .bash_profile, I have

    SSHAGENT=/usr/bin/ssh-agent
    SSHAGENTARGS="-s"
    if [ -z "$SSH_AUTH_SOCK" -a -x "$SSHAGENT" ]; then
      eval `$SSHAGENT $SSHAGENTARGS`
      trap "kill $SSH_AGENT_PID" 0
    fi
    	

    (If you use csh or tcsh, see this note for the equivilent piece of code for your .login shell.)

    This brings SSH_AUTH_SOCK and SSH_AGENT_PID as environment variables into the current shell.

    The trap should kill off any remaining ssh-agent process. If it doesn't, you won't want the ssh-agent daemons sitting around, so you might want the following in your .logout:

    kill $SSH_AGENT_PID
    	

    An alternative, provided by John Buttery, is

    if [ ${SSH_AGENT_PID+1} == 1 ]; then
       ssh-add -D
       ssh-agent -k > /dev/null 2>&1
       unset SSH_AGENT_PID
       unset SSH_AUTH_SOCK
    fi
          

    Finally, this solution from Joseph M. Reagle by way of Daniel Starin:

    SSH_ENV="$HOME/.ssh/environment"
    
    function start_agent {
         echo "Initialising new SSH agent..."
         /usr/bin/ssh-agent | sed 's/^echo/#echo/' > "${SSH_ENV}"
         echo succeeded
         chmod 600 "${SSH_ENV}"
         . "${SSH_ENV}" > /dev/null
         /usr/bin/ssh-add;
    }
    
    # Source SSH settings, if applicable
    
    if [ -f "${SSH_ENV}" ]; then
         . "${SSH_ENV}" > /dev/null
         #ps ${SSH_AGENT_PID} doesn't work under cywgin
         ps -ef | grep ${SSH_AGENT_PID} | grep ssh-agent$ > /dev/null || {
             start_agent;
         }
    else
         start_agent;
    fi
    	

    This last version is especially nice since it will see if you've already started ssh-agent and, if it can't find it, will start it up and store the settings so that they'll be usable the next time you start up a shell.

    (Update 25 Sep 2007: Adam Piper pointed out that quoting anything that uses $HOME is necessary on Cygwin.)

  2. Finally, time to type a password. The last one of this session, maybe.
    $ ssh-add ~/.ssh/id_dsa
    Need passphrase for /home/mah/.ssh/id_dsa (you@example.com).
    Enter passphrase:
    $
        
  3. Now, you should test it:
    $ ssh you@example.com
    Last login: Tue Apr 25 13:40:21 1492 from europe.com
    Sun Microsystems Inc.   SunOS 5.7       Generic October 1998
    No mail.
    [you@example.com]$
        

    Jubilation! It worked! Go forth and conquer! (If it doesn't work, try chmod -R go-rw ~/.ssh on the server and try again.)

  4. In above steps, we only make ssh-agent to hold keys and elimilate the trouble to either assign private key in ssh command or type encrypt phrase everytime the private key is utilized. But this would not make agent forwarding along the way. 
    To make agent forwarding really happen on the logged-in server, we need to enable forwardagent option on ssh client(note: NOT ssh server) to be 'yes'

    Turn on agent forwarding globally

    Unless you have a good reason to forward the agent by default, you should verify that the agent forwarding is disabled by default. Locate the global ssh_config file, which typically lives in /etc/ or /etc/ssh/ and make sure you have the following:

     Host * ForwardAgent yes

    This will enable ssh-agent forwarding.

    Agent forwarding on the command line

    To forward your agent via the command line, just include a -A flag:

     desktop$ ssh -A user@remotehost

    The -a option disables agent forwarding, which is the default.

    Agent forwarding via the config file

    If you have a host to which you always wish to forward your agent, without the trouble of supplying the -A flag, you can create entries in ~/.ssh/config to turn it on for these hosts:

    cat ~/.ssh/config 

     Host shellserver ForwardAgent yes 

     Host management-server ForwardAgent yes 

     Host * ForwardAgent no

    Although the restrictive Host * section should be already contained in the global ssh_config file, I prefer to have it in my personal copy regardless.

如何知道ssh-agent起作用了?

         1. 在ssh client(假定位于主机penghongqing-desktop)上面确保ssh-agent启动了      

                       ps -ef | grep ssh-agent

         2. 在ssh client上面确认private key被ssh-agent管理了            

                      ssh-add -l

        3, 在ssh client上面确认SSH_AUTH_SOCK环境变量被置了

                     echo $SSH_AUTH_SOCK

       4. 在跳板机(假定主机名为cnbj-ctc-ops01-trf0002)上面确认SSH_AUTH_SOCK环境变量被设置了

       5. 在跳板机上启动ssh时,使用verbose模式,并查看private key是从那个主机拿的

            penghongqing@cnbj-ctc-ops01-trf0002:~$ssh -vvv ubuntu@10.1.81.23

              ...............................

               debug1: SSH2_MSG_SERVICE_ACCEPT received

               debug2: key: penghongqing@penghongqing-desktop (0x7f04a4ebde50)  ============>从这里可以看出来private key不是从跳板机本地拿的,而是从最开始的ssh client所在的主机上拿的

 

Logo

更多推荐