使用`gpg --recv-key`下载密钥,同时在脚本中检查指纹

问题描述 投票:3回答:2

如何通过q​​azxswpoi导入密钥并自动检查其指纹?理想情况下,我会直接使用gpg --recv-key,但gpg --recv-key $fingerprint,收到的密钥实际上有正确的指纹,而不是盲目地信任密钥服务器,并且修复程序没有落在我关心的所有发行版中(例如Docker Ubuntu Image仍然有一个旧的gpg版本)。

我想将它与gpg only recently added a check结合使用,将PPA添加到docker容器中。

docker apt pgp gnupg
2个回答
3
投票

解:

apt-key

如果无法下载密钥或密钥服务器返回恶意密钥,则此脚本将返回非零退出代码。注意:恶意密钥仍然存在于gpg密钥环中,因此如果您在Dockerfile之外使用它,您可能希望之后恢复原始密钥环。用于Dockerfile的命令(以生成PPA为例):

#!/bin/bash
set -e
tempName=$(mktemp)
gpg --status-fd 1 --keyserver keyserver.ubuntu.com --recv-keys $fingerprint 1> $tempName 2>/dev/null
grep "^\[GNUPG\:\] IMPORT_OK "[[:digit:]]*" "$fingerprint"$" $tempName
grep "^\[GNUPG\:\] IMPORT_RES 1" $tempName

说明:

要考虑的第一个构建块是GnuPGs RUN echo "deb http://ppa.launchpad.net/hansjorg/rust/ubuntu trusty main" >> /etc/apt/sources.list RUN echo "deb-src http://ppa.launchpad.net/hansjorg/rust/ubuntu trusty main" >> /etc/apt/sources.list RUN bash -c 'set -e;tempName=$(mktemp);apt-key adv --status-fd 1 --keyserver keyserver.ubuntu.com --recv-keys C03264CD6CADC10BFD6E708B37FD5E80BD6B6386 1> $tempName 2>/dev/null;grep "^\[GNUPG\:\] IMPORT_OK [[:digit:]]* C03264CD6CADC10BFD6E708B37FD5E80BD6B6386$" $tempName;grep "^\[GNUPG\:\] IMPORT_RES 1" $tempName' 选项。它告诉gpg将机器可读输出写入给定的文件描述符。文件描述符--status-fd总是引用stdout,所以我们将使用它。然后我们将不得不找出1的输出结果。该文档不在联机帮助页中,而是在--status-fd中。示例输出如下所示:

doc/DETAILS

所以我们正在寻找# gpg --status-fd 1 --keyserver keyserver.ubuntu.com --recv-keys BD6B6386 2>/dev/null [GNUPG:] IMPORTED 37FD5E80BD6B6386 Launchpad PPA for Hans Jørgen Hoel [GNUPG:] IMPORT_OK 1 C03264CD6CADC10BFD6E708B37FD5E80BD6B6386 [GNUPG:] IMPORT_RES 1 0 1 1 0 0 0 0 0 0 0 0 0 0 IMPORT_OK线。 IMPORT_RES之后的第二个参数是导入密钥的实际指纹。 IMPORT_OK之后的第一个参数是导入的键数。

在输出中,IMPORT_RES,所以可以匹配以gpg escapes newlines开头的行来断言我们不匹配由攻击者控制的字符串(例如,键中的名称字段否则可以包含[GNUPG:]并通过创建匹配来欺骗我们)。

使用grep,我们可以通过\n[GNUPG:] IMPORT_OK 1 C03264CD6CADC10BFD6E708B37FD5E80BD6B6386]匹配以[GNUPG] sometext开头的行,并使用grep "^\[GNUPG\:\]"匹配整行(grep "^\[GNUPG\:\] sometext$"^代表行的开头和结尾)。根据文档,$之后的任何数字对我们都没问题,所以我们匹配IMPORT_OK。因此,作为正则表达式,我们得到"[[:digit:]]*""^\[GNUPG\:\] IMPORT_OK "[[:digit:]]*" "$fingerprint"$"

