Skip to content

Auto-detect upstream protocol breaks with multiple backends (HTTP + HTTPS) #7917

@Inode1

Description

@Inode1

Description:
Envoy Gateway’s upstream protocol auto-detection #6792 breaks when an HTTPRoute contains multiple backends with a mix of plain HTTP and HTTPS.
The generated cluster enables HttpProtocolOptions.auto_config causing TLS traffic to be sent to plain HTTP backends.

Root Cause:
Per Envoy documentation:

  1. AutoHttpConfig requires ALPN
  2. ALPN requires TLS
  3. A cluster using AutoHttpConfig cannot contain non-TLS endpoints

However, Envoy Gateway enables auto-detection without checking that all endpoints use TLS.

Relevant code: https://github.com/envoyproxy/gateway/blob/main/internal/xds/translator/cluster.go#L257

Repro steps:

  1. Create an HTTPRoute with two backends:
    1.1. Backend A: HTTP (no TLS)
    1.2. Backend B: HTTPS
  2. Apply the route
  3. Inspect the generated cluster
    {
     "version_info": "ce5aff4691bdf2853c73c9c9fa8ffe49508b54eccdd0c798568c003130a45a44",
     "cluster": {
      "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
      "name": "httproute/default/backend/rule/0",
      "type": "EDS",
      "eds_cluster_config": {
       "eds_config": {
        "ads": {},
        "resource_api_version": "V3"
       },
       "service_name": "httproute/default/backend/rule/0"
      },
      "connect_timeout": "10s",
      "per_connection_buffer_limit_bytes": 32768,
      "lb_policy": "LEAST_REQUEST",
      "circuit_breakers": {
       "thresholds": [
        {
         "max_retries": 1024
        }
       ]
      },
      "dns_lookup_family": "V4_ONLY",
      "transport_socket": {
       "name": "dummy.transport_socket",
       "typed_config": {
        "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext",
        "common_tls_context": {}
       }
      },
      "metadata": {
       "filter_metadata": {
        "envoy-gateway": {
         "resources": [
          {
           "name": "backend",
           "kind": "HTTPRoute",
           "namespace": "default"
          }
         ]
        }
       }
      },
      "common_lb_config": {},
      "ignore_health_on_host_removal": true,
      "typed_extension_protocol_options": {
       "envoy.extensions.upstreams.http.v3.HttpProtocolOptions": {
        "@type": "type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions",
        "upstream_http_protocol_options": {
         "auto_sni": true
        },
        "auto_config": {
         "http_protocol_options": {},
         "http2_protocol_options": {
          "initial_stream_window_size": 65536,
          "initial_connection_window_size": 1048576
         }
        }
       }
      },
      "load_balancing_policy": {
       "policies": [
        {
         "typed_extension_config": {
          "name": "envoy.load_balancing_policies.least_request",
          "typed_config": {
           "@type": "type.googleapis.com/envoy.extensions.load_balancing_policies.least_request.v3.LeastRequest",
           "locality_lb_config": {
            "locality_weighted_lb_config": {}
           }
          }
         }
        }
       ]
      },
      "transport_socket_matches": [
       {
        "name": "httproute/default/backend/rule/0/tls/1",
        "match": {
         "name": "httproute/default/backend/rule/0/tls/1"
        },
        "transport_socket": {
         "name": "envoy.transport_sockets.tls",
         "typed_config": {
          "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext",
          "common_tls_context": {}
         }
        }
       }
      ]
     },
     "last_updated": "2026-01-11T19:55:02.657Z"
    }
   ]
  },

   "dynamic_endpoint_configs": [
    {
     "endpoint_config": {
      "@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
      "cluster_name": "httproute/default/backend/rule/0",
      "endpoints": [
       {
        "locality": {
         "region": "httproute/default/backend/rule/0/backend/0"
        },
        "lb_endpoints": [
         {
          "endpoint": {
           "address": {
            "socket_address": {
             "address": "10.244.0.6",
             "port_value": 3000
            }
           },
           "health_check_config": {}
          },
          "health_status": "HEALTHY",
          "load_balancing_weight": 1
         }
        ],
        "load_balancing_weight": 50
       },
       {
        "locality": {
         "region": "httproute/default/backend/rule/0/backend/1"
        },
        "lb_endpoints": [
         {
          "endpoint": {
           "address": {
            "socket_address": {
             "address": "10.12.4.12",
             "port_value": 80
            }
           },
           "health_check_config": {}
          },
          "health_status": "HEALTHY",
          "metadata": {
           "filter_metadata": {
            "envoy.transport_socket_match": {
             "name": "httproute/default/backend/rule/0/tls/1"
            }
           }
          },
          "load_balancing_weight": 1
         }
        ],
        "load_balancing_weight": 50
       }
      ],
      "policy": {
       "overprovisioning_factor": 140
      }
     }
    }
   ]
  },
  1. Send traffic
Image

Logs:
curl --verbose -k https://www.example.com:8888/get

upstream connect error or disconnect/reset before headers. reset reason: remote connection failure, transport failure reason: TLS_error:|268435703:SSL routines:OPENSSL_internal:WRONG_VERSION_NUMBER:TLS_error_end

Metadata

Metadata

Assignees

Labels

kind/bugSomething isn't working

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions