news 2026/9/30 2:16:40

容器内SSL自签证书不受信?一招帮你解决

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
容器内SSL自签证书不受信?一招帮你解决

原文:ssl自签证书不受信?一招帮你解决

线上 ASR 服务突然回调失败,日志里全是 "certificate signed by unknown authority"。容器内环境有限,没有 sudo,没有 yum 源,你该怎么救?

一、问题现场

项目上反馈新业务部署到客户环境后,测试业务功能始终有问题。这个服务运行在 openEuler 24.03 容器中,负责语音识别完成后向平台回调转写结果。

应用日志中不断刷出这样的错误:

{"file":"ai-meeting-asr-server/dispatcher/callback_dispacher.go:45", "level":"ERROR", "msg":"[callback]create req error:Post \"https://api.internal.com/meeting/...\": tls: failed to verify certificate: x509: certificate signed by unknown authority"}

错误信息很明确:TLS 握手失败,客户端不信任服务端的证书。但诡异的是,同一套证书之前一直跑得好好的,而且手动用 curl 测试同一地址完全正常。

到底哪里出了问题?

二、用 curl 还原现场

排查 SSL 问题的第一步,永远是用curl -v精确复现。进入容器后执行:

curl -v https://api.internal.com/meeting/api/v1/callback/transcripts/...

输出的 TLS 握手过程清晰地展示了问题:

* SSL certificate problem: unable to get local issuer certificate * Closing connection 0 curl: (60) SSL certificate problem: unable to get local issuer certificate

关键信息:unable to get local issuer certificate。这意味着 curl 在本地信任库中找不到签发服务端证书的 CA 根证书。

为什么会这样?因为容器使用的是自签发的内部 CA 证书,而 openEuler 基础镜像的 CA 信任库中没有导入这张根证书。

三、为什么必须拿 CA 根证书,而不是服务器证书?

很多同学到这里会有疑问:我直接把域名的证书下载下来不行吗?为什么非要用 openssl 去拿 CA 根证书?

要理解这个问题,先搞清楚 SSL 证书验证的信任链:

CA 根证书(Root CA) │ ▼ 签发 中间证书(Intermediate CA,可能有多级) │ ▼ 签发 服务器证书(Server Certificate) ← 你访问的网站持有的

客户端验证服务端身份时,不是直接看服务器证书本身,而是沿着这条链逐级往上追溯,直到找到一个自己信任的根证书。如果追溯到顶都没找到信任的根,就会报unknown authority。

换句话说:

  • 服务器证书= 这台服务器的"身份证"
  • CA 根证书= 签发这张身份证的"公安局"

你拿到"身份证"(服务器证书)没用,客户端不认识"公安局"(CA 根证书),照样不信你。你得把"公安局"的备案信息(CA 根证书)加到本地信任库里,验证才能通过。

💡一句话总结:我们需要导入的是签发者的证书(CA 根证书),而不是被签发者的证书(服务器证书)。把服务器证书加到信任库,就像把张三的身份证加到警察系统里——没有任何意义。

四、用 openssl s_client 提取 CA 根证书

理解了原理,操作就很简单了。用openssl s_client连接目标服务器,获取完整证书链:

openssl s_client -connect api.internal.com:443 -showcerts

-showcerts会输出完整的证书链信息,类似:

--- Certificate chain 0 s:/CN=api.internal.com ← 服务器证书 i:/CN=My Internal CA ← 签发者(中间/根证书) 1 s:/CN=My Internal CA i:/CN=My Internal CA ← 自己签发自己 = 根证书 ✓ ---

找到Issuer 和 Subject 相同的那张证书(即自己签发自己的根证书),将其内容保存为文件:

openssl s_client -connect api.internal.com:443 -showcerts 2>/dev/null | \ sed -n '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > ca.crt
💡小贴士:如果证书链有多级(根 → 中间 → 服务器),你需要提取最顶层的根证书。验证方法:查看证书的 Issuer 和 Subject 是否一致,一致的就是根证书。

五、解决方案

方案一:程序级修复(推荐,永久生效)

如果你的服务有 Dockerfile,这是最干净的方案——在构建镜像时就把证书加进去:

FROM openeuler/openeuler:24.03 # 安装 ca-certificates 工具 RUN yum install -y ca-certificates # 将自签 CA 证书复制到系统信任目录 COPY ca.crt /etc/pki/ca-trust/source/anchors/ # 更新系统证书信任库 RUN update-ca-trust

