エラーメッセージ
npm error code UNABLE_TO_VERIFY_LEAF_SIGNATURE
別の表記
- npm ERR! code UNABLE_TO_VERIFY_LEAF_SIGNATURE
- npm error request to https://registry.example.com/lodash failed, reason: unable to verify the first certificate
npm 10 以降は「npm error code UNABLE_TO_VERIFY_LEAF_SIGNATURE」、npm 9 以前は「npm ERR! code UNABLE_TO_VERIFY_LEAF_SIGNATURE」と出力します。最近の Node.js のバージョンでは、理由の行に「; if the root CA is installed locally, try running Node.js with --use-system-ca」が追加されます。
npm (Node.js) — registry request over HTTPS
このエラーの意味
レジストリ(またはその前段にあるプロキシ)が自身の証明書だけを送信し、Node.js はそれを発行した証明書を見つけられませんでした。発行者がなければ、リーフ証明書の署名はまったく検証できません。これはサーバーの設定の問題です。ハンドシェイクに中間証明書が含まれておらず、Node.js はそれをダウンロードして補うことはしません。
発生する理由
リーフ証明書だけが設定されたプライベートレジストリ
よくあるNexus、Artifactory、Verdaccio、またはその前段のリバースプロキシに、完全なチェーンではなく cert.pem がインストールされています。
リーフ証明書だけを提示するプロキシ
ときどきTLS を検査するプロキシの中には、中間証明書が発行した証明書を、その中間証明書を含めずに送信するものがあります。
未知のプライベート CA が発行したリーフ証明書
ときどきリーフ証明書より上位の証明書を Node.js が 1 つも知らない場合も、同じコードが表示されます。その CA(とその中間証明書)を信頼すれば解決します。
修正方法
- 1.
ハンドシェイク内の証明書の数を確認する
depth 0 しか表示されず、その発行者が中間証明書であれば、中間証明書の欠落が確定します。
bash openssl s_client -connect registry.example.com:443 -servername registry.example.com -showcerts </dev/null 2>/dev/null \ | grep -E '^ *[0-9]+ s:|^ *i:' - 2.
レジストリで完全なチェーンを返す
レジストリの前段で TLS を終端するサーバーに、リーフ証明書と中間証明書を設定してください。これで npm、yarn、pnpm、Docker をはじめ、すべてのクライアントが一度に直ります。
text # Registry behind nginx: serve leaf + intermediate(s) ssl_certificate /etc/nginx/tls/registry.example.com.fullchain.pem; ssl_certificate_key /etc/nginx/tls/registry.example.com.key; - 3.
回避策:クライアント側で中間証明書を信頼する
中間証明書とそのルートを含む cafile を使えば、サーバーが修正されるまでの間、npm はリーフ証明書を検証できます。cafile は npm のデフォルトのルートを置き換えるため、同じ npm で registry.npmjs.org も使う場合は、パブリックルートも追加してください。
bash # Until the registry is fixed: trust the intermediate (plus its root) on the client cat issuing-ca.pem corp-root-ca.pem > /etc/ssl/private-ca/registry-ca.pem npm config set cafile /etc/ssl/private-ca/registry-ca.pem