如何不写入文件将远程主机GPG密钥传输导入至本地主机
实现GPG密钥直传导入的方案
问题现象
目标是实现类似ssh-copy-id的无文件落地GPG密钥迁移:不需要先把远程主机的GPG私钥导出成磁盘文件,直接通过SSH流传输到本地完成导入。
首次执行报错
执行命令:
ssh pi@192.168.0.42 gpg --export-secret-key A32D835B51CAF93AD264826E2C7AE63B68CDAB22 | gpg --import
返回错误:
gpg: directory '/home/foo/.gnupg' created gpg: keybox '/home/foo/.gnupg/pubring.kbx' created gpg: key F0A27839C3F40D2B42172A28124E5F88293B3719: error receiving key from agent: Inappropriate ioctl for device - skipped gpg: key 61322A2DACD3C52D35086D123704A5559C3E0456: error receiving key from agent: Inappropriate ioctl for device - skipped gpg: WARNING: nothing exported gpg: no valid OpenPGP data found. gpg: Total number processed: 0
调整参数后的异常
后续尝试添加口令相关参数执行:
stty -echo && ssh pi@192.168.0.42 "gpg --batch --passphrase-fd 0 --pinentry loopback --export-secret-key A32D835B51CAF93AD264826E2C7AE63B68CDAB22" | gpg import; stty echo
返回输出:
gpg: WARNING: no command supplied. Trying to guess what you mean ... gpg: can't open 'import' gpg: key F0A27839C3F40D2B42172A28124E5F88293B3719: error receiving key from agent: No passphrase given - skipped gpg: key 61322A2DACD3C52D35086D123704A5559C3E0456: error receiving key from agent: No passphrase given - skipped gpg: WARNING: nothing exported
执行过程中输出第一行警告后进程卡住,必须按下回车键才会退出,始终无法完成导入。
根因分析
- 首次执行的
Inappropriate ioctl for device错误:默认SSH非交互式执行远程命令时不会分配伪终端(tty),远程主机上的gpg-agent无法唤起pinentry程序读取密钥保护口令,导致密钥导出失败。 - 第二次执行的异常来自两个问题:
- 本地导入命令参数书写错误:
gpg import缺少参数前缀双横杠,正确写法为gpg --import,因此触发“无有效命令、找不到import文件”的报错。 - 标准输入流冲突:
--passphrase-fd 0指定从标准输入读取口令,但此时SSH连接的标准输入、本地gpg的标准输入和管道流绑定在一起,远程gpg无法读取到用户输入的口令,同时输入流被两个进程抢占导致进程卡住。
- 本地导入命令参数书写错误:
可用解决方案
方案1:分配伪终端交互输入口令(推荐,安全性最高)
给SSH加-t参数强制分配伪终端,远程gpg可以正常唤起pinentry要求输入密钥口令,导出的密钥二进制流直接通过管道传给本地gpg导入,全程不会在磁盘写入临时密钥文件:
ssh -t pi@192.168.0.42 "gpg --export-secret-key A32D835B51CAF93AD264826E2C7AE63B68CDAB22" | gpg --import
执行后根据提示在远程pinentry窗口输入GPG密钥的保护口令即可完成导入。
方案2:Loopback模式自动传入口令
如果需要避免交互输入,可以先在远程主机配置gpg-agent允许loopback口令模式,再通过环境变量传入口令完成导出导入:
- 先在远程主机配置gpg-agent(仅需执行一次):
ssh pi@192.168.0.42 "echo 'allow-loopback-pinentry' >> ~/.gnupg/gpg-agent.conf && gpgconf --reload gpg-agent" - 本地读取口令后执行传输导入:
read -s -p "输入远程GPG密钥保护口令: " GPG_PASS ssh pi@192.168.0.42 "gpg --batch --pinentry-mode loopback --passphrase '$GPG_PASS' --export-secret-key A32D835B51CAF93AD264826E2C7AE63B68CDAB22" | gpg --import unset GPG_PASS
注意:该方案下口令会短暂出现在远程进程的命令行参数中,高安全要求场景优先选择方案1。
内容的提问来源于stack exchange,提问作者EricVonB
相关产品推荐
相关产品推荐

