Ubuntu Weekly Recipe

第675回apt-keyはなぜ廃止予定となったのか

サードパーティのAPTパッケージリポジトリを追加する際に使用する「apt-key」コマンドは、2020年8月の2.1.8から「廃止予定(deprecated⁠⁠」となり、2022年の半ばには削除される予定になりました。今回はその理由と、代替手段について解説しましょう。

リポジトリの正当性を担保する仕組み

Linuxにおけるパッケージ管理システムは、システムの重要なデータを置き換えるクリティカルな操作です。よってインターネットの先からパッケージをダウンロードする際は、その正当性を確認しなければなりません。⁠パッケージの正当性」と言ったとき、一般的には複数の意味が含まれます。

  1. パッケージに悪意のあるコードが含まれていないこと
  2. パッケージメンテナ以外の第三者が作ったパッケージがリポジトリにアップロードされていないこと
  3. 本来のリポジトリとは別の場所からパッケージをダウンロードしていないこと

まず一番気になる1についてですが、ここに関してはAPTによる保護の対象外です。利用者はそのパッケージのメンテナーを信頼することしかできません。言い換えると、PPAを含むサードパーティのリポジトリを登録する際は、便利かどうかだけでなく信頼できるかどうかも検討しましょう。

2も厳密にはAPTの対象外です。Ubuntuの公式リポジトリの場合は、ソースパッケージのアップロードにはメンテナーの署名が必要ですし、その署名を検証した上でビルドサーバーがパッケージをビルドし、適切な場所に配置します。しかしながら利用者の観点からすると、この部分についてもリポジトリの管理者を信頼する以外に手はありません。

APTで正当性を確認するのは、実質3のみです。正しい管理者が、悪意のあるコードを含まないパッケージをリポジトリにアップロードし正しく運用しているという前提のもと、ダウンロードしようとしているのが、その管理者によってアップロードされたパッケージであることを保証します。

この「正当性を保証」するために、APTの場合はGPGを利用した公開鍵方式で検証しています。バージョンや設定、リポジトリによって若干の差異はありますが、リポジトリからパッケージをダウンロードする際の検証方法は次のとおりです。

  1. sources.listに記録されているURLからInReleaseファイルをダウンロードする
  2. InReleaseファイルを、ローカルにあらかじめ保存しておいたリポジトリ鍵で検証する
  3. main/binary-amd64/PackagesなどのPackagesファイルをダウンロードする
  4. Packagesファイルのハッシュを、InReleaseの中の情報で検証する
  5. Packagesのパスに応じてpool/main/以下などから、対象のパッケージファイルをダウンロードする
  6. ダウンロードしたパッケージファイルのハッシュを、Packagesファイルの中の情報で検証する

InReleaseに対する署名は、リポジトリ鍵と対になる秘密鍵を持った人だけが可能です。つまりこれはリポジトリそのものの管理者であり、Ubuntuの公式リポジトリは「ftpmaster」と呼ばれます。このInReleaseの署名から続く検証の流れによって、ダウンロードしたパッケージファイルがリポジトリの管理者によるサイトからダウンロードしたことを確認できるわけです[1]⁠。

たとえばUbuntu 20.04 LTSのある日のInReleaseファイル[2]は次のような内容になっています。

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

Origin: Ubuntu
Label: Ubuntu
Suite: focal
Version: 20.04
Codename: focal
Date: Thu, 23 Apr 2020 17:33:17 UTC
Architectures: amd64 arm64 armhf i386 ppc64el riscv64 s390x
Components: main restricted universe multiverse
Description: Ubuntu Focal 20.04
(中略)
 7ef83228ec207df10acac48fbdd81112          5826751 main/binary-amd64/Packages
(中略)
+m9MS1XP0RN13iWp3zXSlWJGPO/mDezqQ7vZ8Iwx
=7xQ1
-----END PGP SIGNATURE-----

Packagesも含むメタデータ情報のURLが示すコンテンツごとの、MD5SUM/SHA1/SHA256のハッシュ値を掲載しています。

それに対してリポジトリからダウンロードできる、Packagesファイル[3]は上記のように、さまざまなハッシュ値を持った次のようなファイルになっています。

Package: accountsservice
Architecture: amd64
Version: 0.6.55-0ubuntu13.2
Priority: standard
Section: gnome
Origin: Ubuntu
Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
Original-Maintainer: Debian freedesktop.org maintainers <pkg-freedesktop-maintainers@lists.alioth.debian.org>
Bugs: https://bugs.launchpad.net/ubuntu/+filebug
Installed-Size: 452
Depends: dbus, libaccountsservice0 (= 0.6.55-0ubuntu13.2), libc6 (>= 2.4), libglib2.0-0 (>= 2.44), libpolkit-gobject-1-0 (>= 0.99)
Suggests: gnome-control-center
Filename: pool/main/a/accountsservice/accountsservice_0.6.55-0ubuntu13.2_amd64.deb
Size: 61424
MD5sum: 8d0c520e5edae8a0526a76982530ce2a
SHA1: 6859166c5c490cf4be3ce74dce3816bb56d4a5f0
SHA256: 344201d66fa1327b1dfce472dc062c5eba482f4caaecb1b832ec658869660b51
SHA512: 964b9ceef71c3cb3cf88dfda3344814c19030de01a59d514268bb2fa89d6495bf9bd587a44517aa960f71b06c04550d5fe9b9cfbd83840e06179708adc4e85cf
Homepage: https://www.freedesktop.org/wiki/Software/AccountsService/
Description: query and manipulate user account information
Task: standard
Description-md5: 8aeed0a03c7cd494f0c4b8d977483d7e

Package: acct
Architecture: amd64
(後略)

そしてaccountsservice_0.6.55-0ubuntu13.2_amd64.debは、上記で列挙されているハッシュ値で検証することで、正当性を確認できるわけです。これによりUbuntuのリポジトリは、HTTPSなどを使わなくても中間者攻撃の心配をする必要なくパッケージをダウンロードできます[4]⁠。

ここでポイントになってくるのが、InReleaseの署名を検証するための「リポジトリ鍵」です。リポジトリの管理者が秘密鍵を使ってInReleaseを署名するとして、利用者はその公開鍵を何らかの方法で取得・管理しなくてはなりません。Ubuntuの公式リポジトリについては、⁠インストーラーに組み込む」ことで自動的に登録されます。これはubuntu-keyringパッケージとして提供されています。

$ gpg --list-keys --keyring /etc/apt/trusted.gpg.d/ubuntu-keyring-2018-archive.gpg
/etc/apt/trusted.gpg.d/ubuntu-keyring-2018-archive.gpg
------------------------------------------------------
pub   rsa4096 2018-09-17 [SC]
      F6ECB3762474EDA9D21B7022871920D1991BC93C
uid           [  不明  ] Ubuntu Archive Automatic Signing Key (2018) <ftpmaster@ubuntu.com>

たとえばInReleaseファイルをダウンロードして検証してみましょう。

$ wget http://jp.archive.ubuntu.com/ubuntu/dists/focal/InRelease
$ gpgv --keyring /etc/apt/trusted.gpg.d/ubuntu-keyring-2018-archive.gpg InRelease
gpgv: 2020年04月24日 02時34分17秒 JSTに施された署名
gpgv:                RSA鍵3B4FE6ACC0B21F32を使用
gpgv: 署名を検査できません: 公開鍵がありません
gpgv: 2020年04月24日 02時34分17秒 JSTに施された署名
gpgv:                RSA鍵871920D1991BC93Cを使用
gpgv: "Ubuntu Archive Automatic Signing Key (2018) <ftpmaster@ubuntu.com>"からの正しい署名

鍵「3B4FE6ACC0B21F32」は2018年より前に使われていた鍵です。古いリリースのUbuntuでも検証できるように、古い鍵でも署名されています。

このようにAPTによるパッケージの正当性は、リポジトリ鍵に依存する仕組みになっています。そのリポジトリ鍵を管理するのがapt-keyコマンドだったのです。

apt-keyの仕組みと問題点

apt-keyはシステム上のリポジトリ鍵を管理するコマンドです。

apt-keyコマンドはAPTキーリング/etc/apt/trusted.gpgに、リポジトリ鍵としてGPG公開鍵を登録・削除します。つまり実態はGPGのキーリングそのものであり、GPGの鍵管理を行っているだけです。Ubuntuのインストール直後はUbuntuの公式リポジトリとインストーラーイメージの鍵しか登録されていませんが、PPA等のサードパーティのリポジトリを追加するごとに、ここに新しい鍵が追加されることになります。これにより、正しく運用されているリポジトリであれば、公式リポジトリと同じように安全にパッケージをダウンロードできるのです。

よく紹介される例は第458回のUbuntuでDocker再入門のようにサードパーティのリポジトリを追加する例ですね。最近はZoomやSlackのように、独自に「Linux向けバイナリパッケージ」を配る際も、パッケージリポジトリを作りアップデートの仕組みを提供することが増えてきました[5]⁠。このため各ベンダーは「まずはリポジトリの鍵をダウンロード・インストールする」ために、apt-keyを使う方法を提案しています。

そんな「apt-key」コマンドですが、2020年8月の2.1.8から「廃止予定(deprecated⁠⁠」となり、2022年の半ばには削除されることになりました[6]⁠。たとえばUbuntu 20.04 LTSのmanページだとタイトルが「apt-key - APT key management utility」だったのが20.10のmanページでは「apt-key - Deprecated APT key management utility」となっています。

また、実際にUbuntu 21.04などでapt-keyコマンドを使うと、次のような警告が表示されます。

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

これはセキュリティ上の懸念点からくるもので、簡単にまとめると次の2点が理由です。

  1. apt-key addは単一ファイル/etc/apt/trusted.gpgに鍵を追加していくため、複数のリスクの異なるリポジトリの鍵を同じ権限で管理しなくてはならない。
  2. リポジトリ鍵として追加した鍵は、すべてのリポジトリに対して適用される

実はどちらも昔から言われていたことで、⁠apt-keyはもう使うべきではない」というのは、遅くともDebian 9がリリースされた2017年頃には開発者側の共通見解だったようです。

1についてはapt-key addを使わずに、/etc/apt/trusted.gpg.d/以下に個別のリポジトリ鍵を置くという回避策があります。実際、Ubuntuの公式リポジトリの鍵は、上記のようにこの手法をとっています。しかしながらたとえファイルを分割したところで2については回避できません。

APTのリポジトリ鍵は「リポジトリの管理者を信頼する」つまり「そのリポジトリサーバーが正しく運用されていることを期待する」前提に立っています。しかしながらリポジトリ鍵を/etc/apt/trusted.gpg{,.d/}に取り込んでしまうと、あるサードパーティのリポジトリに問題が発生したとき、その影響範囲がシステムにインストールされているすべてのパッケージに波及することにほかなりません[7]⁠。

結局のところ/etc/apt/trusted.gpg.dは、⁠システムで利用するすべてのリポジトリ」に対するチェックを行うための鍵を置く場所なので、リスクの異なるサードパーティのリポジトリの鍵も同じように扱うのはおかしいという、ただそれだけの話です。

現時点ではapt-keyの代替となるCLIは用意されていないようです。

今後リポジトリ鍵はどう運用すべきか

すべての利用者がサードパーティのリポジトリの利用をまったくやめることは難しいため、引き続き何らかの形でリポジトリ鍵を取り込む必要があります。では、apt-keyがなくなったあとの「ベストプラクティス」はどうなるのでしょうか。

まもなくリリース予定のDebian 11の2021年7月17日時点でのリリースノートでは、/etc/apt/trusted.gpg.d/に個別にリポジトリ鍵を保存する方法を提案しています。apt-keyコマンドを実行したときの警告も同様です。

これはこれまでapt-key addに渡していたリポジトリ鍵を、単に/etc/apt/trusted.gpg.d/に保存するだけというシンプルなものです。このときバイナリ形式なら拡張子「gpg」を、ASCII形式なら「asc」を利用します。ただし一般的に配布されているリポジトリ鍵はASCII形式であることが大半で、さらにAPTでサポートしているフォーマットでない可能性があります。

よって次のような手順で、一旦適当な鍵束に取り込んでから、バイナリ形式でエクスポートするのが安全なようです。

$ gpg --no-default-keyring --keyring /tmp/temp-keyring.gpg \
    --import "ダウンロードしたリポジトリ鍵ファイル名"
$ gpg --no-default-keyring --keyring /tmp/temp-keyring.gpg \
    --export --output "リポジトリ名".gpg
$ rm /tmp/temp-keyring.gpg
$ sudo cp "リポジトリ名".gpg /etc/apt/trusted.gpg.d/

しかしながら、この方法ではサードパーティのリポジトリに対するリスク管理という観点からは、完全な対応とは言えません。実際、Debian Wikiにある情報ではあるもののサードパーティのリポジトリの利用のページにおいて、apt-keyコマンドだけでなく/etc/apt/trusted.gpg.d/の利用も「MUST NOT(してはならない⁠⁠」と記述しています。

より良い手順は、/usr/local/share/keyrings/に鍵を保存しておき、sources.listからリポジトリごとに参照する鍵を指定する方法です。

$ gpg --no-default-keyring --keyring /tmp/temp-keyring.gpg \
    --import "ダウンロードしたリポジトリ鍵ファイル名"
$ gpg --no-default-keyring --keyring /tmp/temp-keyring.gpg \
    --export --output "リポジトリ名".gpg
$ rm /tmp/temp-keyring.gpg
$ sudo mkdir -p /usr/local/share/keyrings/
$ sudo cp "リポジトリ名".gpg /usr/local/share/keyrings/

ただしこれだけだとAPTからダウンロードしたリポジトリ鍵を参照できません。次にsources.listに鍵を指定するオプションを付けます。おそらくサードパーティのリポジトリを導入する際には、リポジトリの場所を/etc/apt/sources.list.d/リポジトリ名.listみたいなファイルを作ってそこに記述するでしょう。そこでその内容を次のように書き換えます。

変更前:
deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main

変更後:
deb [arch=amd64 signed-by=/usr/local/share/keyrings/"リポジトリ名".gpg] http://dl.google.com/linux/chrome/deb/ stable main

つまりdebの後ろに[signed-by=/usr/local/share/keyrings/"リポジトリ名".gpg]を追加するわけです。上記はすでに[arch=amd64]がある例ですが、ない場合は[]から追加してください。[]の中のオプションは空白で連結可能です。

これによりダウンロードしたリポジトリ鍵は、特定のリポジトリの検証にのみ利用できるようになりました。

おそらく当分の間、サードパーティのリポジトリの導入手順は「apt-keyコマンドを使う方法」が紹介されるでしょう。しかしながら今後は将来apt-keyが廃止されることを考慮して、上記のような手順に変更することも検討してもらえればと思います[8]⁠。

ちなみに前述のサードパーティのリポジトリを利用することについて解説したDebian Wikiのページでは、リポジトリを運用する側がどのような名前の鍵ファイルをどのように配布すべきかについても解説されています。apt-keyの完全な廃止に向けて、リポジトリの運用を見直す際には参考になるでしょう。

おすすめ記事

記事・ニュース一覧