Skip to content

Instantly share code, notes, and snippets.

@Jaykul
Last active April 18, 2024 11:18
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save Jaykul/19e9f18b8a68f6ab854e338f9b38ca7b to your computer and use it in GitHub Desktop.
Save Jaykul/19e9f18b8a68f6ab854e338f9b38ca7b to your computer and use it in GitHub Desktop.
SSH Agent passthru to WSL 2 (working, in Windows 11, in May 2023)

For awhile now, each time I got a new Windows laptop I would dig up strasis gist on how to set up agent forwarding for SSH in WSL2 -- but recently I tried to point someone else at it and they were very confused by it, so this is my attempt at simpler instructions.

Installation

With Chocolatey, you must use an elevated PowerShell session. If there's no choco command found, it will fall back to winget for the npiperelay install. To force using Winget even if you have choco installed, you need to download it, so you can pass parameters to it.

Easy mode: just run this in PowerShell:

iex (irm https://gist.githubusercontent.com/Jaykul/19e9f18b8a68f6ab854e338f9b38ca7b/raw/Install.ps1)

To be more cautious, click the Download zip button in the top right, unzip everything, read it through carefully, to make sure I'm not tricking you. Then run the Install.ps1 script from the unzipped files.

What does it do?

It's all designed to be run from PowerShell (5+) on Windows. When commands need to be run in WSL, it will use the wsl command to do so (as root and as you). Before you start, make sure you have wsl 2 and a distro installed (run wsl --list -v and pick a distro that has VERSION 2).

  1. Install npiperelay in Windows using chocolatey or winget
  2. Install socat in WSL using apt (sorry, if your distro isn't apt, please fork and comment 😉)
  3. Copy an ssh-agent-pipe script that starts npiperelay for you whenever you open bash
  4. Make that script executable
  5. Add that script to your .bashrc (note: better not to run this install multiple times 😝)
<#
.SYNOPSIS
Install npiperelay and socat and configure SSH_AUTH_SOCK forwarding
#>
[CmdletBinding()]
param(
# The distribution to connect the pipe to
[Parameter(Position = 0)]
$Distribution = "Ubuntu",
# The user for whom .bashrc should be modified
# Defaults to your username all lowercase
[Parameter(ParameterSetName = "Insecure")]
$Username = $Env:USERNAME.ToLower(),
# Ingore chocolatey for install (winget must be available).
[switch]$NoChocolate
)
# Install npiperelay
if (!(Get-Command npiperelay.exe -ErrorAction Ignore)) {
if (-not $NoChocolate -and (Get-Command choco -ErrorAction Ignore)) {
choco upgrade npiperelay -y
} elseif (Get-Command winget -ErrorAction Ignore) {
winget install --id=jstarks.npiperelay -e --accept-source-agreements
} else {
throw "Unable to install. Please download https://github.com/jstarks/npiperelay/releases/latest/download/npiperelay_windows_amd64.zip and extract it somewhere in your PATH"
}
}
# install socat in WSL
wsl -d $Distribution -u root apt install socat
if ($LASTEXITCODE) {
throw "Unable to install socat. I give up."
}
# create the ssh-agent-pipe script in WSL
# Ensure the carriage returns are correct (and fetch the script, if necessary):
$script = if (Test-Path $PSScriptRoot\ssh-agent-pipe.sh) {
(Get-Content $PSScriptRoot\ssh-agent-pipe.sh) -join "`n"
} else {
Invoke-RestMethod https://gist.githubusercontent.com/Jaykul/19e9f18b8a68f6ab854e338f9b38ca7b/raw/ssh-agent-pipe.sh
}
# escape $ and " so we can pass this through bash
$script = $script -replace "\$", "\$" -replace '"', '\"'
wsl -d $Distribution -u root -- bash -c "cat > /usr/local/bin/ssh-agent-pipe <<'EOF'`n${script}`nEOF"
# Make it executable
wsl -d $Distribution -u root chmod +x /usr/local/bin/ssh-agent-pipe
# Add to .bashrc for the specified user
wsl -d $Distribution -u $Username -- bash -c "echo \`"source /usr/local/bin/ssh-agent-pipe\`" >> ~/.bashrc"
#!/bin/bash
# Usage: ssh-agent-pipe [ -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:"npiperelay.exe -ei -s //./pipe/openssh-ssh-agent",nofork & ) >/dev/null 2>&1
fi
@theeternalrat
Copy link

Thank you! This worked perfectly!

I did have to follow these instructions as well: https://superuser.com/questions/1726204/get-agent-identities-ssh-agent-bind-hostkey-communication-with-agent-failed

I was able to use ssh-add -l in wsl after running the script, but trying to ssh gave communication with agent failed. Following that SO and restarting seems to have fix it. I've done this one two different computers now, both working.

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