一个常见的错误
在 AWS API Gateway 配置自定义域名时,上传 SSL 证书后,控制台可能会弹出一个刺眼的错误:
Certificate chain is missing or incomplete.
The certificate must include the intermediate CA certificates.
很多人会疑惑:证书不是上传成功了吗?为什么还要什么"证书链"?
这篇文章,将详细解释证书链的作用和影响。
一、什么是证书链?
1.1 信任的传递
想象一下这个场景:你去银行办业务,柜员要求你出示身份证。你递过去一张卡片,柜员看了一眼说:"这张卡我无法验证真假,你需要再给我看发证机关的证明。"
SSL 证书也是同理。浏览器不认识你的证书,它需要一条信任链来验证:
1.2 为什么需要中间证书?
你可能会问:为什么不直接用根证书签发服务器证书?
| 方式 | 安全性 | 风险 |
|---|---|---|
| 根证书直接签发 | ❌ 极低 | 根证书私钥一旦泄露,所有证书都失效 |
| 中间证书签发 | ✅ 高 | 中间证书泄露只影响该中间证书下的证书 |
中间证书就像"代理人":根证书把签发权限委托给中间证书,自己则离线保存,大大降低风险。
二、证书链缺失的影响范围
2.1 AWS 服务影响全景图
2.2 API Gateway 为什么最严格?
API Gateway 是 AWS 中对证书链要求最严格的服务,原因如下:
API Gateway 在边缘位置处理 HTTPS 请求,需要向客户端出示完整的证书链。如果证书链不完整:
- 某些客户端(如 Firefox)会直接拒绝连接
- API 调用失败,返回 SSL 握手错误
- 影响所有依赖 API Gateway 的服务(如 Lambda、AppSync)
三、如何正确导入证书链
3.1 证书文件的组成
一个完整的证书文件应该包含:
-----BEGIN CERTIFICATE-----
服务器证书内容
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
中间证书内容(可能有多个)
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
根证书内容(可选,通常不需要)
-----END CERTIFICATE-----
3.2 获取证书链的方法
方法一:从 CA 获取
大多数 CA 会提供一个压缩包,包含:
your_domain.crt- 服务器证书intermediate.crt- 中间证书ca-bundle.crt- 完整证书链
方法二:手动拼接
# 拼接服务器证书和中间证书
cat your_domain.crt intermediate.crt > fullchain.crt
# 或者按顺序拼接
cat your_domain.crt > fullchain.crt
cat intermediate1.crt >> fullchain.crt
cat intermediate2.crt >> fullchain.crt
方法三:从服务器获取
# 查看远程服务器的证书链
openssl s_client -connect example.com:443 -showcerts
# 导出证书链
openssl s_client -connect example.com:443 -showcerts /dev/null | openssl x509 -outform PEM > certchain.pem
3.3 验证证书链完整性
# 验证证书链
openssl verify -CAfile intermediate.crt your_domain.crt
# 验证完整证书链
openssl verify -CAfile ca-bundle.crt fullchain.crt
# 查看证书链信息
openssl crl2pkcs7 -nocrl -certfile fullchain.crt | openssl pkcs7 -print_certs -noout
3.4 如何检查证书链顺序?
证书链必须按照从下到上的顺序拼接,即:直接签发者 → 上级签发者 → 更上级签发者 → 根证书。顺序错误会导致验证失败。
如何确定顺序?
每个证书都有 subject(主题)和 issuer(签发者)信息。正确的顺序是:
- 服务器证书的
issuer= 第一个中间证书的subject - 第N个中间证书的
issuer= 第N+1个中间证书的subject - 以此类推,直到根证书
快速检查命令:
# 查看每个证书的签发者和主题
openssl x509 -in file1.crt -noout -subject -issuer
openssl x509 -in file2.crt -noout -subject -issuer
openssl x509 -in file3.crt -noout -subject -issuer
# 输出示例:
# subject=CN = Intermediate CA 3
# issuer=CN = Intermediate CA 2 ← 说明 CA2 签发了 CA3
验证顺序是否正确:
# 验证证书链顺序
cat cert1.crt cert2.crt cert3.crt > chain.crt
openssl verify -CAfile chain.crt server.crt
# 输出 "OK" = 顺序正确
# 输出错误 = 顺序不对或缺少证书
如果顺序错了会怎样?
| 情况 | 结果 |
|---|---|
| AWS 导入 | 可能成功(AWS 有时会自动调整) |
| 客户端验证 | ❌ 可能失败,报证书链错误 |
| 最佳实践 | ❌ 必须按正确顺序 |
建议:用上面的命令检查每个文件的 subject 和 issuer,按签发关系排序。
3.5 导入到 AWS IAM
# 上传证书(必须包含证书链)
aws iam upload-server-certificate \
--server-certificate-name my-cert \
--certificate-body file://server.crt \
--private-key file://server.key \
--certificate-chain file://intermediate.crt
# 验证上传结果
aws iam get-server-certificate --server-certificate-name my-cert
3.6 导入到 AWS ACM
# 导入证书到 ACM
aws acm import-certificate \
--certificate file://server.crt \
--private-key file://server.key \
--certificate-chain file://intermediate.crt \
--region us-east-1
# 注意:ACM 证书只能用于特定的 AWS 服务
# API Gateway 和 CloudFront 要求证书在 us-east-1 区域
四、常见问题排查
4.1 如何判断证书链是否完整?
4.2 不同浏览器的行为差异
| 浏览器 | 证书链缺失时的行为 | 原因 |
|---|---|---|
| Chrome/Edge | 可能正常访问 | 自动缓存中间证书(AIA 扩展) |
| Firefox | 直接报错 | 不缓存中间证书,严格验证 |
| Safari | 可能正常访问 | 依赖系统证书库 |
| Android 浏览器 | 可能报错 | 取决于系统版本 |
| iOS Safari | 可能正常访问 | 依赖系统证书库 |
| curl/openssl | 直接报错 | 无缓存机制,严格验证 |
4.3 常见错误信息
| 错误信息 | 原因 | 解决方案 |
|---|---|---|
| Certificate chain is missing | 未上传中间证书 | 添加证书链 |
| unable to get local issuer certificate | 证书链不完整 | 检查中间证书顺序 |
| certificate verify failed | 根证书不在信任库 | 使用主流 CA 证书 |
| SSL handshake failed | 证书格式错误 | 检查 PEM 格式 |
五、最佳实践
5.1 推荐做法
5.2 证书链检查脚本
#!/bin/bash
# 检查证书链完整性
CERT_FILE=$1
if [ -z "$CERT_FILE" ]; then
echo "用法: $0 <证书文件>"
exit 1
fi
echo "=== 证书链检查 ==="
# 统计证书数量
CERT_COUNT=$(grep -c "BEGIN CERTIFICATE" "$CERT_FILE")
echo "证书数量: $CERT_COUNT"
if [ "$CERT_COUNT" -lt 2 ]; then
echo "⚠️ 警告: 证书链可能不完整(建议至少2个证书)"
else
echo "✓ 证书链包含 $CERT_COUNT 个证书"
fi
# 提取并验证每个证书
echo ""
echo "=== 证书详情 ==="
openssl crl2pkcs7 -nocrl -certfile "$CERT_FILE" 2>/dev/null | \
openssl pkcs7 -print_certs -noout 2>/dev/null | \
grep -E "subject=|issuer="
# 验证证书链
echo ""
echo "=== 验证结果 ==="
if openssl verify -CAfile "$CERT_FILE" "$CERT_FILE" 2>/dev/null; then
echo "✓ 证书链验证通过"
else
echo "❌ 证书链验证失败"
fi
六、为什么 CloudFront 和 API Gateway 要求 us-east-1 区域的证书?
很多开发者会有这个疑问:"我的服务部署在 ap-northeast-1(东京)或 cn-north-1(北京),为什么证书非要放在 us-east-1?"
6.1 用一个比喻来理解
想象一下,你开了一家连锁餐厅:
- 你的主厨房在东京(你的服务所在区域)
- 外卖配送点遍布全球(CloudFront 边缘节点)
- 营业执照(SSL 证书)需要挂在每个配送点
问题是:营业执照应该放在哪里?
- 如果放在东京主厨房,全球 200+ 个配送点每次都要跨洋查询,太慢了
- 如果放在一个统一的管理中心,所有配送点都能快速获取
AWS 选择了后者:us-east-1(弗吉尼亚)就是 AWS 的"全球管理中心"。
6.2 技术层面的解释
CloudFront 是全球服务,它的 200+ 个边缘节点分布在世界各地。这些节点需要:
- 统一从某个地方获取证书配置
- 快速响应全球用户的 HTTPS 请求
AWS 选择 us-east-1 作为全球服务的"控制平面"所在地,所有 CloudFront 的配置(包括证书)都存储在这里,然后分发到全球边缘节点。
6.3 不同服务的证书区域要求
| 服务 | 证书区域要求 | 原因 |
|---|---|---|
| CloudFront | 必须 us-east-1 | 全球服务,控制平面在 us-east-1 |
| API Gateway(边缘优化) | 必须 us-east-1 | 底层使用 CloudFront 分发 |
| API Gateway(区域) | 与 API 同区域 | 不经过 CloudFront,直接在区域内部处理 |
| ALB/ELB | 与负载均衡器同区域 | 区域服务,不涉及全球分发 |
| App Runner | us-east-1 | 使用 CloudFront 作为入口 |
6.4 中国区 AWS 和 Global AWS 的区别
6.5 实际案例:我在东京部署服务,证书放哪里?
场景:你的应用部署在 ap-northeast-1(东京),想用 CloudFront 加速。
重要说明:你不需要在 AWS 控制台手动选择证书区域。AWS 会自动检查证书所在区域,如果证书不在正确的区域,会直接报错。
# 步骤1:在 us-east-1 申请/导入证书
aws acm request-certificate \
--domain-name example.com \
--validation-method DNS \
--region us-east-1
# 步骤2:在东京区域部署你的应用
# (Lambda、EC2、S3 等)
# 步骤3:创建 CloudFront 分发
# CloudFront 会自动从 us-east-1 获取证书
# 并分发到全球边缘节点
6.6 常见错误:证书区域不匹配
当你在 CloudFront 或 API Gateway 配置自定义域名时,如果证书不在正确的区域,AWS 会显示类似以下错误:
Error: Certificate must be in us-east-1 region for CloudFront distribution.
或者中文:
错误:证书必须位于 us-east-1 区域才能用于 CloudFront 分发。
为什么你看不到选择区域的选项?
因为证书区域是自动检测的,不是手动选择的:
- 当你在 CloudFront 控制台配置自定义域名时,下拉列表只显示正确区域的证书
- 如果证书不在 us-east-1,它根本不会出现在列表中
- 你需要先切换到 us-east-1 区域的 ACM 控制台,在那里申请或导入证书
操作步骤:
- 切换 AWS 控制台区域到 us-east-1 (N. Virginia)
- 进入 ACM (Certificate Manager) 控制台
- 申请或导入证书
- 回到 CloudFront 或 API Gateway 配置自定义域名
- 此时下拉列表中会显示你的证书
官方文档说明:
"You must request an ACM certificate in the US East (N. Virginia) Region."
"You must import the certificate in the US East (N. Virginia) Region."
为什么这样设计?
- 证书只需要存储一份(在 us-east-1)
- 全球 200+ 边缘节点自动同步
- 更新证书时,只需在 us-east-1 操作一次
6.7 常见误区
| 误区 | 正确理解 |
|---|---|
| "我的服务在东京,证书也要在东京" | CloudFront 是全球服务,证书需要在其控制平面所在区域(us-east-1) |
| "证书在 us-east-1 会影响性能" | 不会,证书配置只影响初始化,实际 HTTPS 握手在最近的边缘节点进行 |
| "中国区也用 us-east-1" | ❌ 中国区独立运营,使用 cn-north-1 作为控制平面 |
6.8 快速参考
| 你的情况 | 证书区域 |
|---|---|
| Global AWS + CloudFront | us-east-1 |
| Global AWS + API Gateway(边缘优化) | us-east-1 |
| Global AWS + API Gateway(区域) | 与 API 同区域 |
| Global AWS + ALB | 与 ALB 同区域 |
| 中国区 AWS + CloudFront | cn-north-1 |
| 中国区 AWS + API Gateway | cn-north-1 |
七、总结
证书链就像身份证的防伪标识,缺少它,再真实的证书也无法被信任。在 AWS 环境中配置 SSL 证书,需要记住以下几点:
7.1 证书链完整性
| 要点 | 说明 |
|---|---|
| 证书组成 | 服务器证书 + 中间证书(按正确顺序拼接) |
| 顺序规则 | 直接签发者在前,上级签发者在后 |
| 验证命令 | openssl verify -CAfile chain.crt server.crt |
| 常见错误 | 只上传服务器证书,缺少中间证书 |
7.2 证书区域选择
| 服务类型 | 证书区域 | 原因 |
|---|---|---|
| CloudFront / API Gateway(边缘优化) | us-east-1(Global)或 cn-north-1(中国) | 全球服务的控制平面所在区域 |
| ALB / NLB | 与负载均衡器同区域 | 区域服务,无需跨区域 |
| 区域型 API Gateway | 与 API 同区域 | 不经过 CloudFront |
7.3 最佳实践
- 优先使用 ACM 申请证书:AWS 自动管理证书链和续期
- 导入外部证书时:确保包含完整证书链,顺序正确
- 检查证书链:使用
openssl s_client或 SSL Labs 测试 - 注意区域要求:CloudFront 和边缘优化型 API Gateway 有特定区域要求
记住两个公式:
- 完整证书 = 服务器证书 + 中间证书(按顺序)
- 全球服务证书区域 = us-east-1(Global)或 cn-north-1(中国)
缺少中间证书,就是给 AWS 服务埋下一颗定时炸弹;选错证书区域,CloudFront 和 API Gateway 就会报错。掌握这两点,SSL 证书配置就不再是难题。
📜 版权声明
本文作者:王梓 | 原文链接:https://www.bthlt.com/note/369662064-LinuxSSL证书链:一个被忽视的配置细节,让AWS服务集体罢工
出处:葫芦的运维日志 | 转载请注明出处并保留原文链接


📜 留言板
留言提交后需管理员审核通过才会显示