SSH Agents

An SSH agent is a program that caches private keys and responds to authentication-related queries from SSH clients. ["The SSH Agent"] They are terrific labor-saving devices, handling all key-related operations and eliminating the need to retype your passphrase.The programs related to agents are ssh-agent and ssh-add. ssh-agent runs an agent, and ssh-add inserts and removes keys from the agent's key cache. A typical use might look like this:

# Start the agent $ ssh-agent $SHELL # Load your default identity $ ssh-add Need passphrase for /home/barrett/.ssh/identity (barrett@example.com). Enter passphrase: ********


By typing your passphrase a single time, you decrypt the private key which is then stored in memory by the agent. From now on, until you terminate the agent or log out, SSH clients automatically contact the agent for all key-related operations. You needn't type your passphrase again.We now briefly discuss how agents work. After that we get practical and illustrate the two ways to start an agent, various configuration options, and several techniques for automatically loading your keys into the agent. Finally, we cover agent security, agent forwarding, and compatibility between SSH-1 and SSH-2 agents.

Agents Don't Expose Keys

Agents perform two tasks: Agents don't, however, send your private keys anywhere. This is important to understand. Once loaded, private keys remain within an agent, unseen by SSH clients. To access a key, a client says, "Hey agent! I need your help. Please perform a key-related operation for me." The agent obeys and sends the results to the client (see Figure 6-4). Figure 6-4

Figure 6-4. How an SSH agent works with its clients

For example, if ssh needs to sign an authenticator, it sends the agent a signing request containing the authenticator data and an indication of which key to use. The agent performs the cryptographic operation itself and returns the signature.In this manner, SSH clients use the agent without ever seeing the agent's private keys. This technique is more secure than handing out keys to clients. The fewer places that private keys get stored or sent, the harder it is to steal them.[80]
[80]This design also fits well with token-based key storage, in which your keys are kept on a smart card carried with you. Examples are the U.S. government-standard Fortezza card or RSA Security's Keon system. Like agents, smart cards respond to key-related requests but don't give out keys, so integration with SSH would be straightforward. Though adoption of tokens has been slow, we believe it will be commonplace in the future.

Starting an Agent

There are two ways to invoke an agent in your login account:
WARNING: Don't invoke an agent with the "obvious" but wrong command:

$ ssh-agent


Although the agent runs without complaint, SSH clients can't contact it, and the termination command (ssh-agent -k) doesn't kill it, because some environment variables aren't properly set.

Single-shell method

The single-shell method runs an agent in your current login shell. This is most convenient if you're running a login shell on a single terminal, as opposed to a Unix window system such as X. Type:

# SSH1, SSH2, OpenSSH $ eval `ssh-agent`


and an ssh-agent process is forked in the background. The process detaches itself from your terminal, returning a prompt to you, so you needn't run it in the background manually (i.e., with an ampersand on the end). Note that the quotes around ssh-agent are backquotes, not apostrophes.What purpose does the eval serve? Well, when ssh-agent runs, it not only forks itself in the background, it also outputs some shell commands to set several environment variables necessary for using the agent. The variables are SSH_AUTH_SOCK (for SSH1 and OpenSSH) or SSH2_AUTH_SOCK (SSH2), and SSH_AGENT_PID (SSH1, OpenSSH) or SSH2_AGENT_PID (SSH2).[81] The eval command causes the current shell to interpret the commands output by ssh-agent, setting the environment variables. If you omit the eval, these commands are printed on standard output as ssh-agent is invoked. For example:
[81]Older versions of SSH1 use SSH_AUTHENTICATION_SOCKET instead of SSH_AUTH_SOCK. If this applies to you, we recommend setting SSH_AUTH_SOCK yourself, for example (in C shell):


$ ssh-agent SSH_AUTH_SOCK=/tmp/ssh-barrett/ssh-22841-agent; export SSH_AUTH_SOCK; SSH_AGENT_PID=22842; export SSH_AGENT_PID; echo Agent pid 22842;


