benpye / wsl-ssh-pageant

A Pageant -> TCP bridge for use with WSL, allowing for Pageant to be used as an ssh-ageant within the WSL environment.
BSD 2-Clause "Simplified" License
625 stars 40 forks source link

Support for WSL2 #33

Open AngellusMortis opened 4 years ago

AngellusMortis commented 4 years ago

According to a similar project, https://github.com/rupor-github/wsl-ssh-agent/issues/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 commented 4 years ago

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 commented 4 years ago

@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 commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

The only two issues I have with https://github.com/benpye/wsl-ssh-pageant/issues/33#issuecomment-640935516 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 commented 4 years ago

This variant of https://github.com/benpye/wsl-ssh-pageant/issues/33#issuecomment-640935516 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 commented 4 years ago

@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
voltagex@10.1.1.2: 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 commented 4 years ago

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

Vashiru commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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 commented 3 years ago

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 commented 3 years ago

@ckuai I'm experiencing the same issue.

ckuai commented 3 years ago

@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 commented 3 years ago

Hi,

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

kohenkatz commented 3 years ago

@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 https://github.com/microsoft/WSL/issues/4240)

madzohan commented 2 years ago

seems like that thread is alive https://github.com/microsoft/WSL/issues/4240 perhaps they'll close this issue in nearest future ๐Ÿšถโ€โ™‚๏ธ but for now wsl.exe --set-version Ubuntu 1 ๐Ÿ˜„

Sieboldianus commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

@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 commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

I roo have dealt with it for several days. My simple solution was to set my instance back to WSL1 ๐Ÿคฎ๐Ÿ˜‚๐Ÿ˜ฉVon meinem iPhone gesendetAm 11/05/23 um 21:30 schrieb Kerick Howlett @.***>:๏ปฟ 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. Please help!

โ€”Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you are subscribed to this thread.Message ID: @.***>

zoredache commented 1 year ago

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

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 commented 1 year ago

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

zoredache commented 1 year ago

@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 commented 5 months ago

my workaround ๐Ÿ™ƒ

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

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

~/bin is on PATH via ~/.bashrc

KerickHowlett commented 5 months ago

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 commented 5 months ago

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 commented 5 months ago

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 commented 4 months ago

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 commented 4 months ago

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 commented 4 months ago

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

fabricionaweb commented 4 months ago

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 commented 4 months ago

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 commented 3 months ago

.. 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 commented 1 month ago

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

works on wsl2 ubuntu.