CentOS 6 で yum localinstall が通らないときの切り分け

CentOS 6 で配布元から落としてきた RPM を yum localinstall で入れようとして、 警告: ... ヘッダ V3 RSA/SHA256 Signature, key ID xxxxxxxx: NOKEY が出たまま進まない、という詰まり方があります。

ただ、同じコマンドが通らない原因は1つではありません。 特に CentOS 6 がサポート終了してからは、署名の警告にたどり着く前に別のところで落ちているケースのほうが多い。 順番に切り分けます。

先に結論

「key ID ...: NOKEY」は何を言っているのか

署名検証の仕組み

RPM パッケージには、作った人の秘密鍵で署名が付いています。 インストール時、rpm はその署名を自分のキーリング(rpm のデータベースに登録された公開鍵の一覧)と突き合わせて、 「このパッケージは確かにその配布元が作ったもので、途中で中身が差し替わっていない」ことを確認します。

NOKEY は、署名に使われた鍵がキーリングに入っていないという意味です。 署名が壊れているわけでも、パッケージが不正だと判定されたわけでもない。「照合する相手がいないので検証できなかった」という状態です。

足りない鍵を特定する

いま入っている鍵は、こう確認できます。

# 登録済みの公開鍵を一覧
rpm -qa gpg-pubkey*
gpg-pubkey-c105b9de-4e0fd3a3

# 中身を見る(誰の鍵なのか)
rpm -qi gpg-pubkey-c105b9de-4e0fd3a3

手元の RPM が誰の署名を要求しているかは、インストールする前に単体で確認できます。

# 署名の検証だけ行う
rpm -K xxxxx.rpm
xxxxx.rpm: RSA sha1 ((MD5) PGP) md5 NOT OK (MISSING KEYS: (MD5) PGP#xxxxxxxx)

MISSING KEYS に出ている ID が、足りない鍵です。 この ID を手がかりに、配布元が公開している鍵を探すことになります。

かつて MySQL 公式のリポジトリ RPM(mysql-community-release-el6-*.noarch.rpm)を入れるときに、 この NOKEY によくぶつかりました。配布元が自前の鍵で署名していて、その鍵が CentOS 標準では入っていないからです。 いまは el6 向けの配布自体が終了しているので、同じ RPM を取得することはできません。

正攻法:鍵をインポートする

取り込んで確認する

配布元が公開鍵を出しているなら、それを取り込むのが本来の手順です。

# URL から直接取り込む
rpm --import https://example.com/RPM-GPG-KEY-example

# ファイルで受け取っている場合
rpm --import /tmp/RPM-GPG-KEY-example

# 取り込まれたか確認
rpm -qa gpg-pubkey* | wc -l
rpm -K xxxxx.rpm
xxxxx.rpm: rsa sha1 (md5) pgp md5 OK

OK に変われば、あとは普通にインストールできます。

yum install ./xxxxx.rpm

鍵の入手先に注意

鍵の入手先は 配布元の公式サイトかドキュメントに書かれている URL だけを使ってください。 検索で出てきた個人ブログに貼られた鍵や、どこかのミラーに転がっているものを取り込むと、 署名検証という仕組みの意味がなくなります。鍵を入れるのは「この配布元を信用する」という宣言なので、そこだけは横着しないほうがいい。

CentOS 自身の鍵は OS に同梱されていて、/etc/pki/rpm-gpg/ に置かれています。 CentOS-Base.repo の gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6 がそれです。

--nogpgcheck が捨てているもの

何が起きるか

--nogpgcheck を付ければ警告は出なくなり、インストールは通ります。

最後の手段

yum install --nogpgcheck ./xxxxx.rpm

ただしこれは「警告を黙らせる」のではなく、そのトランザクションの署名検証を丸ごと無効にするオプションです。 中身が配布元のものである保証を自分で外すことになります。

使ってよい場面

使ってよい場面と、やめたほうがいい場面を分けると、こうなります。

状況判断
自分でビルドした、署名していない RPM を入れる妥当。そもそも署名がないので検証するものがない
社内でビルドして社内で配っている RPM妥当。ただし署名を付ける運用にしたほうが後が楽
配布元が鍵を公開しているのに探すのが面倒やめる。rpm --import で済む
インターネットから落としてきた素性の不明な RPMやめる。検証を外してよい理由がない

リポジトリ単位で常時オフにする gpgcheck=0 も同じです。 ローカルリポジトリを自分で立てて自分のパッケージだけ置くなら実務的な選択ですが、 外部のリポジトリに対して付けるものではありません。

いまの CentOS 6 では、警告より先に止まる2か所

ここからが、2015年ごろの手順書がそのまま使えなくなっている部分です。 CentOS 6 は 2020年11月30日にサポートが終了しました。 それに伴って、デフォルトで設定されているリポジトリが実体を失っています。

1. リポジトリが消えている

yum を叩いた時点で、こう落ちます。

Loaded plugins: fastestmirror
Determining fastest mirrors
YumRepo Error: All mirror URLs are not using ftp, http[s] or file.
 Eg. Invalid release/repo/arch combination/
removing mirrorlist with no valid mirrors: /var/cache/yum/x86_64/6/base/mirrorlist.txt
Error: Cannot find a valid baseurl for repo: base

mirrorlist.centos.org が CentOS 6 に対して有効なミラーを返さなくなったためです。 パッケージ自体は vault.centos.org に退避しているので、CentOS-Base.repo の参照先を差し替えます。

# 先にバックアップ
cp -p /etc/yum.repos.d/CentOS-Base.repo /tmp/CentOS-Base.repo.$(date +%Y%m%d)

各セクションを、mirrorlist をやめて baseurl を直接指定する形に書き換えます。

[base]
name=CentOS-6.10 - Base
baseurl=http://vault.centos.org/6.10/os/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6

base だけでなく updates extras も同じ要領で直します。 バージョンは自分の環境に合わせてください(cat /etc/redhat-release で確認できます)。 6.10 以外のマイナーバージョンのままなら、そのディレクトリを指定します。

書き換えたら、キャッシュを必ず捨てます。

yum clean all
yum repolist

$releasever を使ったまま運用したい場合は /etc/yum/vars/releasever にマイナーバージョンを固定で書く手もあります。 ただ、この先もう更新されない環境なので、repo ファイルにベタ書きしてしまったほうが事故が少ないです。

2. vault に https で繋がらない

リポジトリを直したのに、今度はこうなることがあります。

http://vault.centos.org/6.10/os/x86_64/repodata/repomd.xml: [Errno 14] problem making ssl connection
Trying other mirror.
Error: Cannot retrieve repository metadata (repomd.xml) for repository: base.

CentOS 6 に入っている nss や ca-certificates が古く、いまのサーバの TLS 設定・証明書チェーンについていけていない状態です。 リダイレクトの先が https だと、ここで止まります。

この環境では curl も wget も同じ理由で使えないことが多いので、 別のマシンで必要な RPM を落としてきて転送し、rpm -Uvh で直接入れるのが早いです。 対象は TLS 周りの一式になります。

# 別の(新しい)マシンで取得して、対象サーバへ転送してから
rpm -Uvh nspr-*.rpm nss-util-*.rpm nss-softokn-freebl-*.rpm \
         nss-softokn-*.rpm nss-sysinit-*.rpm nss-*.rpm \
         p11-kit-*.rpm p11-kit-trust-*.rpm ca-certificates-*.rpm

これらは依存関係が絡み合っているので、1つずつ入れようとすると詰まります。まとめて渡してください。 ここを通してはじめて yum が動くようになり、localinstall の依存解決もできるようになります。

つまり、依存パッケージを引いてくる経路が死んでいる状態では、署名の警告を直しても localinstall は完走しません。 順番としては リポジトリ → TLS → 署名 です。

localinstall と install の違い

結論から言うと、いま書くなら install で構いません。yum のマニュアルにはこう書かれています。

install コマンドはファイル名を渡せばローカルインストールを行う。localinstall は過去互換のためだけに維持されている。

どちらもローカルの RPM ファイルを指定して入れられて、不足している依存パッケージは設定済みのリポジトリから取ってきます。 rpm -ivh との差はここで、rpm 単体は依存を解決せず「足りない」と言って止まるだけです。

コマンドローカルの RPM依存解決備考
rpm -ivh foo.rpm入れられるしない足りなければエラーで停止
yum localinstall foo.rpm入れられるする互換のために残っている
yum install ./foo.rpm入れられるするいまはこちら

なお、yum install ./foo.rpm のようにパスを明示しないと、 foo.rpm という名前のパッケージをリポジトリから探しに行って「見つからない」と言われることがあります。 カレントディレクトリのファイルを指すときは ./ を付けてください。

CentOS 7 以降の dnf でも dnf localinstall は残っていますが、これも dnf install のエイリアスです。

切り分けの順番

出ているもの原因対処
Cannot find a valid baseurl for repo: base EOL でリポジトリが空 CentOS-Base.repo を vault に向ける → yum clean all
problem making ssl connection nss / ca-certificates が古い 別マシンで RPM を取得して rpm -Uvh でまとめて更新
key ID ...: NOKEY 署名した鍵が未登録 配布元の公式鍵を rpm --import
Requires: ... で停止 依存パッケージが引けていない 上の2つが解決済みか確認(yum repolist)
パッケージ名が見つからない ファイルではなくパッケージ名として解釈されている ./ を付けてパスで渡す

この環境をいつまで使うか

ここまでの作業は、いずれも「動かすための一時しのぎ」です。 vault は過去のパッケージを置いてあるだけのアーカイブなので、新しい修正は出てきません。 セキュリティ更新が止まって5年以上経っているので、外向きのサーバで動かし続ける前提の話ではないです。

現実にはデータの吸い出しや、移行先での動作確認のために一時的に立ち上げる、という使い方が多いと思います。 その目的なら、ここまでの手順で十分動きます。 逆に言うと、この作業に何日もかけるくらいなら移行を進めたほうが早いということでもあります。

IIJ など国内のミラーが centos-vault を提供している場合は、そちらを baseurl に指定したほうが速いことがあります。 ただしミラーの提供状況は変わるので、作業時点で生きているかを確認してから使ってください。

アーカイブ一覧に戻る