解决 WSL 下 gpg 签名 git commit 报错
问题描述
WSL 中使用以下使用 gpg 对提交的更改并进行签名:
git commit -S -s -m 'This is my commit message'
出现以下报错:
error: gpg failed to sign the data
fatal: failed to write commit object
原因分析
pinentry 是 GnuPG 的密码输入工具,默认情况下会弹出一个图形化窗口来请求用户输入密码,但是在 WSL2 环境中,由于没有图形桌面环境,密码输入框无法弹出,导致 gpg 签名无法继续进行。
解决方案
针对上述分析,笔者梳理了目前常见的三种解决方案,分别利用了 pinentry 回环模式、gpg-agent 缓存机制、socket 重定向以及 WSL 客户机与宿主机的互通性,其中笔者采用的是最后一种方案,直接调用 Windows 下的 gpg.exe,以实现与 vscode 优雅集成。
回环模式
使用以下命令配置 pinentry 启用 loopback 模式:
echo -e '\nuse-agent\npinentry-mode loopback' >> ~/.gnupg/gpg.conf
echo -e '\nallow-loopback-pinentry' >> ~/.gnupg/gpg-agent.conf
上述命令首先启用 GPG 代理并设置密码输入模式为 “回环模式”,接着配置 gpg-agent 允许使用回环模式进行密码输入。此时,密码输入将通过命令行回传给 GnuPG,而不是依赖图形界面。
这种方案有效解决了密码输入框无法弹出的问题,但是只能在终端环境下使用,如果日常使用 vscode 配合 WSL 进行开发,则无法直接在 vscode 中直接提交 git commit,降低了开发体验。此外,通过命令行回传密码通常也被认为不够安全。
gpg-agent 缓存
gpg-agent 会缓存我们输入的密码,在缓存有效期内我们对数据签名不需要重复输入密码,因此我们可以写一个 shell 脚本并设置合适的密码缓存时间,这样就能够实现开机后手动输入一次密码,之后就能顺利使用 vscode 提交 git commit。
笔者写了一个示例脚本供各位参考:
gpg-login() {
export GPG_TTY=$TTY
echo "test" | gpg --clearsign > /dev/null 2>&1
}
gpg-logout() {
echo RELOADAGENT | gpg-connect-agent
}
gpg-login()
函数首先将 gpg 重定向到当前终端,然后对字符串 test
进行签名,这个过程需要在终端中输入密码,之后密码就能被缓存下来。将上述代码添加到 ~/.bashrc
文件中,然后在终端输入 gpg-login
就能输入并缓存密码,输入 gpg-logout
则可以及时清除已经缓存的密码,避免安全隐患。
gpg-agent 的缓存时间可以在 ~/.gnupg/gpg-agent.conf
文件中配置,具体如下:
default-cache-ttl 21600
max-cache-ttl 21600
数字的单位为秒,上述配置将缓存时间设置为 6 小时,基本能够满足使用需求。
socket 重定向
通过 socat
命令将 WSL 中的 gpg-agent socket 重定向到 Windows 下的 gpg-agent,以间接实现调用 Windows 下的各种认证服务,比如生物识别、硬件密钥等。这种方式有很多开源的解决方案,如 tmuntaner/wsl-gpg-agent,demonbane/wsl-gpg-systemd 和 mkulke/wsl-gpg-relay 等,由于配置步骤较为复杂,笔者这里不再展开赘述,感兴趣的读者可以参考上述项目的具体实现。
直接调用 gpg.exe
socket 重定向方案的目标是间接调用 Windows 下的 gpg 服务,考虑到 WSL 与宿主机在网络访问、文件系统等方面均互联互通,我们其实可以直接配置 git 使用 Windows 下的 gpg.exe:
git config --global gpg.program /mnt/c/PROGRA~2/GnuPG/bin/gpg.exe
笔者电脑上安装的是 gpg4win,具体路径为 C:\Program Files (x86)\GnuPG\bin\gpg.exe
,由于 Program Files (x86)
带有空格在命令行中不方便输入,这里使用短文件名 PROGRA~2
替代。
这种方案相比映射 socket 省去了繁琐复杂的配置,也避免了前两个方案使用命令行回传密码带来的潜在安全隐患,同时还能够与 vscode 无缝集成,整体来看是一个不错的解决方案。