Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for WSL2 #33

Open
AngellusMortis opened this issue Dec 10, 2019 · 44 comments
Open

Support for WSL2 #33

AngellusMortis opened this issue Dec 10, 2019 · 44 comments

Comments

@AngellusMortis
Copy link

According to a similar project, rupor-github/wsl-ssh-agent#3, it seems this is not possible yet, but I just wanted to make an issue to cover it for anyone else was doing some digging.

It seems that the Windows/Unix socket interoperability does not work yet for WSL 2.

@benpye
Copy link
Owner

benpye commented Feb 2, 2020

Thanks for the issue @AngellusMortis , I am aware of this limitation. There is a workaround currently which works with npiperelay and the Windows SSH support. It's possible to bridge Pageant to Windows SSH and then use npiperelay to bridge that into WSL 2. If there is interest this could possibly be added in the tool itself, what do you think?

@pearj
Copy link

pearj commented Mar 23, 2020

@benpye How do I run npiperelay correctly?

I have tried this

joel@JOEL-XPS15:/mnt/c/Users/Joel$ socat UNIX-LISTEN:/home/joel/.ssh/authsock,fork,group=joel,umask=007 EXEC:"npiperelay.exe -ep -s //./pipe/ssh-pageant",nofork
/usr/local/bin/npiperelay.exe: Invalid argument

But whenever I try to use the agent I get a /usr/local/bin/npiperelay.exe: Invalid argument error.

I have this: export SSH_AUTH_SOCK=/home/joel/.ssh/authsock as well

What's the magic syntax?

@benpye
Copy link
Owner

benpye commented Apr 8, 2020

Woops! I totally forgot about this thread. I use the following command line - I guess you need to pass the full path to npiperelay.exe.

socat EXEC:"/mnt/c/Users/benpy/go/bin/npiperelay.exe /\/\./\pipe/\ssh" UNIX-LISTEN:/tmp/wsl-ssh-pageant.socket,unlink-close,unlink-early,fork

@pearj
Copy link

pearj commented Apr 11, 2020

Ahh awesome thanks. I think it turned out "Invalid argument" was because I was trying to run windows binaries from a windows working directory. You can see I was using /mnt/c/Users. When I changed to the Linux home directory it worked fine.

Out of interest how do you start socat? I tried to get systemd to run it for me, but it just keeps crashing.

I have:

[Service]
User=joel
Type=Simple
ExecStart=/usr/bin/socat -u EXEC:"/mnt/c/Users/Joel/go/bin/npiperelay.exe //./pipe/ssh-pageant" UNIX-LISTEN:/tmp/wsl-ssh-pageant.socket,unlink-close,unlink-early,fork  

But it dies with:

Apr 11 23:03:23 JOEL-XPS15 systemd[1]: Started ssh-agent-socat.service.
Apr 11 23:03:23 JOEL-XPS15 socat[3045]: 2020/04/11 23:03:23 socat[3045] E waitpid(): child 3046 exited with status 1
Apr 11 23:03:23 JOEL-XPS15 systemd[1]: ssh-agent-socat.service: Main process exited, code=exited, status=1/FAILURE
Apr 11 23:03:23 JOEL-XPS15 systemd[1]: ssh-agent-socat.service: Failed with result 'exit-code'.

@pearj
Copy link

pearj commented Apr 11, 2020

I've added this to my ~/.bashrc

if [ ! -S /tmp/wsl-ssh-pageant.socket ] && [ -z "$TMUX" ]; then
    echo "Starting socat relay to ssh-pageant"
    tmux new-session -d -s socat-ssh-agent
    tmux send-keys '/usr/bin/socat EXEC:"/mnt/c/Users/Joel/go/bin/npiperelay.exe //./pipe/ssh-pageant" UNIX-LISTEN:/tmp/wsl-ssh-pageant.socket,unlink-close,unlink-early,fork' C-m
fi

export SSH_AUTH_SOCK=/tmp/wsl-ssh-pageant.socket

