
原文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:/CNapi.internal.com ← 服务器证书 i:/CNMy Internal CA ← 签发者中间/根证书 1 s:/CNMy Internal CA i:/CNMy 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 证书报错按照这个流程走curl -v 复现→ 确认具体错误信息unable to get local issuer / certificate expired / self-signed 等理解信任链→ 我们缺的是 CA 根证书不是服务器证书openssl s_client -showcerts→ 查看证书链定位并提取根证书选择修复方案→ 能重建镜像走 Dockerfile不能就临时追加到 ca-bundle.crt验证修复→ 再次 curl -v 确认 SSL 握手成功八、写在最后SSL 证书问题在容器化环境中非常常见尤其是使用自签发证书的内部服务。很多同学遇到这类问题的第一反应是加个InsecureSkipVerify true——能跑但隐患巨大。正确的做法是把 CA 证书打进镜像从源头解决信任问题。成本很低效果永久安全性也有保障。记住在生产环境里绕过安全不是解决问题只是把问题藏起来。本文配套排查命令已整理成速查表回复「SSL」即可获取。— 运维之美 · 守护每一次稳定运行