非 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 的 Ingress 閘道預設會啟用伺服器名稱指示 (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" :系統會根據 filter chain 選取伺服器憑證,而 filter chain 則是以 sni_host 為依據。如果沒有 sni_host,且未設定預設值,系統就找不到 filter chain。這表示系統不會傳回任何伺服器憑證,如範例用戶端要求所示。
      3. "status": 0:連線已重設,因此沒有狀態碼。
  2. 如要更準確地檢查用戶端是否已啟用 SNI,請在 Apigee Ingress 前方或 Apigee Ingress 本身擷取封包,而非查看記錄。這有助於判斷用戶端是否傳送 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 表示用戶端 (來源) 將「Client Hello」訊息傳送至 Apigee Ingress (目的地)。 client-hello.png
      • 選取「Client Hello」訊息並檢查「Handshake Protocol: Client Hello」時,您會發現缺少「Extension: server_name」client-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. 如要測試 Apigee 端點是否支援非 SNI 用戶端,請使用 OpenSSL 等工具傳送含有或不含 SNI 標頭的請求。al.
    1. 檢查是否已啟用 non-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. 上述回應顯示「no peer certificate available」(沒有可用的對等互連憑證),表示我們在指令中傳遞 -noservername 選項,因此 Apigee 路由中未啟用 SNI 用戶端。如果在使用 -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. 如果萬用字元路徑存在且已啟用 non-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 的用戶端,且未啟用 SNI 的用戶端未在 Apigee Hybrid 安裝中啟用或正確設定,請按照啟用未啟用 SNI 的用戶端文件操作,允許來自未啟用 SNI 用戶端的流量。

    必須收集診斷資訊

    如果按照上述操作說明後問題仍未解決,請收集下列診斷資訊,然後與 Google Cloud 客服團隊聯絡:
    • Overrides.yaml
    • 下列指令的輸出內容
      • kubectl -n apigee get apigeeroutes
      • 針對每個列出的路徑執行下列指令: kubectl -n apigee describe apigeeroute
    • 發生問題的環境群組