Using tmux seems a bit blah, but it gets the job done. Simply backgrounding the socat command in the ~/.bashrc with & was making VSCode hang when starting up inside WSL 2

@florin-saftoiu
Copy link

florin-saftoiu commented Jun 8, 2020

Adding this to ~/.bashrc

kill -9 $(ps x | grep npiperelay | grep -v grep | awk '{ print $1 }')
setsid nohup socat EXEC:"/mnt/c/work/ssh/npiperelay/npiperelay.exe /\/\./\pipe/\ssh-pageant" UNIX-LISTEN:/tmp/wsl2-ssh-agent.sock,unlink-close,unlink-early,fork >/dev/null 2>&1 &
export SSH_AUTH_SOCK=/tmp/wsl2-ssh-agent.sock

seems to work for me, both in Windows Terminal and VSCode

@Pumba98
Copy link

Pumba98 commented Jun 9, 2020

I struggeled much to get this working. I found out that my pipe, that needs to be passed to npiperelay, had a different name.
You can use this powershell command to check which pipes with "ssh" in name exist on your system.
[System.IO.Directory]::GetFiles("\\.\\pipe\\") | Select-String -Pattern ssh
for me it was \\.\\pipe\\openssh-ssh-agent

@tombowditch
Copy link

WSL v2 is public builds now (may update, ver 2004). Is this limitation still a factor? Since updating to WSLv2 I'm just getting public key permission denied to my servers (i.e. it isn't working!)

@GuyPaddock
Copy link

GuyPaddock commented Jul 21, 2020

The only two issues I have with #33 (comment) are that:

  1. WSL hangs when trying to close WSL windows (you have to CTRL+C to get it to close)
  2. The first WSL window that gets opened displays this warning:

    kill: usage: kill [-s sigspec | -n signum | -sigspec] pid | jobspec ... or kill -l [sigspec]

To solve issue 2, I am using this:

EXISTING_RELAY_PIDS=$(ps x | grep npiperelay | grep -v grep | awk '{ print $1 }')

if [[ ! -z "${EXISTING_RELAY_PIDS}" ]]; then
  kill -9 ${EXISTING_RELAY_PIDS}
fi

setsid nohup socat \
  EXEC:"/mnt/c/Users/MY_USERNAME/bin/npiperelay.exe /\/\./\pipe/\ssh-pageant" \
  UNIX-LISTEN:/tmp/wsl2-ssh-agent.sock,unlink-close,unlink-early,fork >/dev/null 2>&1 &

export SSH_AUTH_SOCK=/tmp/wsl2-ssh-agent.sock

@GuyPaddock
Copy link

GuyPaddock commented Jul 21, 2020

This variant of #33 (comment) worked better for me, and avoids the hang-at-close:

EXISTING_RELAY_PIDS=$(ps x | grep npiperelay | grep -v grep | awk '{ print $1 }')

if [[ -z "${EXISTING_RELAY_PIDS}" ]]; then
  socat \
    EXEC:"/mnt/c/Users/MY_USERNAME/bin/npiperelay.exe /\/\./\pipe/\ssh-pageant" \
    UNIX-LISTEN:/tmp/wsl2-ssh-agent.sock,unlink-close,unlink-early,fork >/dev/null 2>&1 &
fi

export SSH_AUTH_SOCK=/tmp/wsl2-ssh-agent.sock

@ghost
Copy link

ghost commented Jul 26, 2020

@GuyPaddock I'm using your variant, but when I try to ssh to somewhere within WSL, socat exits:

voltagex@Argentum:/mnt/c/Users/Adam$ ssh 10.1.1.2
[email protected]: Permission denied (publickey).
[1]+  Exit 1                  socat EXEC:"/mnt/c/Users/Adam/OneDrive/bin/npiperelay.exe /\/\./\pipe/\ssh-pageant" UNIX-LISTEN:/tmp/wsl2-ssh-agent.sock,unlink-close,unlink-early,fork > /dev/null 2>&1

