You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

客户端使用insecure模式时Ingress Nginx无法代理gRPC的原因

问题背景
  • 请求链路:go-client --> ingress-nginx --> grpc pod
  • 部署环境为私有网络,未采购公网可信CA签发证书,采用自签名证书配置Ingress TLS规则。测试过程中,加载自签证书的客户端可正常发起gRPC调用,使用insecure.NewCredentials()配置传输凭证的客户端调用失败,返回400 Bad Request,对应Nginx访问日志记录为:
"PRI * HTTP/2.0" 400
  • 可正常运行的客户端代码:
cert, _ := credentials.NewClientTLSFromFile("./example.pem", "example.com")
conn, err := grpc.DialContext(
    ctx,
    "example.com:443",
    grpc.WithTransportCredentials(cert),
    grpc.WithBlock(),
)
  • 调用失败的客户端代码:
conn, err := grpc.DialContext(
    ctx,
    "example.com:443",
    grpc.WithTransportCredentials(insecure.NewCredentials()),
    grpc.WithBlock(),
)
  • 本次使用的Ingress配置如下:
apiVersion: networking.k8s.io/v1
kind: Ingress
spec:
  ingressClassName: nginx
  tls:
  - hosts: example.com
    secretName: example-tls
  rules:
  - host: example.com
    http:
      paths:
      - path: /foo/bar
        pathType: Prefix
        backend:
          service: grpc-svc
          port:
            name: grpc-port
核心结论

1. insecure参数的准确含义

很多人会误以为insecure.NewCredentials()的作用是「走TLS但跳过服务端证书校验」,这个认知完全错误:

  • insecure.NewCredentials()返回的传输凭证会完全关闭TLS加密层,客户端直接通过明文HTTP/2协议向服务端发起通信,整个传输过程没有TLS握手、没有证书校验、流量全明文。
  • 真正的「TLS下跳过证书校验」是独立的配置,仍然会走完整TLS握手流程,只是不校验服务端证书的信任链、域名匹配关系,示例代码如下:
import "crypto/tls"
import "google.golang.org/grpc/credentials"

// 注意:该配置存在中间人攻击风险,生产环境不推荐使用
creds := credentials.NewTLS(&tls.Config{
    InsecureSkipVerify: true,
})
conn, err := grpc.DialContext(
    ctx,
    "example.com:443",
    grpc.WithTransportCredentials(creds),
    grpc.WithBlock(),
)

2. 400报错的根因

当前Ingress配置了TLS规则,Nginx的443端口会优先等待客户端发起TLS ClientHello报文,完成TLS握手后才会处理上层HTTP/2流量:

  • 正常工作的代码加载了自签证书作为根信任锚,客户端会正常发起TLS握手,用本地的自签证书完成服务端身份校验,TLS隧道建立后再传输gRPC的HTTP/2流量,Nginx可以正常处理并转发给后端Pod。
  • 使用insecure.NewCredentials()的客户端完全不发起TLS握手,直接向443端口发送明文的HTTP/2连接前言(内容就是PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n)。Nginx在443端口没收到预期的TLS握手报文,会把收到的内容当明文HTTP/1.x请求解析,而PRI不是HTTP/1.x支持的请求方法,因此直接返回400 Bad Request,和日志记录完全吻合。
修复方案

三选一即可,优先推荐第一种:

  • 保持现有Ingress TLS配置不变,客户端加载自签CA证书(即第一段正常工作的代码写法)发起TLS连接,是私有环境下的最稳妥方案。
  • 如果一定要用跳过证书校验的TLS连接,使用上文给出的InsecureSkipVerify: true的凭证配置,不要用insecure.NewCredentials()。
  • 如果确实需要走明文gRPC,需要给Ingress Nginx配置明文gRPC监听(默认使用80端口),同时去掉对应路由的TLS配置,并开启Nginx的h2c支持,生产环境不推荐该方案。

内容的提问来源于stack exchange,提问作者caibirdme

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 03:48:24