如果客户端使用自签证书,如何验证服务器证书链?

解读

在国内金融、政企、IoT 等场景,合规要求往往强制使用国密或企业自签 CA,而 Cloud SQL 默认只信任 Google 官方 CA 签发的服务器证书。面试官想确认两点:

  1. 你是否理解 TLS 双向验证 中“客户端校验服务器”这一环节;
  2. 你是否能把 Cloud SQL 的托管证书体系 与自签 CA 打通,同时满足零信任与可审计。
    回答必须体现“不改动 Google 根证书”的底线,以及“把自签 CA 当作私有信任锚”的思路,否则会被判为“试图破坏托管边界”而直接挂掉。

知识点

  • Cloud SQL 服务器证书链:Google 内部 CA → 区域中间 CA → 实例叶子证书,叶子证书 SAN 字段固定为 <instance-id>.<project-id>.<region>.sql.goog
  • 客户端验证逻辑:Go/MySQL-JDBC/psql 默认使用系统根证书池;只要池里包含 Google Trust Services (GTS) CA,就能完成校验
  • 自签证书场景:客户端系统根证书池里没有 GTS,只有企业私有 CA,因此需要手动构造信任链关闭默认验证(InsecureSkipVerify=false)
  • 国内合规要点:国密双证、CA 证书必须在 国家根 CA 名录 备案,且不得将私钥上传至 GCP;只能把公钥部分注入客户端
  • Cloud SQL Auth Proxy 限制:proxy 默认强制验证 Google 证书,不支持直接替换根证书;必须通过“代理+自定义验证器”或“Private IP + 自签通道”绕过

答案

分三步落地,全程不触碰 Cloud SQL 实例侧配置,完全在客户端解决:

  1. 导出企业自签 CA 公钥
    把企业根 CA 证书(仅公钥)保存为 enterprise-ca.crt,格式 PEM,确保证书 KeyUsage 包含 Digital Signature & KeyCertSign,且 CRL 地址可访问,满足国内审计。

  2. 构造自定义信任池并注入驱动

    • Go 示例:
      rootPool := x509.NewCertPool()
      if ok := rootPool.AppendCertsFromPEM(entCaPEM); !ok {
          log.Fatal("非法 CA 证书")
      }
      tlsConfig := &tls.Config{
          RootCAs:            rootPool,
          ServerName:         "mydb.abc-proj.asia-northeast1.sql.goog", // 必须与 SAN 完全一致
          InsecureSkipVerify: false, // **关键:保持 false,完成主机名校验**
      }
      mysql.RegisterTLSConfig("custom", tlsConfig)
      dsn := "user:pass@tcp(1.2.3.4:3306)/db?tls=custom"
      
    • Java 示例:
      enterprise-ca.crt 导入新 trustStore,启动参数
      -Djavax.net.ssl.trustStore=enterprise.jks -Djavax.net.ssl.trustStorePassword=***
      并在 JDBC URL 追加 sslMode=VERIFY_CA&sslFactory=com.google.cloud.sql.mysql.SocketFactory仍用 Cloud SQL SocketFactory,仅替换信任锚)。
  3. 通道选择

    • 公网 IP:直接连 3306/5433/1433,确保出口防火墙放行 3307 健康检查端口,否则 Cloud SQL 会主动断链
    • Private IP(推荐):通过 VPC 对等或 Private Service Connect 打通企业 VPC 与 Google 内部网络,延迟 <1 ms,不走公网,满足等保 2.0 跨区域加密

结果:客户端仍验证服务器证书,但信任锚从 GTS 切换成企业 CA,既满足零运维托管,又符合国密/自签合规,且无需在 Cloud SQL 侧上传任何证书,完全在 Google 托管边界之外完成。

拓展思考

  • 双向 TLS(mTLS):Cloud SQL 当前不支持客户上传客户端证书,若业务强制双向,可在前面加 Cloud SQL Proxy sidecar + Envoy,由 Envoy 完成 mTLS,再到 Proxy 使用 Google 证书,分层解耦
  • 证书轮换:企业 CA 通常 1~3 年换证,需在客户端实现 热加载 trustStore(Java 可用 KeyStore.refresh,Go 可用 fsnotify),避免重启业务 Pod
  • 混合云场景:若同一套代码要同时访问 Cloud SQL本地 MySQL,可维护双信任池,根据 DNS 后缀自动路由,做到“一份代码,两套根证书”
  • Terraform 模板化:把 enterprise-ca.crt 存进 Secret Manager,Terraform 只传引用,实现 IaC 与证书生命周期分离,满足国内大行审计“密钥不落代码库”的红线