Skip to content

Instantly share code, notes, and snippets.

@WillianTomaz
Last active July 13, 2024 20:44
Show Gist options
  • Save WillianTomaz/a972f544cc201d3fbc8cd1f6aeccef51 to your computer and use it in GitHub Desktop.
Save WillianTomaz/a972f544cc201d3fbc8cd1f6aeccef51 to your computer and use it in GitHub Desktop.
Instructions for using 1Password SSH Agent with WSL2 (on Windows 11)

Saturday, April 22, 2023

How to Use 1Password SSH Agent with WSL2 (on Windows 11)

  • Note:

    • Always look for the official documentation, this tutorial may not suit you as there are new updates to the installation process.
    • References are at the end of the document.
  • Was used:

    • Windows 11 (x64)
    • WSL 2 (Ubuntu 22.04.2 LTS)
    • 1Password (for Windows 8.10.5)



Install WSL2 (on Windows 11)

  • Windows 11 makes it easy to install WSL, basically you need to run these commands:

    In your PowerShell(admin) or CMD(admin):

    1. Run the command to install WSL2, and restart the computer.
      # The command will install WSL alongside the Ubuntu distribution.
      wsl –install
      # Or, to install WSL with a specific distro, run the command:
      wsl –install -d <distro-name>
    2. Other Useful Commands:
      # Checking the image version
      wsl --list --verbose
      
      # Selecting Distro as Main
      wsl --setdefault <distro-name>
      
      # If you need to remove a distro
      wsl --unregister <distro-name>
      
      # If necessary, kill the WSL process
      wsl --shutdown  



1. Enable 1Password SSH Agent

2. Download npiperelay

  • This tool (npiperelay) is used for communication between WSL and the 1Password SSH agent. It uses WSL to communicate with Windows Named Pipes.
    1. Download npiperelay from the GitHub repository
    2. Unzip it, and paste the npiperelay.exe file in any folder that's configured in your system's PATH.
      • If you don't know how to modify your system's PATH... Example Here
        # 1. Create a folder at an address like this
        C:\Users\my-user\folder-npiperelay
        # 2. Create PATH Environment Variable on Windows
        # 3. Run npiperelay.exe

3. Connect WSL with 1Password's SSH agent

In your WSL distribution:

  • "We need to install socat which is a utility to transfer data between channels, this tool will use npiperelay to then communicate with the named pipes"
    sudo apt install socat
  • Create a new file named .agent-bridge.sh in your home directory
    touch $HOME/.agent-bridge.sh && chmod +x $HOME/.agent-bridge.sh
    1. (IMPORTANT) Create the folder on your root for the agent.sock (How mentioned by @rfay and @Lochnair in the comments) or if you prefer, add the content on .agent-bridge.sh at the top of the step bellow
      mkdir -p ~/.1password
    2. Paste content into File: .agent-bridge.sh
      # Code extracted from https://stuartleeks.com/posts/wsl-ssh-key-forward-to-windows/ 
      
      # (IMPORTANT) Create the folder on your root for the `agent.sock` (How mentioned by @rfay and @Lochnair in the comments)
      # mkdir -p ~/.1password
      
      # Configure ssh forwarding
      export SSH_AUTH_SOCK=$HOME/.1password/agent.sock
      # need `ps -ww` to get non-truncated command for matching
      # use square brackets to generate a regex match for the process we want but that doesn't match the grep command running it!
      ALREADY_RUNNING=$(ps -auxww | grep -q "[n]piperelay.exe -ei -s //./pipe/openssh-ssh-agent"; echo $?)
      if [[ $ALREADY_RUNNING != "0" ]]; then
          if [[ -S $SSH_AUTH_SOCK ]]; then
              # not expecting the socket to exist as the forwarding command isn't running (http://www.tldp.org/LDP/abs/html/fto.html)
              echo "removing previous socket..."
              rm $SSH_AUTH_SOCK
          fi
          echo "Starting SSH-Agent relay..."
          # setsid to force new session to keep running
          # set socat to listen on $SSH_AUTH_SOCK and forward to npiperelay which then forwards to openssh-ssh-agent on windows
          (setsid socat UNIX-LISTEN:$SSH_AUTH_SOCK,fork EXEC:"npiperelay.exe -ei -s //./pipe/openssh-ssh-agent",nofork &) >/dev/null 2>&1
      fi
    3. Add the following line at the end of the file .bashrc
      source $HOME/.agent-bridge.sh

