命令行工具

SSL certificate problem:Git clone/push 报错怎么修

作者: · 最后核实

报错信息fatal: unable to access 'https://git.example.com/team/repo.git/': SSL certificate problem: unable to get local issuer certificate

Git 报 SSL certificate problem,意思是:连接远程仓库的 HTTPS 证书验证失败,Git 没法把服务器证书链接到它信任的 CA。 绝大多数情况是自建 Git 服务器证书链不完整或用了私有 CA,或者公司代理在解密 HTTPS。

快速修复

服务器缺中间证书就到服务器上补链;用私有 CA 就让 Git 只对这台主机信任它的根证书。先看 Git 服务器实际发出的证书:

openssl s_client -connect git.example.com:443 -servername git.example.com -showcerts </dev/null
  • 只有一张证书,验证码 20 或 21: 服务器缺中间证书,到服务器上修(见下文),所有客户端一起受益。
  • 链是完整的,签发者是公司 CA 或代理: 只对这台主机信任该根证书:
git config --global http."https://git.example.com/".sslCAInfo /path/to/company-root.pem
  • Windows 上,如果根证书已经在 Windows 证书库里(加入公司域的电脑一般都是):
git config --global http.sslBackend schannel

原因

这个报错有 4 种原因,最常见的是自建 GitLab、Gitea 的证书链不完整。Git 通过 libcurl 校验证书,和 curl 报错 60 是同一类问题。

1. Git 服务器证书链不完整

自建的 GitLab、Gitea、Gogs 经常只配置了站点证书,没发中间证书。

  • 确认: openssl s_client -showcerts 只列出一张证书。
  • 修复: GitLab Omnibus 读取 /etc/gitlab/ssl/<主机名>.crt,把站点证书和中间证书依次写进这个文件,再执行 gitlab-ctl hup nginx。Gitea 或前置反向代理就在 Nginx、Apache 里配置完整链。在阿里云、腾讯云下载证书时选 Nginx 格式,里面的 pem 文件一般已经包含中间证书。详见缺少中间证书。

2. 私有 CA 或自签名证书

公司内网的代码仓库常用内部 CA,报错也可能是 self-signed certificate in certificate chain。

  • 确认: 证书链最上面的签发者是公司内部名称。
  • 修复: 按上文设置 http.sslCAInfo,或者把根证书加入系统信任库,Git、curl 等工具都能用上。见证书链中有自签名证书。

3. 企业代理、上网行为管理解密 HTTPS

  • 确认: 连 github.com、gitee.com 这类公网仓库也报同样的错,证书签发者是安全厂商的名字。
  • 修复: 找 IT 要代理根证书。Windows 上设置 http.sslBackend schannel 往往立刻解决,因为 IT 通常已经把根证书推送到 Windows 证书库。

4. 客户端 CA 证书包过旧

CentOS 7 等老系统、精简容器可能缺少较新的根证书。

  • 确认: 执行 GIT_CURL_VERBOSE=1 git ls-remote https://git.example.com/team/repo.git,看使用的 CA 文件是否存在、是否过旧。
  • 修复: 更新 ca-certificates 包。

各环境修法

各系统的做法都是把私有根证书交给 Git 实际使用的证书库:Linux 用系统 CA 包,Windows 可以切换到 Schannel 读 Windows 证书库。

Linux(Debian/Ubuntu)

sudo cp company-root.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates

CentOS、RHEL、Alibaba Cloud Linux 复制到 /etc/pki/ca-trust/source/anchors/ 后执行 update-ca-trust。

Windows(Git for Windows): 有两种后端:自带 OpenSSL 和自己的 CA 文件,或者 Schannel 加 Windows 证书库。git config --global http.sslBackend schannel 切换到证书库;想继续用 OpenSSL,就把 http.sslCAInfo 指向包含公司根证书的证书包。

macOS: 把根证书加入“系统”钥匙串;如果 Git 用的是自带 OpenSSL 证书包的版本(Homebrew 安装的常见),再设置 http.sslCAInfo。

CI 和容器(GitLab Runner、Jenkins、云效等): 镜像里安装 ca-certificates,复制内部根证书后执行 update-ca-certificates;单个任务也可以设置环境变量 GIT_SSL_CAINFO=/path/to/root.pem。

只对某个仓库生效: 在仓库目录里执行 git config http.sslCAInfo /path/to/root.pem(不加 --global)。

不要这样做

关闭校验后 Git 不再核实服务器身份,账号令牌和代码都可能被截获或篡改。

  • git config --global http.sslVerify false。 这会让当前用户访问所有 HTTPS 仓库时都不校验,包括 GitHub、Gitee。
  • 在 CI 里设置 GIT_SSL_NO_VERIFY=true。 流水线往往带着部署令牌,中间人拿到令牌后可以往构建里注入代码。
  • “就这一次”用 git -c http.sslVerify=false clone。 仓库克隆下来之后照常能用,根本原因没人去修,这条命令还会被抄进团队文档。

常见问题

浏览器能打开 GitLab 页面,git clone 却报错,为什么?

浏览器会自动补齐缺失的中间证书,信任的根证书也可能比 Git 用的证书包多;Git(通过 libcurl)不会补。用证书链补全工具检查服务器,如果只发了站点证书,就在服务器上修。

怎么只对公司内部那台 Git 服务器信任私有证书?

用按 URL 限定的配置:git config --global http."https://git.example.com/".sslCAInfo /path/to/company-root.pem。访问 GitHub、Gitee 等其他远程仓库仍使用默认证书包。

内网服务器,设置 http.sslVerify false 不行吗?

不行。内网同样可能有人冒充服务器,拿到你的账号密码或访问令牌,再给你返回被改过的代码。用 http.sslCAInfo 信任内部根证书,工作量一样,校验还在。

改用 SSH 能绕开吗?

可以。SSH 地址(git@git.example.com:team/repo.git)不用 TLS 证书,不会出现这个报错。但第一次连接要核对 SSH 主机指纹;其他用 HTTPS 的同事仍然会遇到问题,服务器证书链最好还是修好。

资料来源

  1. git-config documentation (http.sslCAInfo, http.sslBackend)
  2. curl: SSL Certificate Verification
  3. OpenSSL openssl-s_client