SSH agent和agent forwarding

把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 ([email protected]).
    Enter passphrase:
    $
        
  3. Now, you should test it:
    $ ssh [email protected]
    Last login: Tue Apr 25 13:40:21 1492 from europe.com
    Sun Microsystems Inc.   SunOS 5.7       Generic October 1998
    No mail.
    [[email protected]]$
        

    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 [email protected]

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

               debug1: SSH2_MSG_SERVICE_ACCEPT received

               debug2: key: penghongqing@penghongqing-desktop (0x7f04a4ebde50)  ============>從這裏可以看出來private key不是從跳板機本地拿的,而是從最開始的ssh client所在的主機上拿的

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章