原理说明:

  • /etc/pki/ca-trust/source/anchors/是 openEuler/CentOS 系列的自定义证书导入目录
  • 执行update-ca-trust后,系统会将anchors/下的所有证书合并到/etc/pki/tls/certs/ca-bundle.crt
  • 之后容器内所有依赖系统 CA 库的程序(curl、wget、Go、Python requests 等)都能自动信任该证书

重新构建镜像并部署,问题彻底解决。

方案二:运行时追加(临时方案,已运行的容器)

如果容器已经在跑,短时间内不方便重新构建镜像,可以用临时方案救急:

# 将 CA 证书追加到系统 CA 信任包 cat ca.crt >> /etc/pki/tls/certs/ca-bundle.crt # 重启容器内的应用服务 kill -HUP $(pidof your-app) # 发送热重载信号 # 或直接重启容器 docker restart <container_name>
⚠️注意:临时方案的缺点是——容器重启后ca-bundle.crt会恢复原状,需要重新追加。所以这只是救急手段,长期方案请走方案一。

方案三:跳过证书验证(仅限测试环境)

curl -k https://api.internal.com/... # Go 程序中跳过验证(不推荐生产使用) # tls.Config{InsecureSkipVerify: true}

生产环境绝对不要用这个方案!跳过证书验证等于放弃了 TLS 的身份校验,中间人攻击将毫无阻拦。

六、方案对比与选型

方案适用场景是否持久化推荐度
Dockerfile + update-ca-trust新构建镜像 / 有计划重建✅ 永久生效⭐⭐⭐⭐⭐
追加到 ca-bundle.crt已运行容器紧急修复❌ 重启失效⭐⭐⭐
跳过验证 (-k)仅限测试环境调试—⭐(禁用于生产)

七、排查思路总结

遇到容器内 SSL 证书报错,按照这个流程走:

  1. curl -v 复现→ 确认具体错误信息(unable to get local issuer / certificate expired / self-signed 等)
  2. 理解信任链→ 我们缺的是 CA 根证书,不是服务器证书
  3. openssl s_client -showcerts→ 查看证书链,定位并提取根证书
  4. 选择修复方案→ 能重建镜像走 Dockerfile,不能就临时追加到 ca-bundle.crt
  5. 验证修复→ 再次 curl -v 确认 SSL 握手成功

八、写在最后

SSL 证书问题在容器化环境中非常常见,尤其是使用自签发证书的内部服务。很多同学遇到这类问题的第一反应是"加个InsecureSkipVerify = true"——能跑,但隐患巨大。

正确的做法是:把 CA 证书打进镜像,从源头解决信任问题。成本很低,效果永久,安全性也有保障。

记住:在生产环境里,绕过安全不是解决问题,只是把问题藏起来。

📌本文配套排查命令已整理成速查表,回复「SSL」即可获取。

— 运维之美 · 守护每一次稳定运行

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/30 2:15:18

TI全栈嵌入式边缘AI:从MCU选型到端到端部署实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/30 2:11:24

第三篇 驱动理解与应变

相信大家使用到传感器都会用到相应的驱动&#xff0c;该驱动主要都是该设备的厂家提供的&#xff0c;这里的驱动主要是指软件驱动。为啥这里提前将驱动&#xff0c;主要是如果你作为一个算法工程师&#xff0c;如果对所使用的传感器的特性不了解&#xff0c;包括硬件、软件参数…

作者头像 李华
网站建设 2026/9/30 2:07:47

DFS 模板总结:关键是“这一层到底在选择什么?”

DFS 模板总结&#xff1a;关键是“这一层到底在选择什么&#xff1f;” DFS 最核心的思想不是死记代码&#xff0c;而是先想清楚&#xff1a;“这一层我到底在决定什么&#xff1f;”只要这个问题想明白&#xff0c;DFS 通常就知道该怎么写了。一、DFS 通用模板 void dfs(当前状…

作者头像 李华
网站建设 2026/9/30 2:06:22

八皇后问题的多种解法 #DFS #位运算 #状态压缩

https://www.luogu.com.cn/problem/P1219这个有趣的问题我将分三个版本为您解释&#xff0c;主要差时间优化异体现在check函数上&#xff0c;实现原理分别从循环到坐标规律实现的O(1)操作&#xff0c;最后是位运算的极致优化 check函数&#xff1a;检测该位置放置王后是否合法&…

作者头像 李华