wsl2-ssh-agent

WSL2 ssh-agent #

Tip

这篇文章中的方案只能转发 Windows 侧的 \\.\pipe\openssh-ssh-agent 管道到 WSL2, 不能转发其他管道(如 %APPDATA%\Local\gnupg\S.gpg-agent,实际上这不是管道,是一个普通文件,首行内容是 gpg-agent 监听端口)。 推荐另一种方案,详见 wsl2-gpg-agent-bridge

简介 #

  1. ssh 是一种远程连接工具。
  2. ssh-agent 是用来管理ssh密钥的一种服务,通过管道的方式来跟ssh客户端交互密钥信息。
  3. gpg 是一种密钥管理工具,可提供 gpg-agent 服务。Gpg4win 是gpg在Windows下的一种实现。
  4. gpg-agent 是用来管理gpg密钥的一种服务,具有 ssh-agent 功能。
  5. 在使用 Gpg4win 提供的gpg-agent服务模拟ssh-agent时,会生成win命名管道\\.\pipe\openssh-ssh-agent,管道文件位于%APPDATA%/Local/gnupg/S.gpg-agent.ssh。Win32-OpenSSH 提供的ssh-add.exe、ssh.exe等客户端会利用该管道向 ssh-agent 服务添加或读取ssh密钥。
  6. 上述win命名管道也可以通过特殊方法转发到WSL内部,让WSL容器内部的ssh-add、ssh等命令使用外部 Gpg4win 提供的 ssh-agent 服务,从而让宿主系统和WSL系统共用一套 ssh-agent 服务,方便集中管理ssh密钥。还可以通过配置 Git Bash 中的 ssh,指定为外部 Win32-OpenSSH 的 ssh.exe 命令,从而在 Git Bash 中不必再维护ssh密钥。

一、安装 Gpg4win #

详见官网: https://gpg4win.org/

本文不涉及其他版本(如 linux 版本,https://gnupg.org/)

二、配置 gpg-agent.conf #

文件位置:%APPDATA%\Roaming\gnupg\gpg-agent.conf

添加以下配置内容:

text
enable-ssh-support
enable-putty-support
# To Enable support for the native Microsoft OpenSSH binaries (requires gpg 2.4.0 / Gpg4win 4.1.0 or higher)
enable-win32-openssh-support
use-standard-socket

重启 gpg-agent 服务:

ps1
gpg-connect-agent reloadagent /bye

三、配置环境和自启脚本 #

配置 PowerShell 的 profile 脚本 #

PowerShell 的 profile 脚本是一个可编辑的启动脚本,每次打开 PowerShell 窗口时自动执行一遍。 下面编辑这个脚本,添加 gpg-agent 启动命令。

(1)使用编辑器打开 profile 配置文件:

ps1
# 使用记事本打开:
notepad $PROFILE
# 或者使用VSCode打开:
code $PROFILE

(2)按需添加配置内容:

ps1
# 启动 gpg-agent 服务
gpg-connect-agent /bye

# 设置环境变量 SSH_AUTH_SOCK (ssh-agent管道地址)
# 方式一(添加到系统环境变量中,这样可以让VSCode、IDEA中的 ssh/git 也可以使用 ssh-agent 服务)。
# 方式二(添加变量赋值代码,但是仅对当前PowerShell窗口生效):
# $env:SSH_AUTH_SOCK="\\.\pipe\openssh-ssh-agent"

配置开机自启脚本 #

(1)添加PowerShell脚本文件,放到固定位置,如:C:\YourPath\init-script.ps1

ps1
# Start gpg-agent
gpg-connect-agent /bye

(2)添加vbs脚本文件,放到固定位置,如:C:\YourPath\init.vbs(使用vbs脚本是为了开机自启时不弹出黑窗口)

vbs
set ws=WScript.CreateObject("WScript.Shell")
ws.run "powershell -file C:\YourPath\init-script.ps1",vbhide

(3)给vbs脚本文件创建快捷方式init.vbs.lnk,放在系统开机自启目录下:C:\Users\YourName\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\init.vbs.lnk

四、在 WSL 中配置管道转发服务 #

准备环境 #

bash
# 安装 socat,用于转发套接字数据
sudo apt install socat

# 下载 npiperelay.exe(用于WSL中打开win管道),放到固定位置,如 C:\YourPath\npiperelay.exe
# 项目地址:https://github.com/jstarks/npiperelay
# 添加权限、创建软连接
sudo chmod a+x /mnt/c/YourPath/npiperelay.exe
sudo ln -s /mnt/c/YourPath/npiperelay.exe /usr/local/bin/npiperelay.exe

# 原理:
#   socat 配合 npiperelay.exe 进行ssh-agent管道数据转发(此命令会阻塞),
#   然后配置环境变量 SSH_AUTH_SOCK=/tmp/win-ssh-agent-relay.socket 即可。
# 下面是命令样例:
# socat UNIX-LISTEN:/tmp/win-ssh-agent-relay.socket,fork EXEC:"npiperelay.exe -ei -s //./pipe/openssh-ssh-agent",nofork

添加服务单元 #

(1)文件路径:/etc/systemd/system/win-ssh-agent-relay.service

text
[Unit]
Description=Relay S.gpg-agent.ssh socket from Gpg4win

[Service]
Type=simple
ExecStart=/usr/bin/socat UNIX-LISTEN:/var/run/win-ssh-agent-relay.socket,fork EXEC:"/usr/local/bin/npiperelay.exe -ei -s //./pipe/openssh-ssh-agent",nofork

[Install]
WantedBy=multi-user.target

(2)启用服务:

bash
sudo systemctl enable --now win-ssh-agent-relay.service

(3)rc文件添加配置内容:~/.bashrc

bash
# Enable ssh-agent
export SSH_AUTH_SOCK="/var/run/win-ssh-agent-relay.socket"

五、配置 Git Bash #

git sshCommand #

给git配置ssh命令:

bash
# PowerShell 或 Git Bash 中执行以下命令(相关配置文件 ~/.gitconfig):
git config --global core.sshCommand C:/Windows/System32/OpenSSH/ssh.exe

PATH 环境变量 #

将 PATH 中的 /c/WINDOWS/System32/OpenSSH 目录移到开头。

添加配置内容:~/.bashrc

bash
_exclude_paths='/c/WINDOWS/System32/OpenSSH'
export PATH="$(echo "$PATH" | tr ':' '\n' | grep -Fxivf <(echo "$_exclude_paths") | sed ':t;N;s/\n/:/;t t')"
export PATH="/c/Windows/System32/OpenSSH:$PATH"
unset _exclude_paths

注意,这样改造之后,如果是通过 Open Git Bash here 打开的 MINGW64 窗口(不包括通过 Windows Terminal 打开), 在使用ssh命令登录远程服务器时,会提示stdin不是一个终端,无法交互, 可以加上 -tt 参数强制开启一个终端来解决(不推荐), 在 MINGW64 窗口内建议使用 Git Bash 自带 /usr/bin/ssh 来连接。

注意事项 #

关于 C:\Users\YourName.gnupg 目录 #

  1. 此目录一般是由 Git Bash 中自带的 gpg 客户端创建,但是经过以上配置之后不再推荐使用此 gpg 实例。
  2. 真正的 gpg 实例,是由 Gpg4win 创建,个人配置目录在 C:\Users\YourName\AppData\Roaming\gnupg,利用其 gpg-agent 进程来管理 gpg 密钥和 ssh 密钥。

参考资料 #

关于 Win32-OpenSSH 与 Gpg4win 的兼容问题的讨论 #

详见 GitHub Issue (Closed): https://github.com/PowerShell/Win32-OpenSSH/issues/827

关于将win命名管道(ssh-agent)转发到WSL内部的几种方案 #

(1)npiperelay

(本文围绕此方案展开) 这是一个通用的win命名管道转发工具(不限于转发 ssh-agent 管道),可将任意win命名管道转发到WSL内部。 详见开源项目: https://github.com/jstarks/npiperelay

(2)wsl-ssh-pageant

(本文不涉及此方案,仅记录) 这是一个可将 Gpg4win 的 ssh-agent 命名管道转发到WSL内部的工具。 详见博客: https://www.zhihu.com/tardis/bd/art/395212895

关于 gpg-connect-agent 等命令 #

ps1
# 启动 gpg-agent 服务
gpg-connect-agent /bye
# 也可以这样:
gpgconf --launch gpg-agent

# 重载 gpg-agent 服务
gpg-connect-agent reloadagent /bye
# 也可以这样:
gpgconf --reload gpg-agent

# 关闭 gpg-agent 服务
gpg-connect-agent killagent /bye
# 也可以这样:
gpgconf --kill all

关于ssh密钥管理 #

具体细节详见 gpg 篇 ssh-add 部分: Wiki/linux/man/gpg/gpg

2025年8月4日