@GuyPaddock
Copy link

@voltagex Yeah, I'm seeing that too... not sure why socat isn't staying open.

@Vashiru
Copy link

Vashiru commented Jul 28, 2020

I just noticed @ BlackReloaded has sort of forked/borrowed some code from @benpye's project specifically for WSL2 (using socat): https://github.com/BlackReloaded/wsl2-ssh-pageant. That setup works for me. Just note that the docs say $HOME/.ssh/ than just the home directory (took me a couple of reads to pick up on that).

Mind you I'm using it with https://smartcard-auth.de/index-en.html for pageant in order to support my Yubikey.

@ckuai
Copy link

ckuai commented Aug 3, 2020

I just noticed @ BlackReloaded has sort of forked/borrowed some code from @benpye's project specifically for WSL2 (using socat): https://github.com/BlackReloaded/wsl2-ssh-pageant. That setup works for me. Just note that the docs say $HOME/.ssh/ than just the home directory (took me a couple of reads to pick up on that).

Mind you I'm using it with https://smartcard-auth.de/index-en.html for pageant in order to support my Yubikey.

I got wsl2-ssh-pageant working, However, not sure why in wsl2, I cannot make this work in my .zshrc. The socat process is running and the sock file is created, I can see it in ss -a, but ssh-add -l hang, I have to kill socat process and resource .zshrc, then it start working again. This behavior is same for weasel-pageant, I cannot eval and start weasel-pageant.exe in my .zshrc in wsl2, I have to run the eval outside my .zshrc or kill the socat process and re-source my .zshrc once my terminal started. WSL1 do not have this issu. Anyone have this issue in WSL2?

Thanks

@Vashiru
Copy link

Vashiru commented Sep 4, 2020

I just noticed @ BlackReloaded has sort of forked/borrowed some code from @benpye's project specifically for WSL2 (using socat): https://github.com/BlackReloaded/wsl2-ssh-pageant. That setup works for me. Just note that the docs say $HOME/.ssh/ than just the home directory (took me a couple of reads to pick up on that).
Mind you I'm using it with https://smartcard-auth.de/index-en.html for pageant in order to support my Yubikey.

I got wsl2-ssh-pageant working, However, not sure why in wsl2, I cannot make this work in my .zshrc. The socat process is running and the sock file is created, I can see it in ss -a, but ssh-add -l hang, I have to kill socat process and resource .zshrc, then it start working again. This behavior is same for weasel-pageant, I cannot eval and start weasel-pageant.exe in my .zshrc in wsl2, I have to run the eval outside my .zshrc or kill the socat process and re-source my .zshrc once my terminal started. WSL1 do not have this issu. Anyone have this issue in WSL2?

Thanks

Well I didn't have any issues on Ubuntu 18.04, I do see something similar on Ubuntu 20.04. But in my case socat wasn't running and ssh-add -l gave me 'file not found'. I discovered that when I run the socat command in the terminal, it works just fine, but it wasn't doing it when I ran it via my .zshrc. My workaround / fix was to remove the if statement so it will always execute.

@johnorourke
Copy link

Just sharing what worked for me - I was new to Windows named pipes, and it's not obvious in the above comments that you need to tell wsl-ssh-pageant to set up the named pipe:

I installed https://github.com/rupor-github/wsl-ssh-agent first because it includes a pre-built npiperelay.exe - I didn't want to have to create a Go build environment.

# in windows, set up a named pipe called ssh-pageant - NOTE: install it in a path with no spaces, it makes the socat command simpler:
"c:\wsl-ssh-agent\wsl-ssh-pageant-386.exe" --winssh ssh-pageant
# then from wsl, use socat to connect it to a socket file:
socat EXEC:"/mnt/c/wsl-ssh-agent/npiperelay.exe -ei -s //./pipe/ssh-pageant" UNIX-LISTEN:/tmp/wsl-ssh-pageant.socket,unlink-close,unlink-early,fork
# then tell ssh to use that socket
export SSH_AUTH_SOCK=/tmp/wsl-ssh-pageant.socket

