命令行工具

SSL validation failed for https://:AWS CLI 证书校验失败修法

作者: · 最后核实

报错信息SSL validation failed for https://

SSL validation failed for https://... 的意思是:AWS CLI(通过 botocore)无法验证它所访问的 AWS 终端节点的 TLS 证书。 URL 后面那段,通常是 [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate,才是具体原因。在办公网络里,绝大多数情况是有代理在解密 HTTPS,而 CLI 不认识它的根证书;用 ca_bundle 把这张根证书交给 CLI,而不是用 --no-verify-ssl。

这条报错是什么意思

这条报错是 botocore 的 SSLError,格式为 SSL validation failed for {endpoint_url} {error}。CLI 会打印它尝试访问的终端节点,以及底层 Python ssl 模块的错误:

SSL validation failed for https://ec2.us-east-1.amazonaws.com/ [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1006)

AWS 自己的排错文档列出了这几种形态和原因:

  • [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed:CLI 不信任代理的证书,典型情况是代理证书由公司自己的 CA 签发。
  • [Errno 2] No such file or directory:配置的 CA 证书包路径不对。
  • [SSL: UNSAFE_LEGACY_RENEGOTIATION_DISABLED] unsafe legacy renegotiation disabled:TLS 实现不兼容,见 UNSAFE_LEGACY_RENEGOTIATION_DISABLED。

TLS 校验发生在任何签名之前,所以和凭证无关。

还有一点容易被忽略:AWS CLI 不会读取浏览器的证书设置,往系统里装根证书也不一定对它生效。最可靠的做法是显式告诉它用哪个证书包,它认的是 ca_bundle、AWS_CA_BUNDLE 和 --ca-bundle 这三个地方(以及默认证书包)。所以“浏览器能打开 AWS 控制台、CLI 却报错”是完全正常的现象,说明问题出在 CLI 用的证书包上,而不是 AWS 服务本身。排查时先确认这三个设置当前的值,再看证书签发者,通常几分钟就能定位。

常见原因(按出现频率排序)

多数情况下是代理或安全软件重新签名了 HTTPS,其次是 ca_bundle 或 AWS_CA_BUNDLE 指向的文件不对。

1. 代理或安全软件重新签名了 HTTPS

安全网关、上网行为管理、杀毒软件的 HTTPS 扫描,会把 AWS 的证书换成由它们自己的根证书签发的证书。浏览器通过系统证书库信任它,CLI 不信任。

  • 确认:
openssl s_client -connect sts.amazonaws.com:443 -servername sts.amazonaws.com </dev/null 2>/dev/null | openssl x509 -noout -issuer

签发者是公司名称或安全厂商而不是 Amazon,就可以确认。见企业 SSL 解密导致的报错。

  • 修复: 把代理根证书导出为 PEM,设置 ca_bundle(见下文)。

2. ca_bundle 或 AWS_CA_BUNDLE 指向的文件不存在或不对

路径写错、用了相对路径、文件里只有公司根证书而你还需要公开根证书、或者文件是 DER 格式而不是 PEM。

  • 确认: aws configure get ca_bundle、echo $AWS_CA_BUNDLE,再用 openssl x509 -in "$AWS_CA_BUNDLE" -noout -subject 确认文件是可读的 PEM。
  • 修复: 用绝对路径指向一个 PEM 证书包。代理解密所有流量时,只放它的根证书就够;只有部分流量被解密时,要做一个“公开根证书 + 公司根证书”的合并证书包。

3. 主机名不匹配:带点的 S3 桶名或自定义终端节点

S3 虚拟主机式请求会把桶名放进主机名。AWS 文档写明,桶名带点时,除非自己做证书校验,否则不能通过 HTTPS 使用虚拟主机式寻址。自定义 --endpoint-url 用了 IP 或别名,同样会出现 Hostname mismatch。

  • 修复: aws configure set default.s3.addressing_style path,或者使用终端节点的真实主机名。

4. 私有的 S3 兼容存储或测试终端节点

MinIO、Ceph、LocalStack 或内部网关,用的是自签名或私有 CA 证书。把 ca_bundle 指向那个 CA 即可。注意 ca_bundle 是替换而不是追加:如果同一个配置还要访问 AWS 自己的服务,证书包里必须同时包含公开根证书,否则访问 AWS 反而会失败。可以为私有存储单独建一个 profile,只在那个 profile 里设置 ca_bundle。

5. 链路上的 TLS 过旧或不常规

老旧代理在 OpenSSL 3 下可能触发重协商或协议错误,按报错里的原因代码查看对应页面。

分平台修复命令

各平台的修法都是把根证书所在的 PEM 文件交给 CLI:ca_bundle 写进配置文件,AWS_CA_BUNDLE 作用于当前环境,--ca-bundle 只作用于单条命令。

Linux 和 macOS:

aws configure set ca_bundle /etc/ssl/certs/company-bundle.pem      # 写入 ~/.aws/config
export AWS_CA_BUNDLE=/etc/ssl/certs/company-bundle.pem             # 当前终端 / CI 任务
aws s3 ls --ca-bundle /etc/ssl/certs/company-bundle.pem            # 单条命令,优先级最高

Windows(PowerShell): 在 certmgr.msc 里把根证书导出为“Base64 编码 X.509(.CER)”,另存为 company-root.pem,然后:

aws configure set ca_bundle C:\certs\company-root.pem
$env:AWS_CA_BUNDLE = "C:\certs\company-root.pem"

Python 里的 boto3:

import boto3
s3 = boto3.client("s3", verify="/etc/ssl/certs/company-bundle.pem")

桶名带点:

aws configure set default.s3.addressing_style path

国内使用要点: 使用 AWS 中国区(北京 cn-north-1、宁夏 cn-northwest-1)时,先确认 region 设置正确,终端节点域名是 amazonaws.com.cn,区域和终端节点混用会导致各种连接和证书问题。用 AWS CLI 操作其他云厂商的 S3 兼容对象存储时,--endpoint-url 要写对方文档给出的域名,不要自己拼接 IP 或别名。

不推荐:关闭证书校验

加 --no-verify-ssl(或 boto3 的 verify=False)能让报错消失,代价是流量失去防中间人攻击的保护。AWS 文档写明:这个选项不是最佳实践,客户端和 AWS 服务之间的流量不再安全,容易受到中间人攻击,证书问题应该去解决。在可能被篡改的网络路径上,这会暴露临时凭证、会话令牌和 S3 里的数据。

更安全的替代办法就是文档给出的那些:用正确的 PEM 文件配置 ca_bundle、AWS_CA_BUNDLE 或 --ca-bundle;带点的桶名改用路径式寻址;使用终端节点的真实主机名;升级使用过时 TLS 的代理。

怎么确认已经修好

aws sts get-caller-identity 正常返回账户信息、调试输出里没有证书错误,问题就解决了:

aws sts get-caller-identity
aws s3 ls --debug 2>&1 | grep -iE "ssl|certificate" | head

在 CI 里使用时,建议把公司根证书放进构建镜像,并在流水线的环境变量里统一设置 AWS_CA_BUNDLE,不要让每个任务各自处理。

get-caller-identity 应当返回你的账号和 ARN,这同时证明 TLS 和凭证都正常;debug 输出里不应再有 SSL 错误。如果终端节点归你管理,用 SSL 检测工具检查它的证书链;想了解为什么少一张根证书浏览器没事、CLI 却失败,见证书链原理。

常见问题

自定义 CA 证书包该用哪个设置?

用 AWS 自己的设置:整台机器用 profile 里的 ca_bundle,某个终端或 CI 任务用 AWS_CA_BUNDLE 环境变量,单条命令用 --ca-bundle 参数。这是文档规定的告诉 botocore 用哪个证书包的方式,--ca-bundle 会覆盖另外两个。

为什么只有某一个 S3 存储桶报错?

看看桶名里有没有点。虚拟主机式请求会把桶名放进主机名,像 my.bucket.example 这样的名字生成的主机名,S3 的通配符证书匹配不上。AWS 建议桶名里不要用点;这类桶把 CLI 改成路径式寻址即可。

用了自定义 --endpoint-url 后报错,要检查什么?

S3 兼容存储、VPC 终端节点、LocalStack 之类的测试服务,常用私有或自签名证书,或者证书上的名字和 --endpoint-url 里写的不一样。把 ca_bundle 指向签发该证书的 CA,并使用证书上的准确主机名。

这和 AWS 凭证有关吗?

无关。TLS 校验发生在请求签名和身份验证之前。凭证有问题时,报错是 TLS 连接成功之后出现的 InvalidAccessKeyId、SignatureDoesNotMatch 之类。

资料来源

  1. AWS CLI User Guide: Troubleshooting errors (SSL certificate errors)
  2. AWS CLI User Guide: Command line options (--ca-bundle, --no-verify-ssl)
  3. AWS CLI User Guide: Configuration file settings (ca_bundle)
  4. AWS CLI: S3 configuration (addressing_style)
  5. Amazon S3 User Guide: General purpose bucket naming rules
  6. botocore source: exceptions.py (SSLError)