如何通过qazxswpoi导入密钥并自动检查其指纹?理想情况下,我会直接使用gpg --recv-key
,但gpg --recv-key $fingerprint
,收到的密钥实际上有正确的指纹,而不是盲目地信任密钥服务器,并且修复程序没有落在我关心的所有发行版中(例如Docker Ubuntu Image仍然有一个旧的gpg版本)。
我想将它与gpg only recently added a check结合使用,将PPA添加到docker容器中。
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
来操作存储库密钥环。
实际上我已经遇到过这个页面,寻找与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。