#61774·istio

ambient: waypoint's filter chain matcher missing IPv4 entry for autoallocated dual-stack ServiceEntry VIPs on IPv6-only (EKS) clusters

Author: acraigupgradeCreated Sep 17, 2026Updated Sep 17, 2026
Labelsarea/networkingarea/user experiencearea/ambientarea/dual-stack

Is this the right place to submit this?

  • This is not a security vulnerability or a crashing bug
  • This is not a question about how to use Istio

Bug Description

On IPV6-only EKS, where waypoint pods only ever have an IPv6 pod IP, a waypoint's Envoy config misses the IPv4 filter chain matcher entry for all Service Entries. Because it is default in Istio to auto-allocate dual-stack addresses to Service Entries on resolution: DNS these days, that means any client that resolves/connects via IPv4 to the VIP gets a connection reset error, every time.

To repro:

  1. IPv6-only EKS cluster, ambient mode, a ServiceEntry for an external host bound to a waypoint, using DNS-based resolution so the host gets auto-allocated dual-stack VIPs.
  2. Any client that resolves and connects via the IPv4 half of that VIP gets the connection dropped.
  3. curl -6 to the same host succeeds every time. curl -4 fails every time with filter_chain_not_found.

Evidence at the ztunnel level (client-side proxy log, connection to the waypoint over HBONE):

error   access  connection complete   ... dst.hbone_addr=240.240.0.49:443 dst.service="*.org" ... bytes_sent=473 bytes_recv=0 duration="46ms" error="send: destination disconnected before all data was written"

dst.hbone_addr here is the autoallocated IPv4 VIP — note the connection to the waypoint's real (IPv6) HBONE endpoint succeeds; only the embedded destination-metadata match fails.

Evidence at the waypoint's own Envoy config: the inbound listener's filter_chain_matcher only has an IPV6 address present, though the ServiceEntry has both ipv4 and ipv6 VIPs, and the client's chain has both too.

Root cause:

go
if (!features.EnableDualStack && !features.EnableAmbient) || node.GetIPMode() != Dual {
    addresses = netutil.FilterAddressesByIPFamily(addresses, node.SupportsIPv4(), node.SupportsIPv6())
}

The IP family is grabbed from the proxy's real pod IP, which is always IPV6 on IPV6 EKS. It would never be "dual". So this condition will always evaluate to true, and the IPv4 VIP will be discarded.

Proposed fix

go
// pilot/pkg/model/service.go, getAllAddressesForProxy
if (!features.EnableDualStack && !features.EnableAmbient) || (node.GetIPMode() != Dual && node.Type != Waypoint) {

The codebase already uses node.Type == Waypoint so we know it is valid. When it is a waypoint, always return both VIPs, even if it is on IPv6 EKS.

Version

Istio version: 1.30.2
Kubernetes version: 1.36.3

Additional Information

will submit PR with proposed fix.