4. Finally last step

  • Reset your Windows Terminal and you should be able to see your keys imported into 1Password when listing the keys added to the agent.
  • Try this command on your WSL2 and if it returns your keys, congratulations you finished the setup!
    ssh-add -l



References

@AnturGyffrous
Copy link

This worked for me on ZSH, but of course I had to add the source $HOME/.agent-bridge.sh line to .zshrc not .bashrc

@michal-grzelak
Copy link

michal-grzelak commented Oct 21, 2023

I second what @rfay posted above. If you're using WSL then you don't need any npiperelay. interop is turned on by default in WSL, so you can simply put:

alias ssh="/mnt/c/Windows/System32/OpenSSH//ssh.exe" # or just ssh.exe
alias ssh-add="/mnt/c/Windows/System32/OpenSSH//ssh-add.exe" # or just ssh-add.exe

into your .zshrc/.bashrc.

If you don't want to use windows ssh in WSL and wanted just to use for git, then no problem, just put:

[core]
  sshProgram = "/mnt/c/Windows/System32/OpenSSH//ssh.exe" # or just ssh.exe

in you .gitconfig.

This is just a shortcut from the article.

@FlyinPancake
Copy link

FlyinPancake commented Oct 29, 2023

If you use fish, you can add this to a file located in .config/fish/conf.d/

#!/bin/fish
# Configure ssh forwarding
set -x SSH_AUTH_SOCK $HOME/.1password/agent.sock

# Check if npiperelay.exe is already running
set ALREADY_RUNNING (ps -auxww | grep -q "[n]piperelay.exe -ei -s //./pipe/openssh-ssh-agent"; echo $status)
if test $ALREADY_RUNNING != 0
    if test -S $SSH_AUTH_SOCK
        # Not expecting the socket to exist as the forwarding command isn't running
        echo "Removing previous socket..."
        rm $SSH_AUTH_SOCK
    end

    echo "Starting SSH-Agent relay..."
    # Use setsid to force a new session to keep running
    # Set socat to listen on $SSH_AUTH_SOCK and forward to npiperelay, which then forwards to openssh-ssh-agent on Windows

    setsid socat UNIX-LISTEN:$SSH_AUTH_SOCK,fork EXEC:"npiperelay.exe -ei -s //./pipe/openssh-ssh-agent",nofork >/dev/null 2>&1 &
end

@FlyinPancake
Copy link

@cyshallchan
Copy link

It seems that this method is no longer effective now? At least in my case, I can't use it. Is there anyone kind enough to help me?

ps -ef | grep -i agent:

root        5236       1  0 20:15 ?        00:00:00 /usr/bin/socat UNIX-LISTEN:/root/.ssh/agent.sock,fork EXEC:/mnt/c/Users/Cyshall/AppData/Local/Microsoft/WinGet/Links/npiperelay.exe -ei -s //./pipe/openssh-ssh-agent,nofork

Running ssh-add -l gives me an error:

error fetching identities: communication with agent failed

System info:

Windows 11 Pro 22H2 22621.2428

1password info:

1Password for Windows 8.10.7 (81007041)

@FlyinPancake
Copy link

Check the value of the SSH_AUTH_SOCK variable, and try restarting the PC

@cyshallchan
Copy link

Check the value of the SSH_AUTH_SOCK variable, and try restarting the PC

I have tried everything, but it didn't work. Then I attempted to start directly from the terminal and checked the output, but I couldn't understand it. The detailed steps are as follows:

The first window executes the following command in wsl2:

/usr/bin/socat UNIX-LISTEN:/root/.ssh/agent.sock,fork EXEC:"/mnt/c/Users/xxxx/AppData/Local/Microsoft/WinGet/Links/npiperelay.exe -ei -s //./pipe/openssh-ssh-agent"

The second window in wsl2 reports an error executing ssh-add -l:

error fetching identities: communication with agent failed

Returning to the first window at this point will output the following:

/mnt/c/Users/xxxx/AppData/Local/Microsoft/WinGet/Links/npiperelay.exe: 1: MZ    @   : not found
/mnt/c/Users/xxxx/AppData/Local/Microsoft/WinGet/Links/npiperelay.exe: 3: Syntax error: word unexpected (expecting ")")
2023/10/31 19:01:56 socat[2906] E waitpid(): child 2907 exited with status 2

@smooshy
Copy link

smooshy commented Nov 2, 2023

Thanks for this! This worked for me on Win 11 with Ubuntu 22.04.3.

@cyshallchan
Copy link

I second what @rfay posted above. If you're using WSL then you don't need any npiperelay. interop is turned on by default in WSL, so you can simply put:

alias ssh="/mnt/c/Windows/System32/OpenSSH//ssh.exe" # or just ssh.exe
alias ssh-add="/mnt/c/Windows/System32/OpenSSH//ssh-add.exe" # or just ssh-add.exe

into your .zshrc/.bashrc.

If you don't want to use windows ssh in WSL and wanted just to use for git, then no problem, just put:

[core]
  sshProgram = "/mnt/c/Windows/System32/OpenSSH//ssh.exe" # or just ssh.exe

in you .gitconfig.

This is just a shortcut from the article.

I just noticed this method, I tried it out and it worked fine. Thank you very much!

@rfay
Copy link

rfay commented Nov 20, 2023

The official instructions at https://developer.1password.com/docs/ssh/integrations/wsl/ are now working in general, it may be best to just adopt them now. Pretty simple.

@julienallexandre
Copy link

@rfay
Copy link

rfay commented Nov 23, 2023

It's working perfectly for me.

@Dragory
Copy link

Dragory commented Nov 30, 2023

The official instructions are really just a different workaround, and for some use cases a worse solution. For example, it requires you to manage your SSH config on the Windows side and doesn't set SSH_AUTH_SOCK at all, which some use cases might need.

@Icehunter
Copy link

I also don't use .exe files in windows as much as possible and don't appendPath. The only issue I have is the constant:

ssh-add -L
Error connecting to agent: No such file or directory

I have to delete the older and remake it a few times and kill wsl to get it working after a reboot.

@mkhoatd
Copy link

mkhoatd commented Mar 8, 2024

I also don't use .exe files in windows as much as possible and don't appendPath. The only issue I have is the constant:

ssh-add -L
Error connecting to agent: No such file or directory

I have to delete the older and remake it a few times and kill wsl to get it working after a reboot.

Maybe try this

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

# Function to start the SSH-Agent relay
start_ssh_agent_relay() {
    if [[ -S $SSH_AUTH_SOCK ]]; then
        echo "Removing previous socket..."
        rm $SSH_AUTH_SOCK
    fi
    echo "Starting SSH-Agent relay..."
    (setsid socat UNIX-LISTEN:$SSH_AUTH_SOCK,fork EXEC:"npiperelay.exe -ei -s //./pipe/openssh-ssh-agent",nofork &) >/dev/null 2>&1
}

# Function to check if the SSH-Agent relay is running
check_ssh_agent_relay() {
    if [[ $(ssh-add -l 2>&1) == "Error connecting to agent: No such file or directory" ]]; then
        return 1  # Return non-zero exit code if the relay is not running
    else
        return 0  # Return zero exit code if the relay is running
    fi
}

# Function to stop the SSH-Agent relay
stop_ssh_agent_relay() {
    npiperelay_pid=$(ps -auxww | grep -q "[n]piperelay.exe -ei -s //./pipe/openssh-ssh-agent" | awk '{print $2}')
    if [[ -n $npiperelay_pid ]]; then
        echo "Killing npiperelay..."
        kill $npiperelay_pid
    fi
    if [[ -S $SSH_AUTH_SOCK ]]; then
        echo "Removing previous socket..."
        rm $SSH_AUTH_SOCK
    fi
}