@benpye
Copy link
Owner

benpye commented Nov 21, 2020

I'll try and have a dig into why this isn't working well. I've generally not had too much trouble with npiperelay and socat though it would be nice to avoid needing the npiperelay binary at the very least.

@judemille
Copy link

@ckuai I'm experiencing the same issue.

@ckuai
Copy link

ckuai commented Nov 30, 2020

@ckuai I'm experiencing the same issue.
Since the Nov win10 monthly update or after 20H2 feature update, the issue seems gone for me.

@tomoyat1
Copy link

tomoyat1 commented Jan 6, 2021

Hi,

Are there any plans to incorporate WSL2 support into wsl-ssh-pageant?
I'd rather not have to fumble with multiple utilities.

@kohenkatz
Copy link

@ckuai Not sure why that would be true, unless you switched to WSL 1.

WSL 2 still has no support for AF_UNIX-based socket communication with Windows programs. (See microsoft/WSL#4240)

@madzohan
Copy link

madzohan commented Jan 14, 2022

seems like that thread is alive microsoft/WSL#4240 perhaps they'll close this issue in nearest future 🚶‍♂️
but for now wsl.exe --set-version Ubuntu 1 😄

@Sieboldianus
Copy link

Sieboldianus commented Jan 25, 2023

Wow, this was not easy. Added the steps here as a Gist, works without tmux, in different WSL2 windows, no issues or errors on start or logout. Tested with Pageant running on the Windows side.

Originally missed to set permissions and ownership of files, which meant that the pipe relay did not work when sourced in bashrc.

@fholzer
Copy link

fholzer commented Feb 23, 2023

For those that have issues using npiperelay due to false positives from antivirus software... if you are using pageant, you'll likely have the full PuTTY suite installed that includes plink.exe. You can use that to connect to pipes as well. My solution doesn't use wsl-ssh-pageant, and doesn't need npiperelay. I run below command as a systemd service in WSL, and export the corresponding socket path via .bashrc:

socat UNIX-LISTEN:/home/username/.ssh/pageant.sock,unlink-early,fork "EXEC:'"'"'"/mnt/c/Program Files/PuTTY/plink.exe"'"'" -serial //
./pipe/pageant.YOURUSERNAME.SOMERVALUE'"

In case you need to look up the pipe name for pageant, you can run this in powershell:

Get-ChildItem \\.\pipe\ | ?{ $_ -like "*pageant*" } | %{ $_.name }

My systemd unit file:

[Unit]
Description=SSH Pageant Forwarder

[Service]
Type=simple
User=fholzer
ExecStart=/usr/bin/socat UNIX-LISTEN:/home/wls-username/.ssh/pageant.sock,unlink-early,fork "EXEC:'"'"'"/mnt/c/Program Files/PuTTY/plink.exe"'"'" -serial //./pipe/pageant.windows-username.random-data'"

[Install]
WantedBy=default.target

@fholzer
Copy link

fholzer commented Mar 17, 2023

Turns out the random string is different on every reboot, at least for me, so have to figure out a way to automate this yet.

@capi
Copy link

capi commented Mar 17, 2023

@fholzer Just an idea: run the power-shell command in a startup task on logon and write output to a file. Read that file as part of the ExecStart

@pearj
Copy link

pearj commented Mar 19, 2023

You can just run the PowerShell command from within WSL2

/mnt/c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe -Command 'Get-ChildItem \\.\pipe\ | ?{ $_ -like "*pageant*" } | %{ $_.name }'

An alternative to the PowerShell command is to get pageant itself to write an OpenSSH configuration file, which you could parse the data from.

You would need to start pageant like this:

"C:\Program Files\PuTTY\pageant.exe" --openssh-config %USERPROFILE%\pageant.conf

Then %USERPROFILE%\pageant.conf has:

IdentityAgent \\.\pipe\pageant.pearj.2d30b9f59dc36f3f89423fe713164d35f9efb8b13fbe40022158982e0fa27d79

From WSL you can grab that with cut -d' ' -f2 /mnt/c/Users/pearj/pageant.conf | tr '\\' '/' which switches the slashes around.

@alef
Copy link

alef commented Apr 27, 2023

Mixing @fholzer and @pearj solutions:

#!/usr/bin/bash
plink="/c/Program\\\\ Files/PuTTY/plink.exe"
IdentityAgent=$(<pageant.conf)
IdentityAgent=${IdentityAgent:0:-1} # removes \r
IdentityAgent=${IdentityAgent##IdentityAgent } # cut it out
IdentityAgent=${IdentityAgent//\\/\/} # flips slashes

/usr/bin/socat \
   UNIX-LISTEN:/tmp/pageant.sock,unlink-early,fork \
  "EXEC:${plink} -serial ${IdentityAgent}"

@KerickHowlett
Copy link

KerickHowlett commented May 12, 2023

Do any of y'all have a step-by-step instruction manual on how to accomplish this?

I've been at this for about a month now, and I still can't get OpenGPG to work in my instance of WSL2, and I've tried just about everything, including all the examples here, and none of them worked.

I'm hoping I just overlooked something, but so far I'm able to get this to work.

@mircsicz
Copy link

mircsicz commented May 12, 2023 via email

@zoredache
Copy link

Since people still seem to be having problems with this, I thought I would post my solution for getting a pretty reliable agent into WSL2.

I have found the npipe+socat options pretty unstable, and frustrating.

My solution for getting an agent into WSL uses a combination of WSL2 systemd support, OpenSSH server installed in WSL2, and using OpenSSH client in Windows.

Prepare the environment

  • Install the openssh client on windows, run some kind of agent on Windows and add your keys. Make sure you can see your keys on the Windows side by running ssh-add.exe -L
  • Setup your favorite WSL distro configure for WSL2.
  • In the WSL2 distro install OpenSSH. Possibly adjusting your /etc/ssh/sshd_config to have WSL2 listen on an alternate port. I run my WSL2 OpenSSH on 2200.
  • Configure your WSL2 environment to use systemd
  • Deploy the public key from your Windows agent into your WSL2 ~/.ssh/authorized_keys. Verify that you can ssh into your WSL2 environment without password prompts.

That is all the prep work done. Now how do I actually forward the agent. It is pretty simple. I add a new systemd unit and enable it. This unit will use the WSL interop to run the windows ssh.exe client to the WSL2 environment. It enables agent forwarding, and will leave an symlink to the agent socket in ~/.ssh/agent. Systemd will keep this ssh session open.

/etc/systemd/system/ssh_agent.service

[Unit]
Description=SSH Agent
After=ssh.service
ConditionPathExists=/mnt/c/Windows/System32/OpenSSH/ssh.exe

[Service]
ExecStart=/mnt/c/Windows/System32/OpenSSH/ssh.exe \
    wsl_username@localhost -p 2200 -A -t -t bash -c \
    ': ; ln -sf "$SSH_AUTH_SOCK" ~/.ssh/agent ; exec sleep 1d'
KillMode=process
Restart=on-failure
Type=simple

[Install]
WantedBy=multi-user.target

With that done, all you have to do is update your shell profile to set the SSH_AUTH_SOCK variable. I have something like this in my bash profile.

if [ -L ~/.ssh/agent -a -z ${SSH_AUTH_SOCK+x} ]; then
    # wait a bit for systemd to start sshd and ssh_agent units.
    wait_tries=20
    until test $((wait_tries--)) -eq 0 -o -S ~/.ssh/agent ; do sleep 0.5; done
    unset wait_seconds
    # set our socket
    export SSH_AUTH_SOCK=~/.ssh/agent
fi

I like this solution since it doesn't require any fancy magic to forward. It simply uses the ssh client and ssh daemon to forward exactly the way ssh agents are normally forwarded. We just are using the WSL2 systemd and interop to get this to happen in the background.

@KerickHowlett
Copy link

@zoredache Stupid question, but this also works with OpenPGP, right?

@zoredache
Copy link

@zoredache Stupid question, but this also works with OpenPGP, right?

Sorry, don't know. Haven't tried. I haven't ever really needed to use PGP in my WSL2 environment.

@viceice
Copy link

viceice commented May 31, 2024

my workaround 🙃

> cat ~/bin/ssh
#!/bin/sh

exec '/mnt/c/Windows/System32/OpenSSH/ssh.exe' "$@"

~/bin is on PATH via ~/.bashrc

@KerickHowlett
Copy link

Where were you when I needed you over a year ago! 😆

Sadly, I can no longer try implementing this, because this problem got so frustrating, I switched over to Linux.

@fabricionaweb
Copy link

my workaround 🙃

> cat ~/bin/ssh
#!/bin/sh

exec '/mnt/c/Windows/System32/OpenSSH/ssh.exe' "$@"

~/bin is on PATH via ~/.bashrc

I struggle like 20h on this... I even found someone that did similar for the gpg.exe to get access to the smartcard and that worked... but I didnt think in ssh it self...

Thanks you mentioned this, Funny how it works...

@viceice
Copy link

viceice commented Jun 13, 2024

my workaround 🙃

> cat ~/bin/ssh
#!/bin/sh

exec '/mnt/c/Windows/System32/OpenSSH/ssh.exe' "$@"

~/bin is on PATH via ~/.bashrc

I struggle like 20h on this... I even found someone that did similar for the gpg.exe to get access to the smartcard and that worked... but I didnt think in ssh it self...

Thanks you mentioned this, Funny how it works...

I'm also doing that for gpg 🙃

@Sieboldianus
Copy link

Sieboldianus commented Jul 2, 2024

my workaround 🙃

> cat ~/bin/ssh
#!/bin/sh

exec '/mnt/c/Windows/System32/OpenSSH/ssh.exe' "$@"

~/bin is on PATH via ~/.bashrc

This works for standard ssh connections, but it does not work for git on my side, e.g. git push > nothing happens, no error, just a prompt that never ends.

I tried specifying the GIT_SSH directly:

export GIT_SSH='/mnt/c/Windows/System32/OpenSSH/ssh.exe'

without success.

@viceice
Copy link

viceice commented Jul 2, 2024

my workaround 🙃

> cat ~/bin/ssh
#!/bin/sh

exec '/mnt/c/Windows/System32/OpenSSH/ssh.exe' "$@"

~/bin is on PATH via ~/.bashrc

This works for standard ssh connections, but it does not work for git on my side, e.g. git push > nothing happens, no error, just a prompt that never ends.

I tried specifying the GIT_SSH directly:

export GIT_SSH='/mnt/c/Windows/System32/OpenSSH/ssh.exe'

without success.

GIT_SSH didn't work for me too, that's why I created the simple shell wrapper which is working fine for me.

@Sieboldianus
Copy link

Strange, even with the SSH wrapper it is not working with git (but with ssh ... directly, it works)

@fabricionaweb
Copy link

fabricionaweb commented Jul 2, 2024

Indeed weird, it works normal here too, just a remind that using the windows openssh you might need to use the windows .ssh dir as well, so I just linked to mine /home/fabricio/.ssh -> /mnt/c/Users/fabricio/.ssh Im also not using a wrapper but instead I linked the ssh.exe to /usr/local/bin/ssh (same for the others)

@Sieboldianus
Copy link

Ok, thanks - I could not get this to work under WSL2. I reverted to splitting my work: (1) Coding in WSL2 and (2) git commit/pull in WSL1.

@Sieboldianus
Copy link

.. finally was able to set this up with the latest Windows 10 and WSL2 following @zoredache steps. Minor changes on my side were necessary. I added it step by step here.

@madmages
Copy link

One more workaround
export GIT_SSH=/mnt/c/Program\ Files/Putty/plink.exe

works on wsl2 ubuntu.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests