サードパーティのAPTパッケージリポジトリを追加する際に使用する「apt-key」コマンドは、2020年8月の2.1.8から「廃止予定(deprecated)」となり、2022年の半ばには削除される予定になりました。今回はその理由と、代替手段について解説しましょう。
リポジトリの正当性を担保する仕組み
Linuxにおけるパッケージ管理システムは、システムの重要なデータを置き換えるクリティカルな操作です。よってインターネットの先からパッケージをダウンロードする際は、その正当性を確認しなければなりません。「パッケージの正当性」と言ったとき、一般的には複数の意味が含まれます。
- パッケージに悪意のあるコードが含まれていないこと
- パッケージメンテナ以外の第三者が作ったパッケージがリポジトリにアップロードされていないこと
- 本来のリポジトリとは別の場所からパッケージをダウンロードしていないこと
まず一番気になる1についてですが、ここに関してはAPTによる保護の対象外です。利用者はそのパッケージのメンテナーを信頼することしかできません。言い換えると、PPAを含むサードパーティのリポジトリを登録する際は、便利かどうかだけでなく信頼できるかどうかも検討しましょう。
2も厳密にはAPTの対象外です。Ubuntuの公式リポジトリの場合は、ソースパッケージのアップロードにはメンテナーの署名が必要ですし、その署名を検証した上でビルドサーバーがパッケージをビルドし、適切な場所に配置します。しかしながら利用者の観点からすると、この部分についてもリポジトリの管理者を信頼する以外に手はありません。
APTで正当性を確認するのは、実質3のみです。正しい管理者が、悪意のあるコードを含まないパッケージをリポジトリにアップロードし正しく運用しているという前提のもと、ダウンロードしようとしているのが、その管理者によってアップロードされたパッケージであることを保証します。
この「正当性を保証」するために、APTの場合はGPGを利用した公開鍵方式で検証しています。バージョンや設定、リポジトリによって若干の差異はありますが、リポジトリからパッケージをダウンロードする際の検証方法は次のとおりです。
- sources.listに記録されているURLからInReleaseファイルをダウンロードする
- InReleaseファイルを、ローカルにあらかじめ保存しておいたリポジトリ鍵で検証する
- main/binary-amd64/PackagesなどのPackagesファイルをダウンロードする
- Packagesファイルのハッシュを、InReleaseの中の情報で検証する
- Packagesのパスに応じてpool/main/以下などから、対象のパッケージファイルをダウンロードする
- ダウンロードしたパッケージファイルのハッシュを、Packagesファイルの中の情報で検証する
InReleaseに対する署名は、リポジトリ鍵と対になる秘密鍵を持った人だけが可能です。つまりこれはリポジトリそのものの管理者であり、Ubuntuの公式リポジトリは「ftpmaster」と呼ばれます。このInReleaseの署名から続く検証の流れによって、ダウンロードしたパッケージファイルがリポジトリの管理者によるサイトからダウンロードしたことを確認できるわけです[1]。
たとえばUbuntu 20.04 LTSのある日のInReleaseファイル[2]は次のような内容になっています。
Packagesも含むメタデータ情報のURLが示すコンテンツごとの、MD5SUM/SHA1/SHA256のハッシュ値を掲載しています。
それに対してリポジトリからダウンロードできる、Packagesファイル[3]は上記のように、さまざまなハッシュ値を持った次のようなファイルになっています。
そして「accountsservice_0.6.55-0ubuntu13.2_amd64.deb
」は、上記で列挙されているハッシュ値で検証することで、正当性を確認できるわけです。これによりUbuntuのリポジトリは、HTTPSなどを使わなくても中間者攻撃の心配をする必要なくパッケージをダウンロードできます[4]。
ここでポイントになってくるのが、InReleaseの署名を検証するための「リポジトリ鍵」です。リポジトリの管理者が秘密鍵を使ってInReleaseを署名するとして、利用者はその公開鍵を何らかの方法で取得・管理しなくてはなりません。Ubuntuの公式リポジトリについては、「インストーラーに組み込む」ことで自動的に登録されます。これはubuntu-keyringパッケージとして提供されています。
たとえばInReleaseファイルをダウンロードして検証してみましょう。
鍵「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コマンドを使うと、次のような警告が表示されます。
これはセキュリティ上の懸念点からくるもので、簡単にまとめると次の2点が理由です。
apt-key add
は単一ファイル(/etc/apt/trusted.gpg
)に鍵を追加していくため、複数のリスクの異なるリポジトリの鍵を同じ権限で管理しなくてはならない。
- リポジトリ鍵として追加した鍵は、すべてのリポジトリに対して適用される。
実はどちらも昔から言われていたことで、「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でサポートしているフォーマットでない可能性があります。
よって次のような手順で、一旦適当な鍵束に取り込んでから、バイナリ形式でエクスポートするのが安全なようです。
しかしながら、この方法ではサードパーティのリポジトリに対するリスク管理という観点からは、完全な対応とは言えません。実際、Debian Wikiにある情報ではあるもののサードパーティのリポジトリの利用のページにおいて、apt-keyコマンドだけでなく/etc/apt/trusted.gpg.d/
の利用も「MUST NOT(してはならない)」と記述しています。
より良い手順は、/usr/local/share/keyrings/
に鍵を保存しておき、sources.list
からリポジトリごとに参照する鍵を指定する方法です。
ただしこれだけだとAPTからダウンロードしたリポジトリ鍵を参照できません。次にsources.list
に鍵を指定するオプションを付けます。おそらくサードパーティのリポジトリを導入する際には、リポジトリの場所を「/etc/apt/sources.list.d/リポジトリ名.list
」みたいなファイルを作ってそこに記述するでしょう。そこでその内容を次のように書き換えます。
つまりdebの後ろに「[signed-by=/usr/local/share/keyrings/"リポジトリ名".gpg]
」を追加するわけです。上記はすでに「[arch=amd64]
」がある例ですが、ない場合は「[]
」から追加してください。「[]
」の中のオプションは空白で連結可能です。
これによりダウンロードしたリポジトリ鍵は、特定のリポジトリの検証にのみ利用できるようになりました。
おそらく当分の間、サードパーティのリポジトリの導入手順は「apt-keyコマンドを使う方法」が紹介されるでしょう。しかしながら今後は将来apt-keyが廃止されることを考慮して、上記のような手順に変更することも検討してもらえればと思います[8]。
ちなみに前述のサードパーティのリポジトリを利用することについて解説したDebian Wikiのページでは、リポジトリを運用する側がどのような名前の鍵ファイルをどのように配布すべきかについても解説されています。apt-keyの完全な廃止に向けて、リポジトリの運用を見直す際には参考になるでしょう。