(basic) SSH Keys Part 2: Agent forwarding, Adding Keys

There's a million and one things you can do with ssh keys, but as a non-power-user I find 99% of the time I'm either trying to get a shell on a different machine or moving a file between machines I trust. So for a long time I didn't really touch ssh configuration.

But it's always good to make brief exceptions to laziness to quickly check whether you could be more lazy, and there are plenty of nice ways to save yourself some typing and fuss sprinkled around.

For simple added SSH key quality of life for someone new to using keys, there are two configuration keywords in particular you might enjoy trying out first.

Here's my setup for a jump through a proxy to a machine in my home:

Host simurgh
ProxyJump jumphost.example.com
ForwardAgent yes
AddKeysToAgent yes

ForwardAgent will allow the remote destination to use the ssh agent on my local machine, rather than needing to supply keys of its own. I don't keep any keys on this remote host, and this means I won't miss them.

AddKeysToAgent will add the key used to make this connection to my ssh agent, so I will have continued access to it for other purposes. (You can specify a lifetime or expiration if you prefer).

Taken together, these allow me the flexibility to connect from this remote machine outward without thinking too hard about it, or to repeatedly connect from the local to the remote machine during a work session without having to type passphrases until I'm ready to throw things.

If you're a newer user who maybe only has one or two machines under your control, though, using ForwardAgent in particular will mean you won't need to store private keys on any hosts you don't own to reap their benefits, which might make you feel more comfortable experimenting with more interesting ways to use them!


To take advantage of those two keywords, we will need a running ssh agent process on the local machine. An ssh agent holds private keys to be used automatically for authentication. This can be safer than using keys generated without passphrases, since you'll need to provide your passphrase to add the key to the agent, but it can make actual use of keys much more convenient.

If you logged into your local machine with xenodm, you may already have keys in your ssh agent available to forward and a running agent collecting any new ones you use. In that case, our setup above likely already works and you will be able to use your keys on the remote machine as soon as you connect, yay!

But if you're working in the terminal or otherwise have not made available the key you want, you'll need to load keys into your ssh agent. To walk through this we'll need ssh-agent(1) running, and we'll either use ssh-add(1) directly or take advantage of making ssh connections configured with AddKeysToAgent.

Let's first see how a connection works without those last two configuration lines using our two new keywords. Here, we're simply connecting through the jump host for a no-frills ssh session using a key.

valefor$ ssh simurgh    
Enter passphrase for key '/home/pamela/.ssh/id_ed25519': 
Enter passphrase for key '/home/pamela/.ssh/id_ed25519':

Ehhh. I don't know about this. Because both the jump host and the destination machine need to be checked against my key, I'll have to provide passphrases for both legs of the connection. I'm going to move a whole bunch of stuff back and forth today. One side needs more cute hippo pictures; the other side needs more reaction gifs starring angry elephants... I may be at this a while. I'm not going to type my passphrase in twice each time I connect!

Let's first make sure ForwardAgent and AddKeysToAgent are both set to "yes" for the connection we wish to make in the config file, as shown in the first section.

Are there any keys in the local ssh agent to start? You can get this list using ssh-add -L (and empty it with -D again to experiment).

valefor$ ssh-add -L
Could not open a connection to your authentication agent.

OK, we don't have an ssh agent running at all! So let's get that going.

valefor$ ssh-agent  
SSH_AUTH_SOCK=/tmp/ssh-Ns6XKrcJ2DZc/agent.17087; export SSH_AUTH_SOCK;
echo Agent pid 71952;

As explained in ssh-agent(1), these are the shell commands we need to set the environment variables and set up our agent. But this isn't going to do us much good for our purposes; it's not meant to be run like this and used to authenticate repeatedly. Instead, let's try using "eval" as described in the manual.

valefor$ eval `ssh-agent`
Agent pid 13373

