Expose Windows SSH-Agent inside WSL environments
Is your feature request related to a problem? Please describe.
I often use SSH keys for authentication. Basically, whenever I want to connect to another server or clone a repository on GitHub, I use SSH. I am always frustrated when I cannot clone a repository or connect to one of my servers from within WSL. I would love to be able to access the SSH agent which runs outside WSL from within all of my WSL instances.
Describe the solution you'd like
- Expose a unix domain socket at
/mnt/wsl/ssh-agentor/mnt/wslg/ssh-agent. (Since you are already exposing various sockets within/mnt/wslg/, I assume this should be possible?) - When a client connects to
/mnt/wsl[g]/ssh-agent, try to connect to the named pipe provided by the ssh-agent of Windows. Forward all traffic in both directions.- If the environment variable
SSH_AUTH_SOCKis defined outside the WSL environment, it should point to a named pipe. This is the named pipe you should use. - I am not sure if there is a fallback which should be used if the environment variable is not set.
- If the environment variable
- Set environment variable
SSH_AUTH_SOCKwithin WSL to/mnt/wsl[g]/ssh-agent. (You may skip this step if you cannot control the environment variables inside WSL.)
Note: I am not sure if there are security considerations which need to be made. If possible, /mnt/wsl[g]/ssh-agent should probably only be accessible by the main user of the Linux distro. Besides, my understanding was that using WSL was not really supported in a context where strict isolation of different users on one Windows installation is required.
Describe alternatives you've considered
As far as I am aware, there are currently three noteworthy protocols for SSH agents on Windows. Here are the three corresponding applications:
- Native ssg-agent for Windows
- MSYS2 ssh-agent
- Pageant (PuTTY authentication agent)
I assume that the native ssh-agent and the ssh-agent of MSYS2 are technically using the same protocol, but just a different transport layer. While the ssh-agent of Windows is using named pipes, MSYS2 is using their compatibility layer for unix domain sockets.
While it would be technically possible to implement a solution for each of the three agents, relying on the protocol of the native ssh-agent seems to be the most straightforward solution. For supporting MSYS2, we would first need to implement the relevant parts of the MSYS2 compatibility layer. For Pageant, we may have to implement some protocol translation layer. Also note that Pageant already supports the native ssh-agent protocol.
The biggest problem I see is that the ssh-agent from Windows and MSYS2 are both using the same environment variable SSH_AUTH_SOCK. This naming conflict means that you cannot use the ssh-agent of Windows if you are also using some ssh-agent for MSYS2. This is especially annoying because Git for Windows uses the ssh client of MSYS2 by default. The Git installer technically asks you if you want to use the native ssh client instead, but I have never tried it. I am not sure if “forcing” users to the native client if they want to benefit from this feature may have unfortunate side effects. If the relevant parts of the MSYS2 compatibility layer are easy to implement, it might make sense to support it as well.
Note: I am currently using Pageant and the script cmd/start-ssh-pageant.cmd which comes with Git for Windows. This means, on my system, SSH_AUTH_SOCK currently points to a unix domain socket of MSYS2. This means I would also be affected by the problem I just described.
There was also #10512 which suggested to automatically start an ssh-agent with WSL. The ticket was closed because starting an ssh-agent inside WSL would be the responsibility of the Linux distribution. Besides, it would also be far less useful as you would still have to set up an SSH-key for each WSL-instance separately. This feature request strives to make SSH work out of the box in all WSL instances if you have some ssh-agent enabled on Windows.
Additional context
- Some official documentation about how to start the SSH agent in windows.
https://learn.microsoft.com/en-us/windows-server/administration/openssh/openssh_keymanagement#user-key-generation - Pageant did support exposing the agent to WSL1, but the solution doesn't work with WSL2.
https://the.earth.li/~sgtatham/putty/0.80/htmldoc/Chapter9.html#pageant-cmdline-unix - There were also third party implementations for WSL1, which stopped working with WSL2 due to #5961. See https://github.com/benpye/wsl-ssh-pageant/issues/33 for example.
- There are also third-party solutions for WSL2, but I have never tried them. They are also a bit annoying to set up for each WSL instance. https://github.com/BlackReloaded/wsl2-ssh-pageant https://github.com/rupor-github/wsl-ssh-agent#wsl2-compatibility
Hi I'm an AI powered bot that finds similar issues based off the issue title.
Please view the issues below to see if they solve your problem, and if the issue describes your problem please consider closing this one and thumbs upping the other issue to help us prioritize it. Thank you!
Open similar issues:
- SSH from WSL (#5017), similarity score: 0.75
Closed similar issues:
- Is ssh-agent working in WSL? (#3206), similarity score: 0.81
- About WSL'ssh (#2811), similarity score: 0.72
- ssh session into WSL cannot execute windows binaries (#2414), similarity score: 0.72
- Error Running WSL Ubuntu SSH from a Windows Service (#2858), similarity score: 0.72
Note: You can give me feedback by thumbs upping or thumbs downing this comment.
Workaround: https://medium.com/@wondrous_oxblood_cheetah_508/ssh-agent-on-windows-c74b90fb2e31
TL;DR: If you simply looking to use git with windows SSH keychain simply run the following inside WSL: (assuming you already have enabled windows SSH)
git config --global core.sshcommand /mnt/c/Windows/System32/OpenSSH/ssh.exe
@samuelhnrq That doesn't help other SSH commands like SSH to a server, SCP, etc
my workaround:
$ cat ~/bin/ssh
#!/bin/sh
if [ -n "${SSH_TEST}${GIT_TEST}" ]
then
exec /bin/ssh "$@"
else
exec '/mnt/c/Windows/System32/OpenSSH/ssh.exe' "$@"
fi
$ cat ~/bin/ssh-add
#!/bin/sh
if [ -n "${SSH_TEST}${GIT_TEST}" ]
then
exec /bin/ssh-add "$@"
else
exec '/mnt/c/Windows/System32/OpenSSH/ssh-add.exe' "$@"
fi
TL;DR: If you simply looking to use git with windows SSH keychain simply run the following inside WSL: (assuming you already have enabled windows SSH)
git config --global core.sshcommand /mnt/c/Windows/System32/OpenSSH/ssh.exe
For some strange reason, this didn't work for me. But using the plink.exe executable from Putty did. This also works for rsync (by setting RSYNC_RSH to plink).
EDIT: it turns out this does not work reliably. I ran into a bunch of errors during the transfer. I had to give up on this approach.
Most of the workarounds floating around are just different ways of using the interop binding to call ssh.exe. You can manually type ssh.exe instead of ssh, configure your app to use ssh.exe directly, define shell aliases, or create symbolic links. None of that solves the problem completely because ssh.exe won't work if you need to use ssh with a control file. That is a blocker for Ansible usage in WSL when the key is stored in the ssh agent on Windows.
Only one technique I've found so far creates a socket in WSL to the ssh agent on Windows. That technique uses socat to bridge the gap with npiperelay.exe.
Here are the basic steps that I used:
-
Prepared the Windows side:
- Install npiperelay:
winget install --id albertony.npiperelay --exact - Start SSH agent:
Set-Service -Name ssh-agent -StartupType Automatic -Status Running
- Install npiperelay:
-
Prepared the WSL side:
- Install socat:
sudo apt install socat - Make sure
~/.sshexists:mkdir -p ~/.ssh - Create
/etc/profile.d/wsl-ssh-agent.sh:
#!/usr/bin/env sh export SSH_AUTH_SOCK="$HOME/.ssh/agent.sock" # Exit if socket already exists and is a valid socket if ss -a | grep -q "$SSH_AUTH_SOCK"; then return fi # Remove the stale socket, if it exists rm -f "$SSH_AUTH_SOCK" # Launch socat/npiperelay as a background process setsid socat \ UNIX-LISTEN:"$SSH_AUTH_SOCK",fork \ EXEC:"npiperelay.exe -ei -s //./pipe/openssh-ssh-agent",nofork \ >/dev/null 2>&1 - Install socat:
Source: https://programmaticdreams.com/posts/sharing-ssh-agent-between-windows-and-wsl/
@FlippingBinary - thank you for outlining this approach. I've nearly had to give up on WSL as a working environment due to this issue ever since my org adopted YubiKey authentication. Some devs I know are switching to Macs just so they can get a fully integrated solution for SSH and GNU tools - I haven't quite reached that point yet myself. But until WSL deals with this, it's a huge gaping hole. Ssh-ing from an Xterm in WSL used to work just fine for Emacs running in TMUX sessions on a remote server. I spent a good week or two getting the Windows Terminal to do the same thing (essentially removing all of the default key bindings and setting a few new ones for those Alt+Shift+Ctrl etc commands). The solution works but it was a pain and shouldn't be necessary. I considered going back to Msys2 (which I used for a long time up until WSL came out) and seeing if I could get a version of rsync going that uses the Windows version of OpenSSH, but decided not to invest time in that.
TL;DR: If you simply looking to use git with windows SSH keychain simply run the following inside WSL: (assuming you already have enabled windows SSH)
git config --global core.sshcommand /mnt/c/Windows/System32/OpenSSH/ssh.exe
This only works for me on Git commands that open a SSH connection to a remote, such as push and pull. But it sadly does not work when using a SSH key for signing commits. Git fails with error: No private key found for public key "/path/to/public/key", even though the key is present in the Windows SSH-Agent.
Update: Git uses ssh-keygen for signing. Thanks to grawity for bringing some clarity. Telling git which program it should use for signing fixes this problem:
git config --global gpg.ssh.program /mnt/c/WINDOWS/System32/OpenSSH//ssh-keygen.exe
I just use SSH to forward the SSH agent from Windows to WSL. This works without npiperelay or anything like that