由于我们希望将输出匹配两次,我们将其保存到一个临时文件中(通过使用"^\[GNUPG\:\] IMPORT_RES 1"创建一个空的临时文件并重新路由该文件中的输出)。如果mktemp与任何行匹配,则返回非零错误代码。我们可以通过指示grep通过bash中止任何错误来使用它。总的来说,我们最终得到:

set -e

如何使用set -e tempName=$(mktemp) gpg --status-fd 1 --keyserver keyserver.ubuntu.com --recv-keys $fingerprint 1> $tempName 2>/dev/null grep "^\[GNUPG\:\] IMPORT_OK "[[:digit:]]*" "$fingerprint"$" $tempName grep "^\[GNUPG\:\] IMPORT_RES 1" $tempName 添加存储库密钥:apt使用apt-key命令直接将命令行参数移交给gpg(运行上面的命令而不输出重新路由以查看adv生成的实际gpg命令)。所以我们可以简单地用apt-key交换gpg来操作存储库密钥环。


0
投票

实际上我已经遇到过这个页面,寻找与OP描述类似的问题的解决方案。提到apt-key adv解决方案是可以的,并且应该在大多数常见发行版中由gpg支持。但在我的情况下,我有另一个限制。 Gpg的网络通信功能在不久前被移到了单独的包gpg --recv-key $fingerprint。从Yakkety Yak(即dirmngr)开始,默认的Ubuntu安装中不包含该软件包,您必须手动安装它才能完成上述命令。只要我的Docker镜像是非常小的Ubuntu设置,我就试图避免这种情况。所以我找到了一些可能有用的替代解决方案。即我正在以这种方式从位于nginx.org的存储库安装Nginx服务器:

this bug

代码摘自Dockerfile,在shell中运行它删除RUN set -Eeuxo pipefail; \ # The keyring is placed in temporary directory export GNUPGHOME="$(mktemp -d)"; \ # Nginx public key (used for signing packages and repositories) NGINX_GPGKEY=0x573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62; \ # Pool of high-available keyservers KEYSERVER=ha.pool.sks-keyservers.net:11371; \ # HKP protocol can be easily represented as HTTP query. The key is imported into temporary keyring. curl -LfSs "http://$KEYSERVER/pks/lookup?op=get&search=$NGINX_GPGKEY&options=mr&exact=on" | gpg --import -; \ # Additional check that imported key is the right one before copying it to apt trusted database gpg --export "$NGINX_GPGKEY" | apt-key --keyring /etc/apt/trusted.gpg.d/nginx.gpg add -; \ # Adding nginx.org repository to the sources list echo "deb [arch=amd64] http://nginx.org/packages/mainline/ubuntu/ $(. /etc/lsb-release; echo $DISTRIB_CODENAME) nginx" > /etc/apt/sources.list.d/nginx.list; \ # Installing Nginx apt-get update; \ apt-get install -y --no-install-recommends --no-install-suggests nginx; \ # Removing apt cached files apt-get clean; \ rm -rf /var/lib/apt/lists/*; \ # Removing temporary keyring rm -rf "$GNUPGHOME" 部分和所有注释(以RUN开头的行)。此外,如果没有在Dockerfile内运行导出#可能会干扰正常的gpg行为。为了避免在子shell中运行整个命令 - 用括号GNUPGHOME换行或者之后运行unset - (command)。因此,使用curl从密钥服务器检索密钥(普通的http查询和特定的URL参数用于模拟HKP协议)并导入临时密钥环。然后通过使用特定的KEYID参数导出它,我们在密钥服务器的答案被篡改的情况下校对密钥身份。密钥被导入到不同的密钥环unset GNUPGHOME,以便以后通过删除文件轻松删除它。实际上没有必要使用/etc/apt/trusted.gpg.d/nginx.gpg,你可以改为将apt-key输出重定向到文件:gpg --export

命令是相当不言自明的,只是一些额外的评论:HKP协议描述可以找到gpg --export "$NGINX_GPGKEY" > /etc/apt/trusted.gpg.d/nginx.gpg,也here很好解释为什么使用最初的there

© www.soinside.com 2019 - 2024. All rights reserved.