SNI 이외의 클라이언트의 TLS 핸드셰이크 중 연결 재설정

증상

Apigee 엔드포인트를 호출할 때 TLS 핸드셰이크 중에 클라이언트 애플리케이션에 연결 재설정, 연결 거부 또는 유사한 오류가 발생할 수 있습니다.

오류 메시지

  • Postman 또는 Node.js 클라이언트에 ECONRESET 오류 메시지가 표시될 수 있습니다.

  • Apigee 인그레스 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가 사용 설정되어 있지 않고 SNI 이외의 클라이언트를 사용 설정하도록 구성된 와일드카드 Apigee 경로가 없는 경우 발생할 수 있습니다. 이로 인해 기본 TLS 서버 인증서가 클라이언트로 전송되지 않고 Apigee 인그레스 TCP 재설정이 발생합니다.

진단

  1. 클라이언트에서 SNI가 사용 설정되어 있는지 확인합니다. SNI가 사용 설정되어 있지 않다는 것을 이미 알고 있다면 4단계로 진행하여 Apigee Hybrid 구성을 검증하세요.

    SNI 서버 이름이 없는 클라이언트 요청의 징후가 있는지 Apigee 인그레스 액세스 로그를 검토하고 가상 호스트가 SNI 이외의 클라이언트의 기본 인증서로 구성되어 있지 않은지 확인합니다.

    • 다음 명령어를 사용하여 apigee-ingressgateway 포드 목록을 가져옵니다.
      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 포드의 로그를 가져옵니다.
      kubectl -n apigee logs APIGEE_INGRESSGATEWAY_POD
      여기서 APIGEE_INGRESSGATEWAY_POD는 이전 명령어 출력에 나열된 apigee-ingressgateway 포드입니다.
    • 액세스 로그는 다음과 같이 표시될 수 있습니다.
      {
        "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. 로그를 검토하는 대신 클라이언트가 SNI를 사용 설정했는지 확인하는 더 정확한 방법은 Apigee 인그레스 앞이나 Apigee 인그레스 자체에서 패킷 캡처를 실행하는 것입니다. 이를 통해 클라이언트가 TLS 핸드셰이크를 위해 SNI 헤더를 전송하는지 확인할 수 있습니다.
    1. Google Kubernetes Engine의 Apigee Ingress에서 실행하려면 인그레스 게이트웨이를 실행하는 노드에 SSH를 연결하고 toolbox와 tcpdump를 설치해야 합니다.
      tcpdump -n -i any -s 0 'host IP_Address' -w FILE_NAME

      여기서 FILE_NAME은 패킷 캡처 출력을 저장할 파일의 이름(경로 포함)입니다.

    2. Wireshark 또는 유사한 도구를 사용하여 패킷 캡처를 분석합니다.
    3. 다음은 Apigee 인그레스에서 Wireshark를 사용하여 캡처한 패킷의 샘플 분석입니다. .
      • 패킷 캡처 출력에서 메시지 #83은 클라이언트 (소스)가 Apigee 인그레스 (대상)에 'Client Hello' 메시지를 보냈음을 나타냅니다. 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
      • 이는 클라이언트가 Apigee 인그레스에 server_name을 전송하지 않았음을 확인합니다.
      • 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. 위 응답에는 사용 가능한 피어 인증서가 없음이 표시됩니다. 이는 명령에 -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. 와일드카드 경로가 있고 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 Customer Care에 문의하세요.
    • Overrides.yaml
    • 다음 명령어의 출력
      • kubectl -n apigee get apigeeroutes
      • 명시된 각 경로에 대해 다음을 실행합니다. kubectl -n apigee describe apigeeroute
    • 문제가 발생하는 환경 그룹