Now you've got an agent running but inaccessible to the shell. You can either kill it using the pid printed in the previous output:

$ kill 22842


or connect your shell manually by setting the environment variables exactly as given:

$ SSH_AUTH_SOCK=/tmp/ssh-barrett/ssh-22841-agent; export SSH_AUTH_SOCK; $ SSH_AGENT_PID=22842; export SSH_AGENT_PID;


Nevertheless, it's easier to use the single-shell form of the command so everything is set up for you.[82]
[82]Why can't ssh-agent set its environment variables without all this trickery? Because under Unix, a program can't set environment variables in its parent shell.
To terminate the agent, kill its pid:

# SSH1, SSH2, OpenSSH $ kill 22842


and unset the environment variables:

$ unset SSH_AUTH_SOCK # SSH2 uses SSH2_AUTH_SOCK instead $ unset SSH_AGENT_PID


Or for SSH1 and OpenSSH, use the more convenient -k command-line option:

# SSH1, OpenSSH $ eval `ssh-agent -k`


This prints termination commands on standard output so the eval can invoke them. If you eliminate the eval, the agent is still killed, but your environment variables don't unset automatically:

# SSH1, OpenSSH $ ssh-agent1 -k unset SSH_AUTH_SOCK # This won't get unset, unset SSH_AGENT_PID # and neither will this, echo Agent pid 22848 killed # but the agent gets killed.


Running an agent in a single shell, as opposed to the method we cover next (spawning a subshell), has one problem. When your login session ends, the ssh-agent process doesn't die. After several logins, you see many agents running, serving no purpose.[83]
[83]Actually, you can reconnect to an agent launched in a previous login by modifying your SSH_AUTH_SOCK variable to point to the old socket, but this is gross.


$ /usr/ucb/ps uax | grep ssh-agent barrett 7833 0.4 0.4 828 608 pts/1 S 21:06:10 0:00 grep agent barrett 4189 0.0 0.6 1460 844 ? S Feb 21 0:06 ssh-agent barrett 6134 0.0 0.6 1448 828 ? S 23:11:41 0:00 ssh-agent barrett 6167 0.0 0.6 1448 828 ? S 23:24:19 0:00 ssh-agent barrett 7719 0.0 0.6 1456 840 ? S 20:42:25 0:02 ssh-agent


You can get around this problem by running ssh-agent -k automatically when you log out. In Bourne style shells (sh, ksh, bash), this may be done with a trap of Unix signal at the top of ~/.profile :

# ~/.profile trap ' test -n "$SSH_AGENT_PID" && eval `ssh-agent1 -k` ; test -n "$SSH2_AGENT_PID" && kill $SSH2_AGENT_PID ' 0


For C shell and tcsh, terminate the agent in your ~/.logout file:

# ~/.logout if ( "$SSH_AGENT_PID" != "" ) then eval `ssh-agent -k` endif if ( "$SSH2_AGENT_PID" != "" ) then kill $SSH2_AGENT_PID endif


Once this trap is set, your ssh-agent process is killed automatically when you log out, printing a message like:

Agent pid 8090 killed 


Subshell method

The second way to invoke an agent spawns a subshell. You provide an argument to ssh-agent, which is a path to a shell or shell script. Examples are:

$ ssh-agent /bin/sh $ ssh-agent /bin/csh $ ssh-agent $SHELL $ ssh-agent my-shell-script # Run a shell script instead of a shell


This time, instead of forking a background process, ssh-agent runs in the foreground, spawning a subshell and setting the aforementioned environment variables automatically. The rest of your login session runs within this subshell, and when you terminate it, ssh-agent terminates as well. This method, as you will see later, is most convenient if you run a window system such as X and invoke the agent in your initialization file (e.g., ~/.xsession). However, the method is also perfectly reasonable for single-terminal logins.When using the subshell method, invoke it at an appropriate time. We recommend the last line of your login initialization file (e.g., ~/.profile or ~/.login) or the first typed command after you log in. Otherwise, if you first run some background processes in your shell, and then invoke the agent, those initial background processes become inaccessible until you terminate the agent's subshell. For example, if you run the vi editor, suspend it, and then run the agent, you lose access to the editor session until you terminate the agent.

