4
OS: Windows 11 Version 10.0.22621 Build 22621
WSL version: 1.2.5.0 (WSL 2)
Linux distro: Ubuntu 22.04.2 LTS

I run WSL2 on Windows 11 in a Windows Terminal window, and I often connect to a remote server through ssh key authentication. To do that, each time I open a new Windows Terminal window (or even just a new tab in an existing Terminal) I need to execute

eval "$(ssh-agent -s)"
ssh-add ~/.ssh/my_key

(it's a key without a passphrase). This gets old very quickly. Is there a way that I can automate the launch of the ssh agent, and the addition of my key to it, every time I start a WSL2 session in the Windows Terminal?

4
  • If it's without passphrase, do you need the agent at all, as opposed to having the ssh client load it directly from a file? Commented Sep 15, 2023 at 16:27
  • I feel I must be missing a nuance to your question -- You obviously know about adding commands to ~/.bashrc` as I see in your previous questions that you've been using WSL (as well as the Mac command-line) for a few years now. Commented Sep 15, 2023 at 19:03
  • @u1686_grawity maybe I don't need the agent. So what should I do?
    – DeltaIV
    Commented Nov 9, 2023 at 10:01
  • The agent is useful when you're using the option AddKeysToAgent. It gives you a "grace period", remembering the password for a specified time. I'm still trying to make this work on WSL, but it seems complicated. Commented Jan 10 at 18:38

3 Answers 3

5

Better Alternative (than original answer) based on having no passphrase on the keyfile

You asked about @u1686_grawity's comment:

If it's without passphrase, do you need the agent at all, as opposed to having the ssh client load it directly from a file?

@u1686_grawity makes a good point, and that's that most SSH clients will let you specify a keyfile directly without requiring an agent.

I often connect to a remote server through ssh key authentication.

You don't necessarily mention how you are connecting, but if it's with the stock ssh command, then you can simply specify your keyfile on the commandline with:

ssh -i ~/.ssh/my_key <username>@site

In that case, you don't need an ssh-agent running at all.

Even if you aren't using ssh-proper, most SSH tools that are based on OpenSSH will also use the same ~/.ssh/config, meaning you can even skip specifying the identity filename. For example, create a ~/.ssh/config with the following:

Host <whatever_you_want_to_call_it>
  Hostname <hostname_or_ip>
  User <optional_username_if_different>
  IntentityFile ~/.ssh/my_key

Then you can simply ssh <whatever_you_want_to_call_it> and everything else will be pulled from the config. Other tools like sftp and scp will also act the same.

Old Answer (works as well, but required for keys will passwords):

@Kolkhis's answer will certainly work, but if you run multiple shells (e.g., under Tmux or Windows Terminal), it will invoke a new running instance of ssh-agent for each shell. In your case, that's not too bad since your key doesn't have a password (although I would caution against that as well, of course). However, for keys with passwords, you have to enter it again for each shell you run. It will also incur additional (albeit small) startup time and memory.

I recommend the keychain utility by Daniel Robbins (also the creator of Gentoo Linux). This small utility checks to see if there's an existing ssh-agent running, and if so, it simply sets the appropriate environment variables to point to that agent. Otherwise, on first launch, of course, it will start a new agent.

It's available in the default repositories of most distributions, including Ubuntu:

sudo apt install keychain

Then add the following to your ~/.bashrc:

eval $(keychain --eval my_key)

IIRC, you don't even need to specify the path to the key unless it isn't in the the default ~/.ssh/.

4
  • since my key doesn't have a passphrase, is it possible to have the ssh client load it directly without using the ssh-agent? User @u1686_grawity suggested it, but I'm not sure how it works. Should I just add ssh-add ~/.ssh/my_key to the .bashrc?
    – DeltaIV
    Commented Nov 9, 2023 at 10:02
  • 1
    @DeltaIV Either way, you'll also need the ssh-agent line from the other answer in each shell invocation, so I still recommend keychain, which will prevent multiple copies from running. Commented Nov 10, 2023 at 12:57
  • @DeltaIV Ah, I see the comment you are referring to now. I'll edit my answer to add some detail there. Commented Nov 10, 2023 at 16:09
  • 1
    @DeltaIV And apologies - It seems likely that the suggestion that u1686_grawity made is the easiest. The rest of us (myself included) were overthinking it with the need for an agent. Commented Nov 10, 2023 at 16:26
6

The .bashrc solution proposed by others will spawn a new agent every time you open a new terminal window. I wanted to fix this without resorting to third-party tools. So this was my first attempt:

~/.bash_profile:

ssh_pid=$(pidof ssh-agent)

if [ "$ssh_pid" = "" ]; then
        eval "$(ssh-agent -s)"
fi

Unfortunately, in WSL every new terminal window spawns a new environment; and there's no way, as far as I know, to set the environment for all terminals.

I noticed the socket file previously pointed to by SSH_AUTH_SOCK still exists, and the agent is still running. That's good, and it shows we just need to fix the environment.

Here's the final solution, which preserves the original environment and restores it every time you open a new terminal:

~/.bash_profile:

ssh_pid=$(pidof ssh-agent)

# If the agent is not running, start it, and save the environment to a file
if [ "$ssh_pid" = "" ]; then
        ssh_env="$(ssh-agent -s)"
        echo "$ssh_env" | head -n 2 | tee ~/.ssh_agent_env > /dev/null
fi

# Load the environment from the file
if [ -f ~/.ssh_agent_env ]; then
        eval "$(cat ~/.ssh_agent_env)"
fi

This creates a file (~/.ssh_agent_env) to store the environment, and use it to reset the variables every time a new terminal is started. This ensures only one instance of the agent is running.

Also note that this code will not output anything - it's completely silent.

1
  • GitHub has published a similar solution in its documentation. I haven't tested it myself, but I see that it doesn't use eval (instead it "sources" the file containing the environment), and not even pidof (instead it parses the exit value of ssh-add -l) — so it looks neater. Commented Jul 13 at 17:28
2

You could simply add those two lines to your .bashrc file.

Open an instance of your WSL2, and put the following at the end of your ~/.bashrc. You can use any text editor to do this - vi/vim, ed, nano, etc.

eval "$(ssh-agent -s)"
ssh-add ~/.ssh/my_key

Alternatively, if you have a ~/.bash_aliases file, you could add it there instead.

After you've done that, you can use the command exec bash -l to reload bash and you'll be good to go.

2
  • Upvoted, but I'm going to propose a slightly different method in an answer ;-) Commented Sep 15, 2023 at 17:58
  • Right now, the problem with this is that the required environment variables (e.g. SSH_AGENT_PID, SSH_AUTH_SOCK) are emptied (lost) after you close the first terminal. You can kill the agent with killall ssh-agent, but you'll lose the keys stored in it, specially if they're added with the option AddKeysToAgent. Commented Jan 10 at 18:44

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .