非 SNI 客户端在 TLS 握手期间连接重置

症状

您的客户端应用在调用 Apigee 端点时,可能会在 TLS 握手期间遇到连接重置、连接遭拒或类似错误。

错误消息

  • Postman 或 Node.js 客户端可能会看到 ECONRESET 错误消息。

  • 当直接向 Apigee Ingress IP 地址发出 HTTPS 调用时,Curl 可能会显示 Connection reset by peer。例如:

    curl https://1.2.3.4/basepath -H "Host: your.apigee.domain" -kv
    * Connected to 1.2.3.4 (1.2.3.4) port 443
    * (304) (OUT), TLS handshake, Client hello (1):
    * Recv failure: Connection reset by peer
    * Closing connection 
  • 其他客户端可能会显示不同的错误。不过,模式是相同的;客户端在 TLS 握手期间无法完全建立连接。

可能的原因

Apigee Hybrid 的入站流量网关默认启用服务器名称指示 (SNI)。如果您的客户端未启用 SNI,并且未配置通配符 Apigee 路由来启用非 SNI 客户端,则可能会出现此问题。这会导致系统不会向客户端发送默认 TLS 服务器证书,并且 Apigee 入口 TCP 重置会发生。

诊断

  1. 确定您的客户端是否已启用 SNI。如果您已经知道未启用 SNI,请继续执行第 4 步,验证 Apigee Hybrid 配置。

    查看 Apigee Ingress 访问日志,了解是否有客户端请求未包含 SNI 服务器名称,并检查虚拟主机是否未为非 SNI 客户端配置默认证书。

    • 使用以下命令获取 apigee-ingressgateway pod 的列表:
      kubectl -n apigee get pods -l app=apigee-ingressgateway

      示例输出

      NAME                                                              READY   STATUS    RESTARTS   AGE
      apigee-ingressgateway-ext-ingress-myorg-hyb-8f2c412-dvrcp         2/2     Running   0          46h
      apigee-ingressgateway-ext-ingress-myorg-hyb-8f2c412-wg26k         2/2     Running   0          46h
      
    • 获取 apigee-ingressgateway pod 的日志。
      kubectl -n apigee logs APIGEE_INGRESSGATEWAY_POD
      其中,APIGEE_INGRESSGATEWAY_POD 是上一个命令输出中列出的 apigee-ingressgateway pod。
    • 访问日志可能如下所示:
      {
        "request_time": 1,
        "tls_protocol": null,
        "upstream_service_time": null,
        "request_method": null,
        "request_protocol": null,
        "upstream_response_time": null,
        "bytes_sent": 0,
        "start_time": "2025-05-19T04:46:20.117Z",
        "bytes_received": 0,
        "host": null,
        "upstream_cluster": null,
        "upstream_address": null,
        "remote_address": "10.138.0.28:19432",
        "request_path": null,
        "request_id": null,
        "user_agent": null,
        "status_details": "filter_chain_not_found",
        "request": "- - -",
        "status": 0,
        "x_forwarded_for": null,
        "apigee_dynamic_data": null,
        "upstream_response_flags": "NR",
        "sni_host": null
      }
      
    • 通过分析上述日志,您可以推断出以下信息:
      1. "sni_host": null:客户端未启用 SNI,因为没有 SNI 主机名。例如,api-test.mydomain.com 与此请求相关联。
      2. "status_details": "filter_chain_not_found" :服务器证书是根据 sni_host 中的 filter chain 选择的。如果不存在 sni_host 且未配置默认值,则找不到 filter chain。这意味着不会返回任何服务器证书,如示例客户端请求所示。
      3. "status": 0:由于连接已重置,因此没有状态代码。
  2. 除了查看日志之外,还可以通过在 Apigee Ingress 前面或 Apigee Ingress 本身捕获数据包,更精确地检查客户端是否已启用 SNI。这有助于确定客户端是否在 TLS 握手时发送 SNI 标头。
    1. 若要在 Google Kubernetes Engine 上运行 Apigee Ingress,您需要通过 SSH 连接到运行 Ingress 网关的节点,并安装 toolbox 和 tcpdump。
      tcpdump -n -i any -s 0 'host IP_Address' -w FILE_NAME

      其中,FILE_NAME 是您要保存数据包捕获输出的文件名(包括路径)。

    2. 使用 Wireshark 或类似工具分析捕获的数据包。
    3. 以下是使用 Wireshark 在 Apigee Ingress 上捕获的数据包的分析示例。 。
      • 在数据包捕获输出中,消息 #83 表示客户端(来源)向 Apigee Ingress(目的地)发送了“Client Hello”消息。 client-hello.png
      • 当您选择 Client Hello 消息并检查 Handshake Protocol: Client Hello 时,会发现缺少 Extension: server_nameclient-hello-extension.png
      • 例如,启用 SNI 的客户端将在输出中显示 Extension: server_name,如以下示例所示。 client-hello-extension-sni.png
      • 这确认了客户端未将 server_name 发送到 Apigee Ingress。
      • 由于 Client Hello 消息中未包含任何 SNI server_name,因此不会返回任何服务器证书,并且 Apigee Ingress 会使用 RST 数据包关闭连接。
  3. 通过使用 OpenSSL 等工具测试 Apigee 端点来检查是否支持非 SNI 客户端,以发送带有或不带有 SNI 标头的请求。al。
    1. 检查非 SNI 客户端是否已启用。
      openssl s_client -connect api-test.mydomain.com:443 -noservername

      输出示例

      Connecting to 1.2.3.4
      CONNECTED(00000005)
      write:errno=54
      ---
      no peer certificate available
      ---
      No client certificate CA names sent
      ---
      SSL handshake has read 0 bytes and written 299 bytes
      Verification: OK
      ---
      New, (NONE), Cipher is (NONE)
      This TLS version forbids renegotiation.
      Compression: NONE
      Expansion: NONE
      No ALPN negotiated
      Early data was not sent
      Verify return code: 0 (ok)
      ---
      
      
    2. 上述响应显示没有可用的对等证书,这意味着 Apigee 路由中未启用 SNI 客户端,因为我们在命令中传递了 -noservername 选项。如果在使用 -noservername 标志时返回了对等证书,则表明已配置通配符路由。
  4. 查看当前的 Apigee 路由配置,了解虚拟主机上是否已配置并启用通配符路由。
    1. 使用以下命令获取已定义的 Apigee 路由的列表:
      kubectl -n apigee get apigeeroutes 

      示例输出

      NAME                                  STATE     AGE
      myorg-hyb-dev-grp-000-33620d0         running   2d1h
      non-sni                               running   17s
      
    2. 检查每个 Apigee 路由中是否包含通配符主机名。

      对于每个 Apigee 路由,执行提供的命令以检索其已定义主机名的 JSON 数组。输出中会使用星号 (*) 指示通配符路由。

      kubectl -n apigee get apigeeroute APIGEE_ROUTE_NAME

      myorg-hyb-dev-grp-000-33620d0 路线的示例:

      kubectl -n apigee get apigeeroute myorg-hyb-dev-grp-000-33620d0 -o jsonpath='{.spec.hostnames}'

      示例输出

      ["api-test.mydomain.com"]

      non-sni 路线的示例:

      kubectl -n apigee get apigeeroute non-sni -o jsonpath='{.spec.hostnames}'

      示例输出

      ["*"]

      non-sni apigeeroute 是通配符路由,因为它包含 (*) 作为主机名。

    3. 如果配置了通配符路由,则会启用非 SNI 客户端。
    4. 对于通配符路由,请确保 enableNonSniClient 标志设置为 true。以下命令在具有 non-sni 客户端的通配符路由上运行。
      kubectl -n apigee get apigeeroute non-sni -o jsonpath='{.spec.enableNonSniClient}'

      示例输出

      true
    5. 如果通配符路由存在且非 SNI 客户端已启用,请查看 overrides.yaml 文件中的虚拟主机配置,确保通配符路由列在 additionalGateways 中。
      virtualhosts:
      - name: dev-grp
        selector:
          app: apigee-ingressgateway
          ingress_name: ext-ingress
        sslCertPath: ./certs/keystore_dev-grp.pem
        sslKeyPath: ./certs/keystore_dev-grp.key
        additionalGateways: ["non-sni"]
        
    6. additionalGateways 将显示在虚拟主机配置定义的 Apigee 路由中。 使用以下命令确认您配置的 additionalGateway 是否显示在 Apigee 路由配置中。
        kubectl -n apigee get apigeeroute APIGEE_ROUTE_NAME -o jsonpath='{.spec.additionalGateways}

      例如,myorg-hyb-dev-grp-000-33620d0 路线应将 non-sni 路线显示为 additionalGateway

        kubectl -n apigee get apigeeroute myorg-hyb-dev-grp-000-33620d0 -o jsonpath='{.spec.additionalGateways}'

      示例输出

      ["non-sni"]

    解决方法

    如果诊断步骤表明您的客户端是已启用非 SNI 的客户端,但您的 Apigee Hybrid 安装中未启用或未正确配置非 SNI 客户端,请按照启用非 SNI 客户端文档中的说明操作,以允许来自非 SNI 客户端的流量。

    必须收集的诊断信息

    如果按照上述说明操作后问题仍然存在,请收集以下诊断信息,然后与 Google Cloud Customer Care 联系:
    • Overrides.yaml
    • 以下命令的输出
      • kubectl -n apigee get apigeeroutes
      • 针对每个声明的路由,运行: kubectl -n apigee describe apigeeroute
    • 出现问题的环境组