$ vi myfile # Run your editor ^Z # Suspend it $ jobs # View your background processes [1] + Stopped (SIGTSTP) vi $ ssh-agent $SHELL # Run a subshell $ jobs # No jobs here! They're in the parent shell $ exit # Terminate the agent's subshell $ jobs # Now we can see our processes again [1] + Stopped (SIGTSTP) vi


The advantages and disadvantages of the two methods are shown in Table 6-1.

Table 6-1. Pros and Cons of Invoking an Agent

Method Pros Cons
eval `ssh-agent` Simple, intuitive Must be terminated manually
ssh-agent $SHELL Agent's environment variables are propagated automatically; terminates on logout Your login shell becomes dependent on the agent's health; if the agent dies, your login shell may die

Format of environment variable commands

As we've said, ssh-agent prints a sequence of shell commands to set several environment variables. The syntax of these commands differs depending on which shell is being used. You can force the commands to use Bourne-style or C shell-style syntax with the -s and -c options, respectively:

# Bourne-shell style commands $ ssh-agent -s SSH_AUTH_SOCK=/tmp/ssh-barrett/ssh-3654-agent; export SSH_AUTH_SOCK; SSH_AGENT_PID=3655; export SSH_AGENT_PID; echo Agent pid 3655; # C-shell style commands $ ssh-agent -c setenv SSH_AUTH_SOCK /tmp/ssh-barrett/ssh-3654-agent; setenv SSH_AGENT_PID 3655; echo Agent pid 3655;


Normally ssh-agent detects your login shell and prints the appropriate lines, so you don't need -c or -s. One situation where you need these options is if you invoke ssh-agent within a shell script, but the script's shell is not the same type as your login shell. For example, if your login shell is /bin/csh, and you invoke this script:

#!/bin/sh `ssh-agent`


ssh-agent outputs C shell-style commands, which will fail. So you should use:

#!/bin/sh `ssh-agent -s`


This is particularly important if you run an agent under X, and your ~/.xsession file (or other startup file) is executed by a shell different from your login shell.

SSH-1 and SSH-2 agent compatibility

An SSH-1 agent can't service requests from SSH-2 clients. The reverse, however, is supported by SSH2. If ssh-agent2 is invoked with the -1 option (that's a numeral one, not a lowercase L), the agent services requests from SSH-1 clients, even from ssh-add1. This works only for SSH-2 implementations that support RSA, because SSH-1 uses RSA keys. At press time, only F-Secure SSH2 Server is capable of SSH-1 agent compatibility.

# Invoke an SSH2 agent in SSH1 compatibility mode $ eval `ssh-agent2 -1` # Add an SSH1 key $ ssh-add1 Need passphrase for /home/smith/.ssh/identity (smith SSH1 key). Enter passphrase: **** Identity added (smith SSH1 key). # Add an SSH2 key $ ssh-add2 Adding identity: /home/smith/.ssh2/id_dsa_1024_a.pub Need passphrase for /home/smith/.ssh2/id_dsa_1024_a (1024-bit dsa, smith SSH2 key, Thu Dec 02 1999 22:25:09-0500). Enter passphrase: ******** # ssh-add1 lists only the SSH1 key $ ssh-add1 -l 1024 37 1425047358166328978851045774063877571270and so forth




# ssh-add2 lists both keys # F-Secure SSH Server only $ ssh-add2 -l Listing identities. The authorization agent has 2 keys: id_dsa_1024_a: 1024-bit dsa, smith SSH2 key, Thu Dec 02 1999 22:25:09-0500 smith SSH1 key


