エラーメッセージ
There was a problem confirming the ssl certificate: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed
別の表記
- Could not fetch URL https://pypi.example.com/simple/requests/: There was a problem confirming the ssl certificate: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate
pip は、「WARNING: Retrying (Retry(total=…)) after connection broken by 'SSLError(…)'」という行を何度か出力した後、「Could not fetch URL <url>: There was a problem confirming the ssl certificate: … - skipping」と出力します。URL と最後の理由は状況によって異なります。
pip — index or find-links URL over HTTPS (pip 24.2+ verifies with truststore by default)
このエラーの意味
pip はパッケージインデックス(または find-links の URL)の TLS 証明書を検証できなかったため、そのページをスキップしました。通常は最終的に「Could not find a version that satisfies the requirement」で終わります。コロンの後の理由は、OpenSSL による検証の結果です。pip 24.2 以降、pip は truststore を通じて OS のトラストストアで検証します。そのため、OS のストアに CA がないか、pip が別のバンドルを使うように指定されているかのどちらかです。
発生する理由
社内の証明書を使うプライベートインデックス(Artifactory、Nexus、devpi)
よくある社内のパッケージミラーは、社内 CA の証明書を使っています。その CA は管理対象のノートパソコンには入っていますが、CI のイメージ、コンテナー、新しく作成した仮想マシンには入っていません。
pypi.org の手前にある TLS を検査するプロキシ
よくある社内ネットワークでは、pypi.org と files.pythonhosted.org の証明書がプロキシによって署名し直されます。pip が使うトラストストアにそのプロキシのルートがなければ、すべてのインストールが失敗します。
pip が OS のストアではなく certifi を使うように設定されている
ときどき--use-deprecated=legacy-certs を指定している、cert の設定で certifi を明示的に指定している、または pip が Python 3.9 以前(truststore が使えない環境)で動作している場合は、OS のストアに追加したルートは使われません。
Python のインストールに同梱された古い pip
ときどき24.2 より前の pip は、常に同梱の certifi のバンドルを使っていました。多くのベースイメージや仮想環境には、今でもそうしたバージョンが含まれています。
修正方法
- 1.
CA を OS のトラストストアにインストールする
Python 3.10 以降で pip 24.2 以降を使えば、システムのストア(またはキーチェーンや Windows のストア)にあるルートが自動的に信頼されます。pip がそれより古い場合はアップグレードしてください。
bash # pip >= 24.2 uses the OS trust store (truststore): add the CA there sudo cp corp-root-ca.pem /usr/local/share/ca-certificates/corp-root-ca.crt sudo update-ca-certificates python3 -m pip --version # upgrade pip itself if it is older than 24.2 - 2.
pip に CA バンドルを明示的に指定する
pip の設定の global.cert、PIP_CERT、--cert のいずれかを使うと、pip はそのファイルで検証します。pip が pypi.org にも接続する場合は、公的に信頼されたルートも含めてください。
bash # A CA bundle for pip only (one of these): python3 -m pip config set global.cert /etc/ssl/private-ca/corp-ca-bundle.pem export PIP_CERT=/etc/ssl/private-ca/corp-ca-bundle.pem python3 -m pip install --cert /etc/ssl/private-ca/corp-ca-bundle.pem requests - 3.
プライベートインデックスを一度だけ設定する
index-url と cert を pip.conf(または pip.ini)に記述してください。そうすれば、ビルドツール内での実行も含め、すべての pip の実行でこれらが使われます。
ini # pip.conf (Linux: ~/.config/pip/pip.conf, Windows: %APPDATA%\pip\pip.ini) [global] index-url = https://pypi.example.com/simple/ cert = /etc/ssl/private-ca/corp-ca-bundle.pem - 4.
一時的な診断:--trusted-host
--trusted-host は、そのホストに対する証明書の検証を無効にし、そのホストでは平文の HTTP の使用も許可します。診断の裏付けにはなりますが、この方法でダウンロードしたものは転送中にすり替えられている可能性があります。設定に残してはいけません。
bash # Temporary diagnostic only: --trusted-host disables certificate checks for that host python3 -m pip download --no-deps -d /tmp/dl --index-url https://pypi.example.com/simple/ \ --trusted-host pypi.example.com requests