You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决Docker环境中S3.Client.upload_fileobj触发的SSL证书验证错误?

解决Docker中boto3连接S3的SSL证书验证失败问题

问题场景

在指定--platform=linux/amd64的Docker镜像中运行Python代码,通过boto3上传JSON文件到S3时,触发ssl.SSLCertVerificationError错误,提示无法获取本地颁发者证书。相同代码在本地开发环境可正常运行,已尝试安装certifi、openssl,设置SSL_CERT_FILE和REQUESTS_CA_BUNDLE环境变量,更换多个Python基础镜像,但问题仍未解决。

错误日志

ssl_sock = ssl_wrap_socket(
File "/root/.cache/pypoetry/virtualenvs/gg-9TtSrW0h-py3.10/lib/python3.10/site-packages/urllib3/util/ssl_.py", line 469, in ssl_wrap_socket
ssl_sock = _ssl_wrap_socket_impl(sock, context, tls_in_tls, server_hostname)
File "/root/.cache/pypoetry/virtualenvs/gg-9TtSrW0h-py3.10/lib/python3.10/site-packages/urllib3/util/ssl_.py", line 513, in _ssl_wrap_socket_impl
return ssl_context.wrap_socket(sock, server_hostname=server_hostname)
File "/usr/local/lib/python3.10/ssl.py", line 513, in wrap_socket
return self.sslsocket_class._create(
File "/usr/local/lib/python3.10/ssl.py", line 1104, in _create
self.do_handshake()
File "/usr/local/lib/python3.10/ssl.py", line 1375, in do_handshake
self._sslobj.do_handshake()
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1007)

相关代码

S3连接类:

class S3Connection(Connection):
    def __enter__(self):
        self._open()
        return self

    def __exit__(
        self,
        exception_type: str,
        exception_value: str,
        exception_traceback: str,
    ):
        self._close()

    def _open(self):
        self.sts_client = get_sts_client()
        self.credentials_response = self.sts_client.assume_role(
            RoleArn=HIPPOGRIFF_ROLE,
            RoleSessionName=self.session_name,
        )
        self.session = get_session(
            self.credentials_response['Credentials']['AccessKeyId'],
            self.credentials_response['Credentials']['SecretAccessKey'],
            self.credentials_response['Credentials']['SessionToken'],
        )
        self.s3_client = get_s3_client(session=self.session)

    def _close(self):
        self.sts_client.close()
        self.s3_client.close()

S3上传函数:

def land_to_aws_s3(response, table_name, file_name):
    logger.info(
        f'{LOG_ENV_PREFIX}: \
         Landing json file into s3 bucket  ' +
        'table_name: \n:' + table_name,
    )
    json_bytes = BytesIO(json.dumps(response.json()['data']).encode('utf-8'))
    with S3Connection() as s3_connection:
        s3_response = s3_connection.s3_client.upload_fileobj(
            json_bytes,
            Bucket=LANDING_BUCKET,
            Key=LANDING_BUCKET_PATH + '/'+table_name+'/'+file_name,
            ExtraArgs={'ContentType': 'application/json'},
        )
    return s3_response

问题原因

  1. Docker镜像CA证书链不完整:多数轻量Python基础镜像(如python:alpine)默认未预装完整的系统级根CA证书,即使安装了certifi,系统证书与Python使用的证书链可能不同步,缺失中间颁发者证书。
  2. 环境变量未正确生效:虽然设置了SSL_CERT_FILE和REQUESTS_CA_BUNDLE,但boto3依赖的urllib3可能未正确读取这些变量,或环境变量设置时机错误(如虚拟环境启动后才设置,导致Python进程未加载)。
  3. 虚拟环境证书隔离:Poetry创建的虚拟环境可能未继承系统证书配置,certifi的证书路径在虚拟环境中未正确关联。
  4. 内部代理/私有CA问题:若环境使用内部代理或私有CA,未将对应的CA证书添加到系统证书库中,导致无法验证S3服务器证书。

修复建议

1. 安装系统级根CA证书

根据镜像的操作系统类型,在Dockerfile中添加证书安装命令:

  • Debian/Ubuntu系镜像:
RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates && update-ca-certificates
  • Alpine系镜像:
RUN apk add --no-cache ca-certificates && update-ca-certificates

2. 确保环境变量正确设置

在Dockerfile中提前设置环境变量,确保Python进程启动时能读取到:

ENV SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
ENV REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt

也可在启动容器时通过-e参数传递,避免镜像构建时的路径冲突。

3. 显式配置boto3客户端的SSL上下文

在代码中强制指定CA证书路径,不依赖环境变量:

import ssl
import boto3
from botocore.client import Config

def get_sts_client():
    # 创建自定义SSL上下文,指定系统证书文件路径
    ssl_context = ssl.create_default_context(cafile='/etc/ssl/certs/ca-certificates.crt')
    config = Config(ssl_context=ssl_context)
    return boto3.client('sts', config=config)

def get_s3_client(session=None):
    ssl_context = ssl.create_default_context(cafile='/etc/ssl/certs/ca-certificates.crt')
    config = Config(ssl_context=ssl_context)
    if session:
        return session.client('s3', config=config)
    return boto3.client('s3', config=config)

若使用certifi的证书文件,可替换为cafile=certifi.where()。

4. 添加内部CA证书(如有)

如果环境使用私有CA,需将CA证书添加到系统证书库:

# 复制内部CA证书到指定目录
COPY internal-ca.crt /usr/local/share/ca-certificates/
# 更新证书链
RUN update-ca-certificates

5. 验证证书路径正确性

在Docker镜像中执行以下命令,确认证书文件存在且可读:

ls -l /etc/ssl/certs/ca-certificates.crt
python -c "import ssl; print(ssl.get_default_verify_paths())"
python -c "import certifi; print(certifi.where())"

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 15:47:31