Now an SSH-1 client contacts ssh-agent2 transparently, believing it to be an SSH-1 agent:

$ ssh1 server.example.com [no passphrase prompt appears]


ssh-agent2 achieves compatibility by setting the same environment variables normally set by ssh-agent1: SSH_AUTH_SOCK and SSH_AGENT_PID. Therefore, any SSH-1 agent requests are directed to ssh-agent2.
WARNING: If you have an ssh-agent1 process running, and you invoke ssh-agent2 -1, your old ssh-agent1 process becomes inaccessible as ssh-agent2 overwrites its environment variables.
Agent compatibility works only if the SSH2 distribution is compiled with the flag -- with-ssh-agent1-compat. ["SSH-1/SSH-2 agent compatibility"] It also depends on the value of the client configuration keyword Ssh1AgentCompatibility. ["SSH1/SSH2 Compatibility"]

Loading Keys with ssh-add

The program ssh-add is your personal communication channel to an ssh-agent process. (Again, this command may be ssh-add1 under SSH1 and ssh-add2 under SSH2, with ssh-add a link to one program or the other.)When you first invoke an SSH agent, it contains no keys. ssh-add, as you might guess from its name, can add private keys to an SSH agent. But the name is misleading, because it also controls the agent in other ways, such as listing keys, deleting keys, and locking the agent from accepting further keys.If you invoke ssh-add with no arguments, your default SSH key is loaded into the agent, once you have typed its passphrase. For example:

$ ssh-add1 Need passphrase for /home/smith/.ssh/identity (smith@client). Enter passphrase: ******** Identity added: /home/smith/.ssh/identity (smith@client). $ ssh-add2 Adding identity: /home/smith/.ssh2/id_dsa_1024_a.pub Need passphrase for /home/smith/.ssh2/id_dsa_1024_a (1024-bit dsa, smith@client, Thu Dec 02 1999 22:25:09-0500). Enter passphrase: ********


Normally, ssh-add reads the passphrase from the user's terminal. If the standard input isn't a terminal, however, and the DISPLAY environment variable is set, ssh-add instead invokes an X window graphical program called ssh-askpass that pops up a window to read your passphrase. This is especially convenient in xdm start-up scripts.[84]
[84]X has its own security problems, of course. If someone can connect to your X server, they can monitor all your keystrokes, including your passphrase. Whether this is an issue in using ssh-askpass depends on your system and security needs.
Both ssh-add1 and ssh-add2 support the following command-line options for listing and deleting keys, and for reading the passphrase: In addition, ssh-add2 has further features controlled by command-line options:

Automatic agent loading (single-shell method)

It's a pain to invoke ssh-agent and/or ssh-add manually each time you log in. With some clever lines in your login initialization file, you can automatically invoke an agent and load your default identity. We demonstrate this with both methods of agent invocation, single-shell and subshell.With the single-shell method, here are the major steps:
  1. Make sure you're not already running an agent, by testing environment variable SSH_AUTH_SOCK or SSH2_AUTH_SOCK.
  2. Run the agent, ssh-agent1 or ssh-agent2, using eval.
  3. If your shell is attached to a tty, load your default identity with ssh-add1 or ssh-add2.
For the Bourne shell and its derivatives (ksh, bash), the following lines can be placed into ~/.profile :

# Make sure ssh-agent1 and ssh-agent2 die on logout trap ' test -n "$SSH_AGENT_PID" && eval `ssh-agent1 -k` ; test -n "$SSH2_AGENT_PID" && kill $SSH2_AGENT_PID ' 0 # If no agent is running and we have a terminal, run ssh-agent and ssh-add. # (For SSH2, change this to use SSH2_AUTH_SOCK, ssh-agent2 and ssh-add2.) if [ "$SSH_AUTH_SOCK" = "" ] then eval `ssh-agent` /usr/bin/tty > /dev/null && ssh-add fi


For the C shell and tcsh, the following lines can be placed into ~/.login:

