修复 apt-key deprecated 警告

2023-07-28 ⏳3.2分钟(1.3千字)

我的服务器使用 Ubuntu LTS 版本。之前是 20.04,升级到 22.04 之后,每次更新系统都会报一堆警告信息。虽然不影响功能,但肯定是哪里出了问题,作为强迫症患者的我肯定要一查究究。查一来发现是跟 apt-key 被弃用有关,整个 apt 的签名系统有了新的配置方案。今天就跟大家分享一下处理过程。

系统升级之后每次运行 apt-get update 都有如下警告:

W: http://security.ubuntu.com/ubuntu/dists/jammy-security/InRelease: Key is stored in legacy trusted.gpg keyring (/etc/a
pt/trusted.gpg), see the DEPRECATION section in apt-key(8) for details.
W: http://archive.ubuntu.com/ubuntu/dists/jammy/InRelease: Key is stored in legacy trusted.gpg keyring (/etc/apt/trusted
.gpg), see the DEPRECATION section in apt-key(8) for details.
W: http://archive.ubuntu.com/ubuntu/dists/jammy-updates/InRelease: Key is stored in legacy trusted.gpg keyring (/etc/apt
/trusted.gpg), see the DEPRECATION section in apt-key(8) for details.
W: http://archive.ubuntu.com/ubuntu/dists/jammy-backports/InRelease: Key is stored in legacy trusted.gpg keyring (/etc/a
pt/trusted.gpg), see the DEPRECATION section in apt-key(8) for details.

说是上面几个软件仓库的签名公钥1还保存在 trusted.gpg 文件,现在已经不推荐使用了,具体请参考 apt-key(8) 手册的 DEPRECATION 部分。

我看了手册,主要说现在推荐把签名公钥保存到 /etc/apt/trusted.gpg.d 目录,每个 key 使用单独的文件保存。现在的问题是怎么提取上面的 key。

apt-key 有一个 list 子命令:

$ sudo apt-key list
Warning: apt-key is deprecated. Manage keyring files in trusted.gpg.d instead (see apt-key(8)).
/etc/apt/trusted.gpg
--------------------
pub   rsa4096 2018-09-17 [SC]
      F6EC B376 2474 EDA9 D21B  7022 8719 20D1 991B C93C
uid           [ unknown] Ubuntu Archive Automatic Signing Key (2018) <[email protected]>

这是 Ubuntu 官方用的签名 key。讲道理应该在系统升级的时候自动保存到新的位置才对。现在我们需要手工导出再导入。

导出 key 需要用到它的 ID,也就是第二行的最后两部分 991BC93C,合到一起,配使 apt-key export 命令:

$ sudo apt-key export 991BC93C
Warning: apt-key is deprecated. Manage keyring files in trusted.gpg.d instead (see apt-key(8)).
-----BEGIN PGP PUBLIC KEY BLOCK-----

mQINBFufwdoBEADv/Gxytx/LcSXYuM0MwKojbBye81s0G1nEx+lz6VAUpIUZnbkq
...
-----END PGP PUBLIC KEY BLOCK-----

BEGINEND 之间的部分就是导出的公钥。因为 apt-key 已经不推荐使用,所以屏幕上会输出另一条警告信息:

Warning: apt-key is deprecated. Manage keyring files in trusted.gpg.d instead (see apt-key(8)).

apt-key 输出的是 ASCII 格式,但我们需要保存成二进制格式,所以需要使用 gpg 工具做转换:

sudo apt-key export 991BC93C | sudo gpg --dearmour \
  -o /etc/apt/trusted.gpg.d/ubuntu-keyring-2018-archive.gpg

-o 表示将转换后的内容保存到指定路径。执行这步操作之后再更新系统,就不会看到上面的警告了。我们现在可以删除 trusted.gpg 中的公钥:

sudo apt-key del 991BC93C

其实在我的服务器上,trusted.gpg.d 已有存在 ubuntu-keyring-2018-archive.gpg~ 文件。我也不知道是怎么创建的。直接去掉最后 ~ 就可以了。

现在更新系统就不会有告警,就很治愈~

$$ sudo aptitude update
Hit http://archive.ubuntu.com/ubuntu jammy InRelease
Get: 1 http://archive.ubuntu.com/ubuntu jammy-backports InRelease [108 kB]
Get: 2 https://deb.goaccess.io jammy InRelease [3062 B]
Get: 3 http://security.ubuntu.com/ubuntu jammy-security InRelease [110 kB]
Get: 4 http://archive.ubuntu.com/ubuntu jammy-updates InRelease [119 kB]
Hit https://apt.syncthing.net syncthing InRelease
Fetched 340 kB in 1s (345 kB/s)

从 trusted.gpg 到 trusted.gpg.d 是一个进步,因为可以比较方便地查看当前有哪些 key,添加删除也比较容易。但这种方式还有一个安全隐患,这就是所谓的交叉签名。

假如我们添加了 A 和 B 两个软件仓库,那么就需要添加 GAG_AGBG_B 两个公钥。公钥添加之后,系统就会局信任 GAG_AGBG_B,哪怕是 B 仓库的软件用了 A 的密钥来签名,系统也认,对应的软件也能正常安装。这就是所谓的交叉签名。

为了让系统安全运行,我们应该坚持最小信任原则。也就是说 GAG_A 只能用于签 A 仓库的软件,GBG_B 亦然。那么原来使用 trusted.gpg 和 trusted.gpg.d 这种全局信任的方式就不推荐了。

我的系统里装有 Syncthing2。因为 Ubunut 官方仓库里的版本较低,我配置了 Syncthing 官方的 APT 源。正好以此为例说明。

首先在创建 /etc/apt/sources.list.d/syncthing.list 文件,内容如下:

deb [signed-by=/etc/apt/keyrings/syncthing.gpg] https://apt.syncthing.net/ syncthing stable

然后下载签名公钥:

sudo curl -o /etc/apt/keyrings/syncthing.gpg https://syncthing.net/release-key.gpg

这里用 signed-by 指定签名公钥的文件路径,我把它保存到 /etc/apt/keyrings/ 目录。这也是 APT 系统推荐的位置。这样配置下来,syncthing.gpg 只能用于验证 Syncthing 官方仓库的软件。Syncthing 的签名密钥就算是意外泄露,也不会被用来签其他仓库的软件。

虽然实现这种攻击的可能性比较小,但安全无小事。所以建议大家都尽快迁移到最新的 signed-by 方案。

除了做软件签名外,GPG 还被用到各种各样的领域。离我们最近的要属 Git 了。我们可以用自己的私钥对 Git 的提交内容做签名,别人可以用我们发布的公钥验证。我们也可以把 GPT 公钥发布到 GitHub 上,GitHub 会自动显示验证标志。不过普通的开发者很少有生成自己的 GPG 官钥。后来 OpenSSH 也支持使用 SSH 密钥给任意数据做签名,一定程度上可以替换 GPG。大多数开发者应该都有自己的 SSH 官钥吧,甚至 Git 也支持使用 SSH 官钥做签名了。有兴趣的读者可以参考我的另一篇文章


  1. 这里的签名公钥指 OpenPGP 的公钥,大部分 Linux 会使用 OpenPGP 对软件包做签名,防止被中间人篡改。↩︎

  2. 我的博客使用 Syncthing 自动发布文章,具体可参考 ./blog-internal.html↩︎