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

> botocore 在 TLS 校验失败时输出 SSL validation failed for <endpoint>。用 ca_bundle 或 AWS_CA_BUNDLE 指定证书包、改正终端节点，或给 S3 改用路径式寻址。

Source: https://ssl.sh/zh/errors/aws-cli-ssl-validation-failed/
Last updated: 2026-11-10

**`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` 模块的错误：

```text
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](https://ssl.sh/zh/errors/python-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 不信任。

- **确认：**

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

签发者是公司名称或安全厂商而不是 Amazon，就可以确认。见[企业 SSL 解密导致的报错](https://ssl.sh/zh/errors/corporate-ssl-inspection/)。

- **修复：** 把代理根证书导出为 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：**

```bash
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`，然后：

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

**Python 里的 boto3：**

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

**桶名带点：**

```bash
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` 正常返回账户信息、调试输出里没有证书错误，问题就解决了：

```bash
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 检测工具](https://ssl.sh/zh/tools/ssl-checker/)检查它的证书链；想了解为什么少一张根证书浏览器没事、CLI 却失败，见[证书链原理](https://ssl.sh/zh/learn/certificate-chains/)。