# Use SSH2_AUTH_SOCK instead for SSH2 if ( ! $?SSH_AUTH_SOCK ) then eval `ssh-agent` /usr/bin/tty > /dev/null && ssh-add endif


and termination code in ~/.logout :

# ~/.logout if ( "$SSH_AGENT_PID" != "" ) eval `ssh-agent -k` if ( "$SSH2_AGENT_PID" != "" ) kill $SSH2_AGENT_PID


Automatic agent loading (subshell method)

The second way to load an agent on login uses the subshell method to invoke the agent. This time, you need to add lines to both your login initialization file (~/.profile or ~/.login), an optional second file of your choice, and your shell initialization file (~/.cshrc, ~/.bashrc, etc.). This method doesn't work for the Bourne shell, which has no shell initialization file.
  1. In your login initialization file, make sure you're not already running an agent, by testing environment variable SSH_AUTH_SOCK or SSH2_AUTH_SOCK.
  2. As the last line of your login initialization file, exec ssh-agent, which spawns a subshell. Optionally run a second initialization file to configure aspects of the subshell.
  3. In your shell initialization file, check whether the shell is attached to a tty and that the agent has no identities loaded yet. If so, load your default identity with ssh-add1 or ssh-add2.
Now let's see how to do this with Bourne shell and C shell families. For derivatives of Bourne shell (ksh, bash), put the following lines at the end of ~/.profile :

test -n "$SSH_AUTH_SOCK" && exec ssh-agent $SHELL


This runs the agent, spawning a subshell. If you want to tailor the environment of the subshell, create a script (say, ~/.profile2) to do so, and use this instead:

test -n "$SSH_AUTH_SOCK" && exec ssh-agent $SHELL $HOME/.profile2


Next, in your shell initialization file ($ENV for ksh, or ~/.bashrc for bash), place the following lines to load your default identity only if it's not loaded already:

# Make sure we are attached to a tty if /usr/bin/tty > /dev/null then # Check the output of "ssh-add -l" for identities. # For SSH2, use the line: # ssh-add2 -l | grep 'no keys' > /dev/null # ssh-add1 -l | grep 'no identities' > /dev/null if [ $? -eq 0 ] then # Load your default identity. Use ssh-add2 for SSH2. ssh-add1 fi fi


Automatic agent loading (X Window System)

If you're using X and want to run an agent and load your default identity automatically, it's simple. Just use the single-shell method. For example, in your X startup file, usually ~/.xsession, you can use these two lines:

eval `ssh-agent` ssh-add


Agents and Security

As we mentioned earlier, agents don't expose private keys to SSH clients. Instead, they answer requests from clients about the keys. This approach is more secure than passing keys around, but it still has some security concerns. It is important to understand these concerns before completely trusting the agent model:

Access control

When your agent is loaded with private keys, a potential security issue arises. How does your agent distinguish between legitimate requests from your SSH clients and illegitimate requests from unauthorized sources? Surprisingly, the agent does not distinguish at all. Agents don't authenticate their clients. They will respond to any well-formed request received over their IPC channel, which is a Unix domain socket.How is agent security maintained then? The host operating system is responsible for protecting the IPC channel from unauthorized access. For Unix, this protection is accomplished by the file permissions on the socket. SSH1 and SSH2 keep your agent sockets in a protected directory, /tmp/ssh-USERNAME, where USENRAME is your login name, while OpenSSH names the directory /tmp/ssh-STRING, where STRING is random text based on the agent's pid. In either case, the directory is protected from all other users (mode 700) and owned by you:

$ ls -la /tmp/ssh-smith/ drwx------ 2 smith smith 1024 Feb 17 18:18 . drwxrwxrwt 9 root root 1024 Feb 17 18:01 .. srwx------ 1 smith smith 0 May 14 1999 agent-socket-328 s-w--w--w- 1 root root 0 Feb 14 14:30 ssh-24649-agent srw------- 1 smith smith 0 Dec 3 00:34 ssh2-29614-agent


