So yesterday I finally managed to get a reliable ssh-agent configuration which stores passphrases of your private keys inside the KWallet so that you don’t ever have to enter them again (for example when doing a git pull
).
Since I had failed at the task several times, and you find plenty of different ways to do it on the Internet (some of which seemed a bit clunky and outdated), I decided to become (hopefully) yet another Google search result. Hopefully this will be useful to someone.
First of all, I assume that some pre-requisites are met. You got your key pairs generated and your private keys are passphrase-protected.
Your ~/.ssh/config file should like something like this. You can (and should!) have different key pairs for different uses (I have a personal one and a work one, but you could even have one per domain).
Private key files can be called any way you like, you don’t have to necessarily call them id_25519 or whatever the default is. Just make sure your config file references valid private key files in the IdentityFile
property
The important bit here is the AddKeysToAgent yes
Host github.com
IdentityFile ~/.ssh/personal
AddKeysToAgent yes
Host *.repo.borgbase.com
IdentityFile ~/.ssh/personal
AddKeysToAgent yes
Host my.work.domain
IdentityFile ~/.ssh/work
AddKeysToAgent yes
Next, set up ssh-agent so that it starts at boot. We will create a user systemd unit.
mkdir -p ~/.config/systemd/user
echo '[Unit]
Description=SSH key agent
[Service]
Type=simple
Environment=SSH_AUTH_SOCK=%t/ssh-agent.socket
ExecStart=/usr/bin/ssh-agent -D -a $SSH_AUTH_SOCK
[Install]
WantedBy=default.target' >> ~/.config/systemd/user/ssh-agent.service
This requires the SSH_AUTH env variable to be set, so add it to your ~/.bash_profile:
echo '# For SSH agent systemd user unit
export SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/ssh-agent.socket"' >> ~/.bash_profile
(note: this env var is also exported inside the systemd unit above, I need to check if it’s really needed there, a bit of more testing is needed, as maybe it can be removed from the systemd unit file)
Now you should enable this service:
systemctl --user enable --now ssh-agent.service
Confirm ssh-agent is running via:
systemctl --user status ssh-agent.service
And check identities known/cached by the ssh-agent:
ssh-add -l
It should say that no identites are known at the moment.
Now thanks to the AddKeysToAgent yes
mentioned earlier, as soon as you need to unlock your private key, the agent will remember the passphrase (just as long as the process is alive, i.e. for the entire current session - unless it crashes)
You can confirm this with a git pull
, enter your passphrase when requested, then run again ssh-add -l
, and this time you should see something like:
256 SHA256:your public key fingerprint your@mail.com (ED25519)
Now if you do the same git pull
again, ssh-agent will provide the cached passphrase, so that you won’t be prompted again.
With this fairly simple setup you should already solve the major annoyance of having to re-type your passphrase every time. Now you only have to do that once per key per session logon. Nice!
All good so far? Let’s do the final step, so that you only have to enter it once, and let then KWallet take care of it for the rest of days.
Extra pre-requisite here: KWallet should be properly configured to auto-unlock at login.
To my knowledge, this happens automatically provided that:
the wallet file is called kdewallet
and it’s either NOT password protected (which is acceptable if your partition is encrypted, I guess) OR it’s protected with a password that matches the one of your user.
If these conditions aren’t met, I’d recommend to delete the wallet and recreate one so that they are.
Now just to make the explanation more relatable, so far you have set up ssh-agent to auto-start, you have configured ssh to feed passphrases to such agent once at least one successful key unlock has happened. What we are going to do is force the use of a different handler for collecting the passphrase from the user, when needed.
By default ssh uses standard input if the unlock attempt happened from the terminal, so we are gonna see how to force the use of a KDE UI instead.
The KDE UI part is crucial, because on top of showing an input field, it also features a magic checkbox that allows to remember the entered passphrase and store it inside the KWallet, for more than just this session. Makes sense? Let’s go!
Simply append these two lines to your ~/.bash_profile:
echo 'export SSH_ASKPASS="/usr/libexec/ssh/ksshaskpass" export SSH_ASKPASS_REQUIRE=prefer' >> ~/.bash_profile
The first one tells it to use the KDE UI to fetch the user input/passphrase, the second one forces it to do so even if the private key unlocking attempt came from a terminal (i.e. not a graphical app)
You will probably need to log-out/log-in again, or even reboot, to make this effective.
Once you are back in your session, you should see that:
ssh-add -l
says no identities known
If you do a git pull
again, this time the passphrase should be requested via a UI popup (that app is actually called ksshaskpass, and its executable location CAN vary depending on the distro! So if your distro has it elsewhere, make sure to adapt the path in your ~/.bash_profile)
The UI looks like this:
Be sure to check the Remember password
checkbox here!
Now you can verify that the ssh agent has your passphrase saved via:
ssh-add -l
, and it should also appear in your KWalletManager:
If you try to git pull
again, no passphrase will be requested. We had already achieved this.
But the cool thing is that, even if you reboot or re-login, you are also NOT prompted for the passphrase again, because the KDE Wallet will provide it from now on.
Any questions, feel free to ask.
Enjoy!