Skip to content

Instantly share code, notes, and snippets.

@strarsis
Last active November 17, 2024 21:25
Show Gist options
  • Save strarsis/e533f4bca5ae158481bbe53185848d49 to your computer and use it in GitHub Desktop.
Save strarsis/e533f4bca5ae158481bbe53185848d49 to your computer and use it in GitHub Desktop.
KeeAgent (for KeePass) on Bash on Windows / WSL (2)

Update (March 2023) (Last checked: Oktober 2024)

Side note: The latest edge build of KeeAgent plugin offers an option for creating a WSL compatible socket. This would be very handy. I already tried to use that socket, but the socket file is currently empty and ssh inside WSL 2 is unable to use it. This appears to be a very new, unreleased and unstable feature. I will follow the development of it and when it finally works (well, for me) I will update this HOWTO. But until then, please use the proven wsl-ssh-agent/npiperelay.exe approach below.

Thanks to the instructions for WSL 2 of the wsl-ssh-agent project, KeeAgent works great in WSL 2 now: https://github.com/rupor-github/wsl-ssh-agent#wsl-2-compatibility The approach uses minimal and well-maintained tools.

Mini-changelog

  • 17.11.2024: Add: Add helpful troubleshooting note.
  • 29.10.2024: Add: Note about symptoms of npiperelay.exe not being found.
  • (28.10.2024)
    • Change: Fix apt install invocation for dos2unix package.
    • Change: Update wsl-ssh-agent release from 1.5.2 to 1.6.6.
    • Add: Use PPA for wslu package for bugfixed version of wslpath in Ubuntu LTS (24.04).
    • Add: Note what environment the commands/instructions should be run in (on Windows Host system or Linux/WSL system).
  • (16.03.2024) Add: Ensure 7z and wslvar being available (thanks @johnzielke).
  • (15.03.2024) Add: Note about issues with SSH key agent suddenly not working anymore due to issue with WSL 2 itself (Input/output error).
  • (03.03.2023) Change: Place the npiperelay.exe not onto the devfs filesystem, but rather Windows filesystem (thanks @NOBUTOKA) which fixes strange delays when using the SSH keys.

Installation/setup (proven/best approach (wsl-ssh-agent+npiperelay.exe))

  1. (on Windows system) Install the KeeAgent plugin for KeePass (2.x).
  2. (on Windows system) The OpenSSH Authentication Agent Windows service must be stopped. For being sure that it stays stopped, even after rebooting, disable the service (when it is stopped).
  3. (on Windows system) Open the KeeAgent options via KeePass Menu → Tools → Options → KeeAgent Tab. Enable the option Enable agent for Windows OpenSSH. Note: You may have to scroll down a bit in the list to find that option. A possible error message Windows OpenSSH agent is already running. KeeAgent cannot listen for Windows OpenSSH requests. can be ignored, everything will still work fine. (You may still find the Workarounds / troubleshooting section at the end of this HOWTO interesting). No socket files need to be created, the options can be left disabled.
  4. (on Linux/WSL system) Necessary step (thanks @jacobblock): socat must also be installed:
sudo apt install -y socat
  1. (Instructions below) Place the npiperelay.exe under the Windows filesystem (not onto the WSL system (devfs) filesystem! (thanks @NOBUTOKA)).

Place the npiperelay.exe under /usr/local/bin/npiperelay.exe inside your WSL 2 installation. It must be on the devfs filesystem, see https://github.com/rupor-github/wsl-ssh-agent#wsl-2-compatibility. Note on this change: Although the deprecated approach (of putting npiperelay.exe onto the devfs filesystem) still worked, it introduced strange delays. An user here noticed that placing npiperelay.exe onto the Windows filesystem (one can still symlink it into /usr/local/bin/ if one likes, not only didn't prevent it from running, but also fixed the delay. And indeed, the npiperelay repository itself states the opposite: The npiperelay.exe should be placed onto the windows filesystem, not onto devfs filesystem (interestingly, it would not have even run at that time as WSL hadn't supported running exe files in devfs, but apparently it also would introduce these delays).

Download instructions (thanks @musm; thanks @dmwyatt; thanks @johnzielke):

One suitable directory on the Windows filesystem can be C:\Users\<username>\wsl-keeagent\npiperelay.exe (%USERPROFILE%\wsl-keeagent\npiperelay.exe). (on Linux/WSL system) You can easily get the compatible path in WSL by using this handy command: wslpath "$(wslvar USERPROFILE)". Note that the version of wslpath command is outdated on Ubuntu LTS (22.04) (v3.2.3-1), and prints annoying warning messages. The wslu author recommends using the wslu PPA for the recent, bug-fixed version of wslpath.

# use the wslu PPA as the outdated `wslvar` version command prints annoying warning messages
sudo add-apt-repository -y ppa:wslutilities/wslu

# ensure wslvar is available (thanks @johnzielke)/upgraded
sudo apt update
sudo apt install -y wslu

# just to be sure the path is right
echo $(wslpath "$(wslvar USERPROFILE)"/wsl-keeagent)

# create dedicated directory on Windows filesystem
mkdir -p $(wslpath "$(wslvar USERPROFILE)"/wsl-keeagent/)

# Download release ZIP into /tmp
# Release v1.6.6
wget https://github.com/rupor-github/wsl-ssh-agent/releases/download/v1.6.6/wsl-ssh-agent.zip -P /tmp

# Ensure 7z is available (thanks @johnzielke)
sudo apt install -y p7zip-full

# Extract directly to the prepared Windows directory
sudo 7z e -y /tmp/wsl-ssh-agent.zip -o$(wslpath "$(wslvar USERPROFILE)"/wsl-keeagent/)

# Make the file executable
sudo chmod +x $(wslpath "$(wslvar USERPROFILE)"/wsl-keeagent/npiperelay.exe)

# (optional) Clean up downloaded ZIP file
rm /tmp/wsl-ssh-agent.zip

# Symlink `npiperelay.exe` back into `/usr/local/bin/npiperelay.exe`
sudo ln -s $(wslpath "$(wslvar USERPROFILE)"/wsl-keeagent/npiperelay.exe) /usr/local/bin/npiperelay.exe

# Ensure the `~/bin` directory is available for the script file in next step.
mkdir -p ~/bin

What if I followed this guide before this change (pre 3rd March 2023) and I already have npiperelay.exe at /usr/local/bin/npiperelay.exe? No problem, you can just move it out onto the Windows filesystem and even symlink it from there back to /usr/local/bin/npiperelay.exe, as this doesn't reintroduce the delay issue! See the instructions here

  1. (on Linux/WSL system) Create a new script file ~/bin/wsl-ssh-agent-forwarder (thanks @r2evans) with the following contents:
#!/bin/bash
# Usage: wsl-ssh-agent-forward [ -k | -r ]
# Options:
#    -k    Kill the current process (if exists) and do not restart it.
#    -r    Kill the current process (if exists) and restart it.
# Default operation is to start a process only if it does not exist.

export SSH_AUTH_SOCK=$HOME/.ssh/agent.sock

sshpid=$(ss -ap | grep "$SSH_AUTH_SOCK")
if [ "$1" = "-k" ] || [ "$1" = "-r" ]; then
    sshpid=${sshpid//*pid=/}
    sshpid=${sshpid%%,*}
    if [ -n "${sshpid}" ]; then
        kill "${sshpid}"
    else
        echo "'socat' not found or PID not found"
    fi
    if [ "$1" = "-k" ]; then
        exit
    fi
    unset sshpid
fi

if [ -z "${sshpid}" ]; then
    rm -f $SSH_AUTH_SOCK
    ( setsid socat UNIX-LISTEN:$SSH_AUTH_SOCK,fork EXEC:"/usr/local/bin/npiperelay.exe -ei -s //./pipe/openssh-ssh-agent",nofork & ) >/dev/null 2>&1
fi

Ensure the script (text) file uses proper UNIX (LF) line endings - especially when you create/edit that file from a Windows editor. You can ensure proper UNIX line endings by using the handy dos2unix tool: (e.g. install it using apt install -y dos2unix) dos2unix ~/bin/wsl-ssh-agent-forwarder. A telling symptom for incorrect line endings are errors like

command not found: ^M
command not found: ^M
parse error near `fi'

The bash script parser encountered characters that are used as line endings on non-UNIX systems, trying to interpret them and failing in the process. (thanks @jetzerb)

  1. Make the script executable: chmod +x ~/bin/wsl-ssh-agent-forwarder
  2. Add the following line to your .bashrc (~/.bashrc) to execute the script above:
# KeeAgent
. ~/bin/wsl-ssh-agent-forwarder

It is important that the script is sourced (. is shorthand for source), not just executed inside .basrc, as otherwise the exported environment variables would be used for the child process. The VSCode terminal is a case for this.

  1. Important: Ensure the socket file exists (even just as an empty placeholder file)!
mkdir -p $HOME/.ssh
touch $HOME/.ssh/agent.sock
  1. (Tip) Reload .bashrc config in current bash session:
source ~/.bashrc
  1. You can check the key agent functionality by either connecting via SSH or listing the keys with ssh-add -l (thanks @jacobblock). KeePass should automatically show the authentication prompt and/or notify that SSH keys have been accessed. Note: The KeePass program must be running when KeeAgent should be used. Turning on KeePass autostart could be a good idea.

Workarounds / troubleshooting

ssh-add -l

ssh-add -l is helpful for debugging as it simply tries to connect to the SSH Agent to list the available keys, reporting potential issues.

ssh suddenly doesn't use KeeAgent anymore / "Windows OpenSSH agent is already running" error message / TortoiseGit/TortoiseSVN

Once in a while I encounter the issue where ssh suddenly doesn't use KeeAgent anymore. The "Windows OpenSSH agent is already running" error message when closing/confirming the KeeAgent options dialog (KeePass Menu → Tools → Options → KeeAgent Tab) also appears then. This could be caused by a deeper, underlying issue: I noticed that this happens when updating TortoiseGit or TortoiseSVN (I have both installed). These tools also install their own version of PuTTY/Pageant - this may cause issues with KeeAgent which also tries to run its own SSH agent. Uninstalling TortoiseGit and TortoiseSVN appears to alleviate the issue. Of course, one still wants to use TortoiseGit and TortoiseSVN. An uninstall isn't necessary. It should be sufficient to just disable the PuTTY Pageant(s) that ships with TortoiseGit and TortoiseSVN, so they don't interfere with KeeAgent (and they aren't used anyway).

error fetching identities: communication with agent failed

Possible reasons (among others): /usr/local/bin/npiperelay.exe symbolic link not pointing to npiperelay.exe / npiperelay.exe not existing (anymore). Symptom: SSH keys not loaded from Kee Agent. error fetching identities: communication with agent failed when using ssh-add -l. Invoking the /usr/local/bin/npiperelay.exe -ei -s //./pipe/openssh-ssh-agent command from ~/bin/wsl-ssh-agent-forwarder executable script results in error: -bash: /usr/local/bin/npiperelay.exe: No such file or directory. ls /usr/local/bin/npiperelay.exe shows a problem with the symlink (printed in red). Ensure that the npiperelay.exe can be found at the expected path (on Windows file system) as described in the setup instructions. One underlying cause can be using [automount] root = / in /etc/wsl.conf which changes the external drive mounts from /mnt/n to /n, also changing the path to the npiperelay.exe on Windows file system. Sometimes simply invoking ~/bin/wsl-ssh-agent-forwarder -k multiple times to kill all existing processes and then re-sourcing the bashrc or restarting bash can fix the issue.

ssh asks for (private key) passphrase

If Kee Agent is not used for SSH keys, ssh falls back to local key files (in ~/.ssh). Kee Agent can also handle passphrases of private keys. As a fallback, an existing, local private key file is used, that has a passphrase, a passphrase is then prompted for.

~/bin/wsl-ssh-agent-forwarder

The ~/bin/wsl-ssh-agent-forwarder script can also be manually invoked with a -r or -k paramter. -r makes it restart the SSH agent forwarding process, while -k kills it without restarting it (see the script comments). When the SSH client has issues using the forwarded SSH agent, using wsl-ssh-agent-forwarder with -r and -k (and restarting/reloading the shell) can fix those issues without the need for rebooting the whole system.

WSL 2 I/O issue

From time to time WSL 2 I/O may simply stop working (unrelated to SSH agent/KeeAgent), until WSL 2 is restarted or the whole system is rebooted. Often the internal VSCode-WSL connection also starts hanging shortly thereafter. When accessing files on non-WSL filesystems, this error then occurs: Input/output error. You can easily check whether this happens, simply by accessing npiperelay.exe, e.g. ls /usr/local/bin/npiperelay.exe. When you get an Input/output error, then WSL 2 or the system has to be rebooted in order to fix this. The SSH Agent usually also stops working until the I/O issue is resolved.

reboot

Some issues (probably some stuck process or socket or pipe) can be fixed by simply rebooting the sytem.

Errata

npiperelay.exe should actually not be used from a devfs filesystem

What if I followed this guide before this change (pre 3rd March 2023) and I already have npiperelay.exe at /usr/local/bin/npiperelay.exe? No problem, you can just move it out onto the Windows filesystem and even symlink it from there back to /usr/local/bin/npiperelay.exe, as this doesn't reintroduce the delay issue!

# just to be sure the path is right
echo $(wslpath "$(wslvar USERPROFILE)"/wsl-keeagent)

# create dedicated directory on Windows filesystem
mkdir -p $(wslpath "$(wslvar USERPROFILE)"/wsl-keeagent/)

# Move `npiperelay.exe` from the `devfs` filesystem to Windows filesystem
sudo mv /usr/local/bin/npiperelay.exe $(wslpath "$(wslvar USERPROFILE)"/wsl-keeagent/)

# (optional) Change file ownership back from `root` to the normal user
sudo chown $USER npiperelay.exe

# Symlink `npiperelay.exe` back into `/usr/local/bin/npiperelay.exe`
sudo ln -s $(wslpath "$(wslvar USERPROFILE)"/wsl-keeagent/npiperelay.exe) /usr/local/bin/npiperelay.exe

Thanks to the symlink, nothing else (like paths) needs to be changed. You are done here, the fix is applied and the delays should be fixed now. No need to reload or restart either, as the binary is invoked each time, hence the next time the SSH agent is used, the binary at new location is used instead, which should fix the delay.

Note: Comments below may relate to the outdated Howto for WSL 1 and msysgit2unix-socket.py!

@NOBUTOKA
Copy link

I found the solution for this delay issue.
Do NOT place npiperelay.exe in /usr/local/bin/ or other directory inside WSL.
Instead, place it under directory inside the Windows file system, such as /mnt/c.
If you want, create simlink to npiperelay.exe in /usr/local/bin.
The delay will be disappeared.

Refer: jstarks/npiperelay#26

@strarsis
Copy link
Author

strarsis commented Feb 21, 2023

@NOBUTOKA: That's interesting! Because basically the opposite is known to work/recommended: That npiperelay.exe should be placed inside /usr/local/bin/ or at least on the devfs filesystem in WSL. So these changes improved the performance for you? And it works? 🤔

@NOBUTOKA
Copy link

@strarsis Yes, it works for me.
I had experienced 5 seconds delay in every single ssh access while npiperelay is placed under /usr/local/bin directly,
and after it placed under /mnt/c, there is no delay.

@tueur-a-gage
Copy link

@strarsis, same things for me, npiperelay.exe was on /usr/local/bin as indicated, and since around 1 month (windows update ??) it was very slow. By putting it on /mnt/c/...somewhere and do a symbolic link as indicated by @NOBUTOKA no it works fine.
Many thanks for the trick !

@GlucNAc
Copy link

GlucNAc commented Feb 27, 2023

@strarsis Thanks for the tip it also help me to stop the freezing!

Otherwise, I've made a script to install the connection between my Debian distro and Windows SSH agent : https://gitlab.com/GlucNAc/wsl-use-windows-ssh-agent/-/blob/master/use_windows_ssh_agent.sh

Another interesting point is that you can use Docker images as WSL distro. So I've made a Debian slim docker image with that connection to windows SSH agent, and then I've install it as a WSL2 distro using this script : https://gitlab.com/GlucNAc/wsl-install-docker-image-as-distro/-/blob/master/load_and_run_docker_image_as_wsl_distro.bat.

In that way, no need to make an Ansible script or a custom shell script to install my set up :)

@strarsis
Copy link
Author

strarsis commented Mar 3, 2023

@NOBUTOKA, @tueur-a-gage, @GlucNAc, @antoniozh, @fracaron, @Bond246, @sdettmer:
Important update!
There were contradicting information on where to put the npiperelay.exe, either it has to be on the devfs filesystem or on the Windows filesystem.
It turns out that a) it can be now put onto the Windows filesystem without preventing its proper functionality and b) it should be actually put onto the Windows filesystem as this prevents the strange delay issues some users (including me) experienced (thanks @NOBUTOKA).

The guide as updated to reflect this (step 5), including extra instructions for those who already put the npiperelay.exe into the devfs filesystem, prior to this update:
https://gist.github.com/strarsis/e533f4bca5ae158481bbe53185848d49#:~:text=What%20if%20I%20followed%20this%20guide%20before%20this%20change
It is very simple to change and indeed, the delays went away.

@airtonix
Copy link

does this support the use of security keys like yubikey with the ssh key stored as a resident key?

setting that up is described here:

https://www.stavros.io/posts/u2f-fido2-with-ssh/

@johnzielke
Copy link

Just as a small comment, maybe consider adding sudo apt install p7zip-full wslu to the npiperelay script. Otherwise there are errors during execution and the symlink created points to an invalid location, which then needs to be manually created

@strarsis
Copy link
Author

@johnzielke: Thanks for these improvements! You can see the addition here.

Where should the wslu package installation be added? I assume that the wslu package is required for the wslpath command.
In the instructions above it is assumed that the command is wslpath, while the wslu package provides the wslupath command (both appear to be functionally equal).

@johnzielke
Copy link

johnzielke commented Mar 16, 2024 via email

@strarsis
Copy link
Author

strarsis commented Mar 16, 2024

provides the wslvar command

This makes sense, I added the commands with sudo. Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment