You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

企业网Docker环境下配置requests双CA证书解决pip失效问题

我来帮你解决这个问题——你遇到的核心问题是REQUESTS_CA_BUNDLE并不支持用冒号分隔多个证书路径,它只能指向单个文件。当你只指定自签名证书时,pip访问外网PyPI会因为缺少默认信任的CA证书而失败。下面给你几个靠谱的解决方案:

方案1:使用系统合并后的CA证书 bundle(最推荐,无需修改代码)

你已经执行了update-ca-certificates命令,这个工具会自动把/usr/local/share/ca-certificates/下的自定义证书,合并到系统默认的CA bundle文件/etc/ssl/certs/ca-certificates.crt里。这个文件同时包含了系统预装的主流CA证书(覆盖了certifi的绝大多数需求)和你的自签名证书,完美兼顾内网和外网访问。

只需要修改Dockerfile里的环境变量设置即可:

COPY EDAG_Bundle.crt /usr/local/share/ca-certificates/my_cert.crt
RUN update-ca-certificates
# 改为指向系统合并后的CA bundle
ENV REQUESTS_CA_BUNDLE /etc/ssl/certs/ca-certificates.crt

这样不管是requests访问内网服务,还是pip拉取外网包,都能正常验证证书了。

方案2:合并自签名证书到certifi的cacert.pem

如果你更倾向于沿用certifi的证书集合,可以把自签名证书追加到certifi自带的cacert.pem文件中。在Dockerfile里可以这样实现:

COPY EDAG_Bundle.crt /tmp/my_cert.crt
# 获取certifi的证书路径,合并自签名证书后覆盖原文件
RUN python -c "import certifi; import shutil; shutil.copy(certifi.where(), '/tmp/cacert_combined.pem')" \
    && cat /tmp/my_cert.crt >> /tmp/cacert_combined.pem \
    && mv /tmp/cacert_combined.pem $(python -c "import certifi; print(certifi.where())")
# 设置环境变量指向合并后的certifi证书文件
ENV REQUESTS_CA_BUNDLE $(python -c "import certifi; print(certifi.where())")

这个方法能确保证书bundle包含certifi的所有默认证书加上你的自签名证书,但要注意:如果后续升级certifi包,这个合并后的文件可能会被覆盖,所以建议在安装完所有Python依赖后再执行合并步骤。

方案3:代码层面自定义证书验证(适合灵活控制的场景)

如果不想修改环境变量,也可以在代码里通过自定义requests Session来指定合并后的证书文件:

import requests
import certifi
import tempfile
import os

# 创建临时文件合并两个证书
with tempfile.NamedTemporaryFile(mode='wb', delete=False) as tmp_cert:
    # 先写入certifi的所有默认证书
    with open(certifi.where(), 'rb') as certifi_cert:
        tmp_cert.write(certifi_cert.read())
    # 再追加自签名证书
    with open('/usr/local/share/ca-certificates/my_cert.crt', 'rb') as my_cert:
        tmp_cert.write(my_cert.read())

# 用合并后的证书创建Session
session = requests.Session()
session.verify = tmp_cert.name

# 之后用这个session发起所有请求,兼顾内网和外网
internal_response = session.get('https://your-internal-service.com')
pypi_response = session.get('https://pypi.org')

# 用完临时文件后可以删除(可选)
os.unlink(tmp_cert.name)

这个方案不需要改动系统配置或环境变量,适合部分请求需要特殊证书验证的场景,但需要调整你的代码逻辑。

内容的提问来源于stack exchange,提问作者Igl3

火山引擎 最新活动