WSL2 ssh-agent #
这篇文章中的方案只能转发 Windows 侧的 \\.\pipe\openssh-ssh-agent
管道到 WSL2,
不能转发其他管道(如 %APPDATA%\Local\gnupg\S.gpg-agent
,实际上这不是管道,是一个普通文件,首行内容是 gpg-agent 监听端口)。
推荐另一种方案,详见
wsl2-gpg-agent-bridge 。
简介 #
- ssh 是一种远程连接工具。
- ssh-agent 是用来管理ssh密钥的一种服务,通过管道的方式来跟ssh客户端交互密钥信息。
- gpg 是一种密钥管理工具,可提供 gpg-agent 服务。Gpg4win 是gpg在Windows下的一种实现。
- gpg-agent 是用来管理gpg密钥的一种服务,具有 ssh-agent 功能。
- 在使用 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密钥。 - 上述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
添加以下配置内容:
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 服务:
gpg-connect-agent reloadagent /bye
三、配置环境和自启脚本 #
配置 PowerShell 的 profile 脚本 #
PowerShell 的 profile 脚本是一个可编辑的启动脚本,每次打开 PowerShell 窗口时自动执行一遍。 下面编辑这个脚本,添加 gpg-agent 启动命令。
(1)使用编辑器打开 profile 配置文件:
# 使用记事本打开:
notepad $PROFILE
# 或者使用VSCode打开:
code $PROFILE
(2)按需添加配置内容:
# 启动 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
# Start gpg-agent
gpg-connect-agent /bye
(2)添加vbs脚本文件,放到固定位置,如:C:\YourPath\init.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 中配置管道转发服务 #
准备环境 #
# 安装 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
[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)启用服务:
sudo systemctl enable --now win-ssh-agent-relay.service
(3)rc文件添加配置内容:~/.bashrc
# Enable ssh-agent
export SSH_AUTH_SOCK="/var/run/win-ssh-agent-relay.socket"
五、配置 Git Bash #
git sshCommand #
给git配置ssh命令:
# PowerShell 或 Git Bash 中执行以下命令(相关配置文件 ~/.gitconfig):
git config --global core.sshCommand C:/Windows/System32/OpenSSH/ssh.exe
PATH 环境变量 #
将 PATH 中的 /c/WINDOWS/System32/OpenSSH 目录移到开头。
添加配置内容:~/.bashrc
_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 目录 #
- 此目录一般是由 Git Bash 中自带的 gpg 客户端创建,但是经过以上配置之后不再推荐使用此 gpg 实例。
- 真正的 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 等命令 #
# 启动 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