Istio HBONE CONNECT wait
The contrib Istio HBONE CONNECT adapter delays an internal upstream
connection’s readiness until its HTTP/2 CONNECT stream is accepted. A transient
failure reaches the HTTP router as a connection failure before the router starts
sending the application request. Routes can retry it using connect-failure,
including for POST requests.
This experimental extension pairs the envoy.transport_sockets.istio_hbone upstream
transport with the envoy.upstreams.istio_hbone connection pool adapter on both the
application and HBONE clusters. The receiving internal listener
uses the standard TCP proxy filter. The pool adapter signals transport readiness when
TCP proxy’s tunneling pool accepts CONNECT, retaining its HTTP/2 pooling, flow control
and half-close handling. CONNECT streams continue to share outer HTTP/2 connections
according to the existing pool keys.
Configuration
Retain the internal listener bootstrap extension and the existing HBONE upstream
cluster. That cluster must use HTTP/2 and the appropriate upstream mutual TLS settings,
including peer identity validation and the h2 ALPN protocol. Configure the
application service cluster’s transport socket and pool adapter as follows:
transport_socket:
name: envoy.transport_sockets.istio_hbone
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.istio_hbone.v3alpha.UpstreamConfig
passthrough_metadata:
- name: envoy.filters.listener.original_dst
kind: {host: {}}
upstream_config:
name: envoy.upstreams.istio_hbone
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.istio_hbone.v3alpha.ConnectionPoolConfig
Configure the same upstream_config pool adapter on the HBONE cluster selected by
TCP proxy. The adapter on that cluster observes CONNECT acceptance and rejection;
the application cluster’s adapter handles the resulting application connection attempt.
For example, the connect_originate cluster used by the listener below includes
these settings, in addition to its existing endpoint discovery and mutual TLS configuration:
name: connect_originate
typed_extension_protocol_options:
envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
"@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
explicit_http_config:
http2_protocol_options: {}
upstream_config:
name: envoy.upstreams.istio_hbone
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.istio_hbone.v3alpha.ConnectionPoolConfig
Tunneling callers without the adapter transport’s readiness state retain the stock pool behavior, allowing the HBONE cluster to serve both kinds of callers.
Point the service cluster’s internal endpoints at connect_originate_hbone_adapter,
preserving endpoint identifiers and metadata. Keep the standard TCP proxy on that listener:
name: connect_originate_hbone_adapter
internal_listener: {}
filter_chains:
- filters:
- name: envoy.filters.network.tcp_proxy
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy
stat_prefix: connect_originate
cluster: connect_originate
upstream_connect_mode: IMMEDIATE
tunneling_config:
hostname: "%DOWNSTREAM_LOCAL_ADDRESS%"
Istio’s upstream peer-metadata filter recognizes connect_originate_hbone_adapter
and inner_connect_originate_hbone_adapter. It consumes their metadata preamble
before forwarding the application response.
Keep any existing original destination listener filter and address restoration needed
to produce the CONNECT authority. A fixed hostname: "app:8080" can be used when
testing one destination. CONNECT establishment must use upstream_connect_mode: IMMEDIATE
(the default). ON_DOWNSTREAM_DATA cannot work while the transport is holding application data.
The pool adapter rejects POST tunneling and the filter-state override that disables
tunneling before creating an upstream stream.
Retry behavior
On the application HTTP route, a minimal retry policy is:
retry_policy:
retry_on: connect-failure
num_retries: 1
retry_host_predicate:
- name: envoy.retry_host_predicates.previous_hosts
typed_config:
"@type": type.googleapis.com/envoy.extensions.retry.host.previous_hosts.v3.PreviousHostsPredicate
host_selection_retry_max_attempts: 3
The service cluster’s connect_timeout now includes CONNECT establishment. Set it
to accommodate the outer connection and destination connection attempt, while bounding
how long a router request waits. Normal request replay buffer limits and retry budgets
still apply. TCP proxy’s own connection attempts occur before the router sees a final
failure; selecting another application endpoint requires a router retry.
When CONNECT fails:
CONNECT 500–599 remains eligible for connection-failure retries, within the configured attempt and time budgets.
CONNECT 4xx, including 400, 401, 403 and 429, is permanent. An HTTP caller receives a local 403 for CONNECT 401 and the original status for other 4xx. The tunnel’s authorization denial does not challenge the application’s credentials. A raw TCP caller is closed without forwarding data.
Other rejected non-5xx statuses are permanent and produce a local 502 for HTTP callers. A CONNECT 200 that prematurely ends the stream is an establishment failure and retains the existing transient-failure behavior.
Permanent rejections bypass both the terminal TCP proxy’s retry path and the application router’s retry path, including explicit retriable-status-code policies. They do not report an outlier failure for either the selected service endpoint or the HBONE peer. Application-generated responses inside accepted CONNECT streams retain normal HTTP retry and outlier semantics.
Access logs identify a rejection with UF and
istio_hbone_connect_rejected:<status> in the response code details and upstream
transport failure reason. The selected service endpoint remains in upstream info.
For CONNECT 401, the application response is 403 with UF, while both diagnostic
fields retain istio_hbone_connect_rejected:401. Application-generated 401
responses inside accepted tunnels are unchanged.
Connection-attempt failure counters can still increase; this does not imply an
outlier health failure. The local response is not charged as an application response
in the service cluster’s upstream HTTP status counters.
The service cluster’s upstream_cx_connect_ms histogram measures time until the
application connection becomes ready, including HBONE CONNECT establishment.
Connection-latency dashboards can therefore show larger values after enabling
CONNECT wait.
Double HBONE
Gate application readiness at the inner CONNECT by pointing the application transport
at inner_connect_originate_hbone_adapter. Use TCP proxy on both origination
listeners and configure the pool adapter on both selected HBONE clusters. Pair the
outer_connect_originate_hbone_adapter listener with an adapter transport on the
inner_connect_originate HTTP/2 cluster. Set that transport’s transport_socket
field to the existing inner TLS transport, retaining all identity validation,
certificate, SNI and ALPN settings.
Inner TLS starts only after outer CONNECT acceptance. Its own handshake must still
complete before the inner HTTP/2 pool becomes ready.
Each internal socket pair owns separate readiness state; no request-specific state is added to the shared outer HTTP/2 pool key.
Failure boundaries
The transport blocks application reads and writes until acceptance. Readiness is
released on a later dispatcher iteration so a failure observed before that callback
cancels acceptance. This does not guarantee detection of a reset that arrives later.
After readiness is released, the normal established-connection behavior applies;
connect-failure does not authorize a retry after application data may have reached
the destination.
A graceful outer HTTP/2 GOAWAY stops new streams on that connection while accepted CONNECT streams can continue. It does not invalidate those streams or prevent an existing application connection from carrying another request. A CONNECT rejection before readiness follows the retry behavior above, including when caused by peer draining.
The scope is HBONE origination. This extension does not add termination, PROXY protocol, or application TLS wrapping of the service transport. Existing metadata filters and HBONE mutual TLS configuration remain necessary where applicable.