DEV Community

Lucy Llewellyn
Lucy Llewellyn

Posted on • Originally published at snapcraft.ninja

GPG-sign your Git commits and remember your SSH key passwords in WSL2 including Yubikey PGP support

This is a follow-up to my WSL2 hack enabling Systemd to run enabling all the awesome features such as service management and session management. The session management enables most graphical or GUI applications in the WSL2 Distro to function without issue when combined with an appropriate Windows-based X11 server such as X410, MobaXTerm or VCXSRV.

So, you're working away in your WSL2 distro and then you want to sign a GIT commit with your PGP key which is backed by a Hardware Security Module like a YubiKey. Or you want to SSH into a remote system using an SSH key that has a long and difficult to remember password. Both activities can be improved or enabled by using Windows-based "Agents". For PGP we can use GPG4Win's gpg-agent and for SSH we can use the SSH agent that is shipped with Windows.

Installation

We only need to install GPG4Win, because Windows comes with the SSH Agent out of the box. So, to install GPG4Win we'll use winget. In a CMD or PowerShell window run:

winget.exe install gpg4win
Enter fullscreen mode Exit fullscreen mode

Loading your keys

Next we load your Private SSH or PGP keys or HSM-backed Public PGP keys into the Windows agents. For SSH keys this is easy; simply copy the keys to C:\Users\<your-username>\.ssh\.

For PGP keys, use the Start Menu to open Kleopatra. If you are using an HSM you only need the public key as a file or the fingerprint ID to lookup the public key on a key server. To import a file-based key select "File" and then "Import" (or press ctrl+I), locate your key file in the browser, and click "Open". To lookup a public key on a key server with the key ID select "File" and then "Lookup on server" (or press ctrl+shift+I). In the dialog that opens enter your key's fingerprint ID, click search, select the correct key from the list and finally click "Import".

Ensuring the agents start automatically

For SSH Agent this is easy to do with PowerShell. Open the run dialog by pressing win+r and type powershell into the text box and finally pressing ctrl+shift+enter to start it in a privileged mode. Now we type the following into the PowerShell window and then you can close it because we're finished there:

Set-Service ssh-agent -StartupType automatic
Start-Service ssh-agent
Enter fullscreen mode Exit fullscreen mode

To start the GPG agent open a new unprivileged PowerShell window and run:

& 'C:\Program Files (x86)\GnuPG\bin\gpg-connect-agent.exe' /bye
Enter fullscreen mode Exit fullscreen mode

However, that only starts the agent once for your current session. To get it started every time you login you can open a privileged PowerShell like we did with the SSH agent above and run:

Register-ScheduledJob -Name GPGAgent -Trigger (New-JobTrigger -AtLogOn) -RunNow -ScriptBlock {
    & "${env:ProgramFiles(x86)}/GnuPG/bin/gpg-connect-agent.exe" /bye
}
Enter fullscreen mode Exit fullscreen mode

Tying the agents to WSL2

First you need your Distro to have the WSLUtilities installed. On Ubuntu these are already present. Follow the steps on the linked GitHub page for your Distro.

Next, we need socat if it isn't already installed:

sudo apt update
sudo apt install -yyq socat
Enter fullscreen mode Exit fullscreen mode

Now, place the following code into a file in your Distro at /etc/profile.d/wsl2-ssh-gpg-agents.sh. This presumes that your Distro automatically parses files in /etc/profile.d:

NPIPERELAY_URL="https://github.com/NZSmartie/npiperelay/releases/download/v0.1/npiperelay.exe"

if [ -n "$WSL_DISTRO_NAME" ]; then
    APPDATA="$(wslvar appdata)"
    APPDATA="${APPDATA//\\/\/}"
    NPIPERELAY_WIN="$APPDATA/wsl2-ssh-gpg-npiperelay.exe"
    NPIPERELAY="$(wslpath "$NPIPERELAY_WIN")"

    if [ ! -f "$NPIPERELAY" ]; then
        curl -L -q -o "$NPIPERELAY" "$NPIPERELAY_URL"
    fi
    #####
    ## Autorun for the gpg-relay bridge
    ##
    SOCAT_PID_FILE=$HOME/.gnupg/socat-gpg.pid
    SOCAT_PID_FILE2=$HOME/.gnupg/socat-gpg.pid.2

    for GPG_SOCK in "$HOME/.gnupg/S.gpg-agent" "/run/user/$UID/gnupg/S.gpg-agent"; do
        if ! ss -a | grep -q "$GPG_SOCK"; then
            rm -f "$GPG_SOCK"
            mkdir -p "$(dirname "$GPG_SOCK")"
            setsid --fork socat UNIX-LISTEN:"$GPG_SOCK",fork EXEC:"$NPIPERELAY -ei -ep -s -a "'"'"$APPDATA"/gnupg/S.gpg-agent'"',nofork
        fi
    done

    #####
    ## Autorun for the ssh-relay bridge
    ##
    export SSH_AUTH_SOCK=$HOME/.ssh/agent.sock
    if ! ss -a | grep -q "$SSH_AUTH_SOCK"; then
        rm -f "$SSH_AUTH_SOCK"
        setsid --fork socat UNIX-LISTEN:"$SSH_AUTH_SOCK",fork EXEC:"$NPIPERELAY -ei -s //./pipe/openssh-ssh-agent",nofork
    fi
fi 
Enter fullscreen mode Exit fullscreen mode

Finishing up

You're done. Just restart your WSL2 session and you'll be able to use the GPG and SSH agents hosted on Windows from within the Linux environment. This also works for Yubikey-backed PGP keys!

I hope to return to this soon to automate the installation the way that Damion Gans did for the Systemd hack.

Top comments (0)