我在 Fedora 25 (F25) 工作站(KDE spin)上工作。我正在编写一些脚本来执行自动化测试。
其中一项自动化测试涉及调用 RPMSIGN(8) 程序,该程序又调用 GPG(1) 将数字签名附加到我正在创建的某些 RPM 文件中。当然,GPG 使用 pinentry(PIN 输入)来提示用户输入 RPM 签名密钥(RSA 密钥对)的密码。我想让人类脱离循环,完全自动化为 RPM 签名密钥提供密码的任务。(是的,我知道安全隐患。这只是一个自动化测试环境,而不是生产主机,所以我不太担心安全性。在生产版本中,用户将手动输入 RPM 签名密钥的密码。)
过去,我使用 EXPECT(1) 脚本等待 GPG 将文本“输入密码短语:”输出到控制台,然后 EXPECT 脚本将输入密码短语,然后继续。效果很好。
在 F25 中,pinentry 功能打破了我现有的基于 EXPECT 的解决方案,用于自动输入 RPM 签名密钥的密码。
当我在此 F25 主机上的 GUI 控制台窗口中运行 RPMSIGN 时,GPG 使用 pinentry 弹出一个 GUI 对话框,要求用户(我)输入 RPM 签名密钥的密码。当然,这种密码输入行为会干扰并阻止密码短语的自动输入。
如果我创建一个暂时取消设置 DISPLAY 环境变量的 Bash 脚本,那么我将不再获得 GUI 对话框,
#!/bin/bash
DISPLAY_SAVE=$DISPLAY
unset DISPLAY
rpmsign --resign "/path/to/test-1.0.0-1.fc25.noarch.rpm"
export DISPLAY=$DISPLAY_SAVE
但现在我在控制台上看到了该对话框的 ncurses 版本:
+----------------------------------------------------------------+
| Please enter the passphrase to unlock the OpenPGP secret key: |
| "Testing (rpm-sign)" |
| 1024-bit RSA key, ID 0123456789ABCDEF, |
| created 2016-12-02. |
| |
| |
| Passphrase: __________________________________________________ |
| |
| <OK> <Cancel> |
+----------------------------------------------------------------+
同样,pinentry-curses 的控制台“对话框”会干扰并阻止自动输入密码。
我不想永久修改或禁用 pinentry 模块;我只是想暂时禁用它们以返回 GPG 的 CLI 提示“输入密码:”(或现在的提示字符串),而不会受到 pinentry 的干扰。
对于通过 CLI 完全自动化输入 RPM 签名密钥的密码短语而不存在 pinentry 干扰,有什么建议吗?
答案1
感谢@Joe Damato 向我指出了该gpg-preset-passphrase
实用程序。下面描述的解决方案是在已安装的 Fedora 25 主机上开发和测试的gnupg2-2.1.x
。
(注意,我还没有弄清楚如何在运行旧版本 GnuPG 的平台上确定 RPM 签名密钥的 keygrip 值,因为它们不支持该--with-keygrip
选项。如果有人想对此解决方案发表评论,请这样做。)
确保~/.gnupg/gpg-agent.conf
包含该行。
allow-preset-passphrase
修改后~/.gnupg/gpg-agent.conf
重新加载gpg-agent。
$ gpg-connect-agent reloadagent /bye
OK
列出您的 GPG 密钥以获得 RPM 签名密钥的八个十六进制数字密钥 ID。在此示例中,密钥 ID 为0123ABCD
。
$ gpg --list-keys
/home/me/.gnupg/pubring.gpg
-----------------------------------
pub 1024R/0123ABCD 2015-06-13
uid Test (rpm-sign)
获取 RPM 签名密钥的 keygrip 代码。 (注意,在我用于测试的 RHEL 7.2 和 Fedora 20 主机上,GPG2(1)
这些主机上的程序无法识别该--with-keygrip
选项。)
$ gpg2 --with-keygrip -K 0123ABCD
sec rsa1024 2015-06-13 [SCEA]
0A1B2C3D4E5F6A7B8C9D0E0F1A2B3C4D0123ABCD
Keygrip = 2EACA0C5A4B46168EB91970B6715AF1AA52968BE
uid [ unknown] Test (rpm-sign)
缓存 RPM 签名密钥的密码。在下面显示的命令行中,替换'PASSPHRASE'
为 RPM 签名密钥的实际密码。
$ /usr/libexec/gpg-preset-passphrase --passphrase 'PASSPHRASE' --preset 2EACA0C5A4B46168EB91970B6715AF1AA52968BE
:: 测试 ::
创建未签名的测试 RPM 文件。验证测试 RPM 文件是否未签名。
$ rpm --checksig test-1.0.0-1.f25.noarch.rpm
test-1.0.0-1.fc25.noarch.rpm: sha1 md5 OK
验证在签署测试 RPM 文件时RPMSIGN(8)
是否使用缓存的密码(即,不会RPMSIGN(8)
提示您输入 RPM 签名密钥的密码)。
$ rpmsign --resign test-1.0.0-1.f25.noarch.rpm
验证测试 RPM 文件是否已签名。
$ rpm --checksig test-1.0.0-1.f25.noarch.rpm
test-1.0.0-1.fc25.noarch.rpm: rsa sha1 (md5) pgp md5 OK
:: 附录 1 (2016-12-17) ::
根据这个GnuPG 第 2331 期网页:
gpg1 不知道 keygrips。 gpg1 使用指纹作为 gpg-agent 的缓存 ID,而不是 keygrip。 gpg1 使用的代理命令 GET_PASSPHRAE 使用与 gpg-preset-passphrases 使用的不同的缓存模式。因此,即使您用(子)钥匙的指纹替换钥匙柄,它也不起作用。
无论如何,我已经在 RHEL7 主机上使用 GnuPG 版本 2.0.x 进行了一些测试,但gpg-preset-passphrase
似乎不受支持。我只能gpg-preset-passphrase
使用 GnuPG 版本 2.1.x。
参考
答案2
%__gpg_sign_cmd
通过在文件中添加/修改宏.rpmmacros
,您可以告诉 gpg 从文件中读取密码。使用rpm --showrc
查看当前的情况%__gpg_sign_cmd
,然后将其放入.rpmmacros
文件中,并添加以下内容:
--batch --pinentry-mode loopback --passphrase-file /path/to/passphrase-file
\
如果您有多行值,请确保除最后一行之外的每一行都以 结束。
这将导致 gpg 不会以任何方式提示输入密码,而是从定义的文件中读取它。这构成了一个安全风险当然,所以请考虑这是否是您想要做的事情,并采取任何必要的措施来确保它的安全(例如所有权和许可)。
完整的%__gpg_sign_cmd
示例.rpmmacros
:
%__gpg_sign_cmd %{__gpg} \
gpg --no-verbose --no-armor --batch --pinentry-mode loopback \
--passphrase-file /path/to/passphrase-file \
%{?_gpg_digest_algo:--digest-algo %{_gpg_digest_algo}} \
--no-secmem-warning \
-u "%{_gpg_name}" -sbo %{__signature_filename} %{__plaintext_filename}
签署包裹:
$ rpm --checksig somepackage.rpm
somepackage.rpm: sha1 md5 OK
$ rpmsign --addsign somepackage.rpm
somepackage.rpm:
$ rpm --checksig somepackage.rpm
somepackage.rpm: rsa sha1 (md5) pgp md5 OK
答案3
解决此类问题的一种方法是使用gpg-agent
,它管理 GPG 密钥。您可以结合使用该工具gpg-preset-passphrase
将密码短语植入gpg-agent
缓存中。阅读有关 gpg-agent 的更多信息这里。这将使您无需手动输入密码,以便执行自动化任务。
顺便说一句,我写了一篇有用的博客文章GPG 签名和验证 RPM 包和 YUM 存储库您可能也会觉得有用。
答案4
对于带有 GPG 2.0 的 CentOS7(我猜是 RedHat7), 和pinentry-mode
不起作用gpg-preset-passphrase
。
我设法让它工作使用预计。
#!/usr/bin/expect -f
### rpm-sign.exp -- Sign RPMs by sending the passphrase.
spawn rpm --addsign {*}$argv
expect -exact "Enter pass phrase: "
send -- "Secret passphrase\r"
expect eof
## end of rpm-sign.exp
用法
$ ./rpm-sign.exp PACKAGE-FILE
致谢亚伦·S·霍利 (Aaron S. Hawley)GPG 在无人值守的情况下签署 RPM