现象
请求 HTTPS 时报 ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed;原因常为 unable to get local issuer certificate;pip install 失败而 curl 正常;同一代码在另一台机器或容器里失败。
诊断
先看服务端实际下发的证书链,再确认 Python 使用的信任库:
openssl s_client -connect api.example.com:443 -servername api.example.com -showcerts </dev/null 2>/dev/null \
| openssl x509 -noout -issuer -subject -dates
python -c "import ssl; print(ssl.get_default_verify_paths())"
env | grep -iE 'SSL_CERT_FILE|REQUESTS_CA_BUNDLE|CURL_CA_BUNDLE'
date -u
issuer 是公司 CA 说明存在 TLS 拦截,需要把该根证书加入信任库;issuer 是公共 CA 但链很短,说明服务器没发中间证书。get_default_verify_paths() 显示 Python 实际使用的 cafile 与 capath,路径不存在或指向容器内旧文件都会失败。REQUESTS_CA_BUNDLE、SSL_CERT_FILE 会覆盖默认 bundle,是常见的隐形故障源;系统时间明显偏差则会让有效证书被判定为未生效或已过期。
根因
TLS 握手时无法用 Python 可见的信任锚验证证书链:签发 CA 不在 bundle 中、bundle 路径错误或被环境变量覆盖、证书链不完整或过期,或者本机时钟偏差导致有效期判断错误。
修复
把企业根证书安装到系统信任库,并让 Python 使用包含它的完整 PEM bundle:
sudo cp corporate-root.crt /usr/local/share/ca-certificates/corporate-root.crt
sudo update-ca-certificates
export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
# macOS python.org 安装包
open "/Applications/Python 3.12/Install Certificates.command"
同时升级 certifi,清理失效的 SSL_CERT_FILE 与 REQUESTS_CA_BUNDLE,修正服务端过期或缺失的中间证书。容器镜像构建时就应带入根证书,不要设置 verify=False 或全局关闭校验。
验证
在开启校验的情况下重跑原请求应返回 200,并在部署镜像内再验证一次;openssl verify -CAfile /etc/ssl/certs/ca-certificates.crt server.pem 返回 OK;pip 从配置的索引安装不再报证书错误。