Now we have actually used what ssh-agent gave us, rather than just admiring it once, and we have a running agent, ready for keys. A process can't change the environment variables of its parent process, so any direct use of ssh-agent (i.e. "ssh-agent ksh" to open a new shell with these settings) will only apply to that one process and its children. Evaluating these commands instead allows us to load the environment variables ssh-agent gave us and then continue on to issue other commands as we like, with ongoing access to our agent.

Remember how I said you could look at /etc/X11/xenodm/Xsession to see how xenodm loads in keys upon login? That's done using eval, too, and your keys will be available to you in every fresh xterm window you open! If you're planning to connect via shell and want to be able to use an agent every time, you could even add eval 'ssh-agent' to your .profile (though this will also kill attempts to forward a different ssh agent if you later connect to this machine remotely, so it's probably not a great default).

Adding keys to ssh-agent

valefor:~$ ssh-add -L
The agent has no identities.

The agent is running on the local machine now, but it's empty. I'll use ssh-add to provide identities to the agent, teaching it about some of the private keys this machine holds.

valefor:~$ ls .ssh/        
authorized_keys config          id_ed25519.pub  id_rsa.pub
backups.pub     id_ed25519      id_rsa          known_hosts

valefor:~$ ssh-add         
Enter passphrase for /home/pamela/.ssh/id_rsa: 
Identity added: /home/pamela/.ssh/id_rsa (pamela@valefor.blah)
Identity added: /home/pamela/.ssh/id_ed25519 (pamela@valefor.blah)

You can specify particular keys with ssh-add private-key-file to add them individually, or simply running ssh-add by itself will load in the usual (i.e. default) suspects for you automatically. There are now two different private keys known to my ssh agent, and if I ssh to a host where one of these keys is authorized, barring specialty settings on either side, I'll simply be ushered directly to a remote prompt like a hecking VIP!

Now, let's try emptying out the agent and instead add a key automatically by using the AddKeysToAgent keyword we specified in that first configuration file.

valefor:~$ ssh-add -D
All identities removed.

Connecting to remote host "simurgh" should automatically furnish the key we use for the connection to our local agent because of AddKeysToAgent, and let us use the key there as well, thanks to ForwardAgent. Let's go ahead and connect to the remote host, and look at what these two handy configuration lines have done for us.

valefor:~$ ssh simurgh
Enter passphrase for key '/home/pamela/.ssh/id_ed25519': 
Enter passphrase for key '/home/pamela/.ssh/id_ed25519': 
Last login: Tue Aug 11 01:31:04 2020 from
OpenBSD 6.7 (GENERIC.MP) #3: Tue Aug 11 09:21:14 MDT 2020

Welcome to OpenBSD: The proactively secure Unix-like operating system.

Please use the sendbug(1) utility to report bugs in the system.
Before reporting a bug, please try to reproduce it with the latest
version of the code.  With bug reports, please try to ensure that
enough information to reproduce the problem is enclosed, and if a
known fix for it exists, include that as well.

simurgh$ ssh-add -L
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII42PVL153xszd1SLBiNB7fTwQvIa8HKXxymx5JBbUZz    pamela@valefor.blah

Yay! We had to type the passphrase because the key we needed wasn't already in the agent, but the local agent is being forwarded successfully. I can now connect from simurgh to anywhere this particular key grants me access. But will the key that was added when we made this connection stick around even after the connection closes?

simurgh$ exit
Connection to closed.

valefor:~$ ssh-add -L
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII42PVL153xszd1SLBiNB7fTwQvIa8HKXxymx5JBbUZz    pamela@valefor.blah

Yep, loaded into the agent and ready for the next use. I won't need to type my passphrase if I connect to simurgh a second time. My agent will handle authentication for me for as long as it holds that particular key.

If I connect somewhere else using ForwardAgent now, my key (and any others my agent might hold at that point) will be available for that remote host's use, even if it wasn't the key used to authenticate that session. This can really come in handy both from an "I don't want to think about which key I use where" perspective, and for working with more complex configurations to suit your specific needs and habits.

There are many options and directives you can play with, but hopefully this gives you something simple and useful to try out when first setting up a workflow using ssh keys.