把ssh-agent單拿出來說,是因爲隨着公司的跳板機方案的實施,ssh-agent將大規模被或暗地裏被應用。理解它的原理有助於我知道相關的部署和操作,以及如何安全滴應用。
像其他linux軟件一樣,最好的資料是用英文寫的,關於ssh的認證和用戶管理,有個不錯的系列:http://www.symantec.com/connect/articles/ssh-and-ssh-agent, 搜索Brian Hatch這個紅客即可。
ssh-agent到底是怎麼工作的?下面列舉2段E文,從描述我們能窺一斑。
- 摘自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 theSSH_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 theSSH_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 thessh-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
- 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.)
- 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: $
- 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.)
- 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 globalssh_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所在的主機上拿的