# Check if the SSH-Agent relay is already running
if ! ps -auxww | grep -q "[n]piperelay.exe -ei -s //./pipe/openssh-ssh-agent"; then
    start_ssh_agent_relay
fi

# Check if the SSH-Agent relay is running and retry if it fails
retry_count=0
max_retries=3
while ! check_ssh_agent_relay; do
    if ((retry_count >= max_retries)); then
        echo "Failed to start SSH-Agent relay after $max_retries attempts."
        exit 1
    fi
    echo "SSH-Agent relay failed to start. Retrying..."
    stop_ssh_agent_relay
    start_ssh_agent_relay
    ((retry_count++))
done

echo "SSH-Agent relay started successfully."

@SJ50
Copy link

SJ50 commented Mar 16, 2024

for those who are facing error fetching identities: communication with agent failed or any ssh-add -l related errors.
try below script

#!/bin/bash

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

# need `ps -ww` to get non-truncated command for matching
# use square brackets to generate a regex match for the process we want but that doesn't match the grep command running it!
SSH_AGENT_WORKING=$(ssh-add -l >/dev/null 2>&1; echo $?)
if [[ $SSH_AGENT_WORKING != "0" ]]; then
    # echo "ssh agent not working, killing npiperelay.exe"
    kill $(ps -auxww | grep "[n]piperelay.exe -ei -s //./pipe/openssh-ssh-agent" | awk '{print $2}') >/dev/null 2>&1
fi	

ALREADY_RUNNING=$(ps -auxww | grep -q "[n]piperelay.exe -ei -s //./pipe/openssh-ssh-agent"; echo $?)
if [[ $ALREADY_RUNNING != "0" ]]; then	
    
    if [[ -S $SSH_AUTH_SOCK ]]; then
        # not expecting the socket to exist as the forwarding command isn't running (http://www.tldp.org/LDP/abs/html/fto.html)
        # echo "removing previous socket..."
        rm $SSH_AUTH_SOCK >/dev/null 2>&1
    fi
    # echo "Starting SSH-Agent relay..."
    # setsid to force new session to keep running
    # set socat to listen on $SSH_AUTH_SOCK and forward to npiperelay which then forwards to openssh-ssh-agent on windows
    (setsid socat UNIX-LISTEN:$SSH_AUTH_SOCK,fork EXEC:"npiperelay.exe -ei -s //./pipe/openssh-ssh-agent",nofork &) >/dev/null 2>&1
fi

When WSL shutdown it keep socat process stored and when we start WSL again it reuses same process, this leads to error error fetching identities: communication with agent failed. I have added check if ssh-agent process is running properly, if not then kill and restart socat process

@rodrigo-a-moreno
Copy link

Excellent Post!!!

@rfdonnelly
Copy link

rfdonnelly commented Jul 13, 2024

I've been using this solution for years. Within the last year or so (maybe longer), I've noticed excessive delay on making ssh connections. I finally narrowed it down to the SSH Agent relay. If I use the relayed agent, it takes about 5 seconds. If I use the agent directly (no relay), it takes 92 milliseconds.

Using the relay for the 1Password SSH Agent:

> time ssh-add -l
...
ssh-add -l  0.00s user 0.00s system 0% cpu 5.339 total

Using the 1Password SSH Agent directly via Windows OpenSSH:

> time ssh-add.exe -l
...
ssh-add.exe -l  0.00s user 0.04s system 42% cpu 0.092 total

Anyone have any tips on debugging this? Using Windows OpenSSH (ssh.exe) isn't a viable option for all use cases. In particular, Ansible makes use of ControlPath which uses POSIX sockets which are not available in Windows OpenSSH.

SOLVED: I had npiperelay.exe in my WSL 2 distro filesystem. I moved to npiperelay.exe to the Windows filesystem and made sure it was in the Windows PATH. Now the delay is completely gone.

> time ssh-add -l
...
ssh-add -l  0.00s user 0.00s system 4% cpu 0.094 total

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