In this case, user smith has several agent-related sockets in this directory. The two sockets owned by smith were created by agents run and owned by smith. The third, which is world-writable and owned by root, was created by the SSH server to effect an agent forwarding.[85] ["Agent Forwarding"]
[85]Even though this socket is world-writable, only user smith can access it due to the permissions on the parent directory, /tmp/ssh-smith.
This organization of a user's sockets into a single directory is not only for neatness but also for security and portability, because different operating systems treat socket permissions in different ways. For example, Solaris appears to ignore them completely; even a socket with permission 000 (no access for anyone) accepts all connections. Linux respects socket permissions, but a write-only socket permits both reading and writing. To deal with such diverse implementations, SSH keeps your sockets in a directory owned by you, with directory permissions that forbid anyone else to access the sockets inside.Using a subdirectory of /tmp, rather than /tmp itself, also prevents a class of attacks called temp races. A temp-race attack takes advantage of race conditions inherent in the common setting of the "sticky" mode bit on the Unix /tmp directory, allowing anyone to create a file there, but only allowing deletion of files owned by the same uid as the deleting process.

Cracking an agent

If the machine running your agent is compromised, an attacker can easily gain access to the IPC channel and thus to your agent. This permits the interloper to make requests of the agent, at least for a time. Once you log out or unload your keys from the agent, the security hole is closed. Therefore, you should run agents only on trusted machines, perhaps unloading your keys (ssh-agent -D) if you're away from the computer for an extended time, such as overnight.Since agents don't give out keys, your keys would seem safe from theft if the machine is compromised. Alas, that's not the case. An enterprising cracker, once logged into the machine, has other means for getting your keys, such as: The bottom line is this: run agents only on trusted machines. SSH does not excuse you from securing other aspects of your system.

Agent Forwarding

So far, our SSH clients have conversed with an SSH agent on the same machine. Using a feature called agent forwarding, clients can also communicate with agents on remote machines. This is both a convenience feature -- permitting your clients on multiple machines to work with a single agent -- and a means for avoiding some firewall-related problems.

A firewall example

Suppose you want to connect from your home computer, H, to a computer at work, W. Like many corporate computers, W is behind a network firewall and not directly accessible from the Internet, so you can't create an SSH connection from H to W. Hmm... what can you do? You call technical support and for once, they have good news. They say that your company maintains a gateway or "bastion" host, B, that is accessible from the Internet and runs an SSH server. This means you should be able to reach W by opening an SSH connection from H to B, and then from B to W, since the firewall permits SSH traffic. Tech support gives you an account on the bastion host B, and the problem seems to be solved... or is it?For security reasons, the company permits access to its computers only by public-key authentication. So, using your private key on home machine H, you successfully connect to bastion host B. And now you run into a roadblock: also for security reasons, the company prohibits users from storing SSH keys on the exposed bastion host B, since they can be stolen if B were hacked. That's bad news, since the SSH client on B needs a key to connect to your work account on W. Your key is at home on H. (Figure 6-5 illustrates the problem.) What now? Figure 6-5

Figure 6-5. Bastion host scenario

Notice that this problem doesn't arise with telnet or rsh. You'd simply type your password to reach W (insecurely, of course).[86] For a solution, we turn to SSH agents and agent forwarding.
[86]This key-distribution problem can also be solved with network file-sharing protocols, such as NFS, SMB, or AFP, but these aren't usually available in the remote-access situation we're discussing.
SSH agent forwarding allows a program running on a remote host, such as B, to access your ssh-agent on H transparently, as if the agent were running on B. Thus, a remote SSH client running on B can now sign and decrypt data using your key on H as shown in Figure 6-6. As a result, you can invoke an SSH session from B to your work machine W, solving the problem. Figure 6-6

Figure 6-6. Solution with SSH agent forwarding

How agent forwarding works

Agent forwarding, like all SSH forwarding ("Port Forwarding and X Forwarding"), works "behind the scenes." In this case, an SSH client has its agent requests forwarded across a separate, previously established SSH session, to an agent holding the needed keys, shown in Figure 6-7. The transmission takes place over a secure SSH connection, of course. Let's examine, in detail, the steps that occur. Figure 6-7

Figure 6-7. How agent forwarding works

  1. Suppose you're logged onto machine X, and you invoke ssh to establish a remote terminal session on machine Y:

    # On machine X: $ ssh Y
    


  2. Assuming that agent forwarding is turned on, the client says to the SSH server, "I would like to request agent forwarding, please," when establishing the connection.
  3. sshd on machine Y checks its configuration to see if it permits agent forwarding. Let's assume that it's enabled.
  4. sshd on machine Y sets up an interprocess communication (IPC) channel local to Y by creating some Unix domain sockets and setting some environment variables. ["Single-shell method"] The resulting IPC mechanism is just like the one ssh-agent sets up. As a result, sshd is now prepared to pose as an SSH agent.
  5. Your SSH session is now established between X and Y.
  6. Next, from machine Y, you run another ssh command to establish an SSH session with a third machine, Z:

    # On machine Y: $ ssh Z
    


  7. This new ssh client now needs a key to make the connection to Z. It believes there's an agent running on machine Y, because sshd on Y is posing as one. So, the client makes an authentication request over the agent IPC channel.
  8. sshd intercepts the request, masquerading as an agent, and says, "Hello, I'm the agent. What would you like to do?" The process is transparent: the client believes it's talking to an agent.
  9. sshd then forwards the agent-related request back to the original machine, X, over the secure connection between X and Y. The agent on machine X receives the request and accesses your local key, and its response is forwarded back to sshd on machine Y.
  10. sshd on Y passes the response on to the client, and the connection to machine Z proceeds.
Thanks to agent forwarding, you have transparent access from machine Y to any SSH keys on machine X. Thus, any SSH clients on Y can access any hosts permitted by your keys on X. To test this, run this command on machine Y to list your keys:

# On machine Y: $ ssh-agent -l


You will see all keys that are loaded in your agent on machine X.It's worth noting that the agent-forwarding relationship is transitive: if you repeat this process, making a chain of SSH connections from machine to machine, then clients on the final host will still have access to your keys on the first host (X). (This assumes, of course, that agent forwarding is permitted by sshd on each intermediate host.)

Enabling agent forwarding

Before an SSH client can take advantage of agent forwarding, the feature must be turned on. SSH implementations vary in their default settings of this feature, and of course the system administrator can change it. If necessary, you can turn it on manually with the configuration keyword ForwardAgent[87] in the client configuration file ~/.ssh/config, giving a value of yes (the default) or no:
[87]SSH2 supports the keyword AllowAgentForwarding as a synonym for ForwardAgent.


# SSH1, SSH2, OpenSSH ForwardAgent yes


Likewise, you can use command-line options. In addition to the -o command-line option, which accepts any configuration keyword and its value:

# SSH1, SSH2, OpenSSH $ ssh -o "ForwardAgent yes" ...


The ssh option -a turns off agent forwarding:

# SSH1, SSH2, OpenSSH $ ssh -a ...


In addition, ssh2 and OpenSSH's ssh accept options to turn on agent forwarding, even though it's on by default:

# SSH2 only $ ssh2 +a ... # OpenSSH only $ ssh -A ...


Agent CPU Usage

Before we leave our discussion of agents, we'll make one final note about performance. Agents carry out all cryptographic work that would otherwise be done by SSH clients. This means an agent can accumulate substantial CPU time. In one case we saw, some friends of ours were using SSH1 for a great deal of automation, running hundreds of short-lived SSH sessions in a row. Our friends were quite puzzled to find that the single ssh-agent used by all these processes was eating the lion's share of CPU on that machine.