Skip to content

gateway-api: 1.19.6 regression: same-port HTTPS and TLS passthrough listeners rejected on any SNI overlap, wildcard next to exact included #48092

Description

@lexfrei

Is your proposed feature related to a problem?

Since v1.19.6 / v1.20.0, an HTTPS/Terminate listener and a TLS/Passthrough listener on the same port are marked Conflicted=True/ProtocolConflict whenever their hostnames intersect (listenerPairConflict on main, samePortCrossProtocolConflictedListeners on v1.19). So *.example.com (HTTPS) next to api.example.com (TLS passthrough) on 443 gets both listeners Accepted=False, and on 1.20 both are dropped from Envoy (#47306, #47457).

This worked up to v1.19.5, so for the v1.19 branch it is also a regression: a config that 1.19.5 accepted and served stopped being accepted in the 1.19.6 patch release. #32292 is the same shape (*.test HTTPS + proxmox.test passthrough on 443), reproduced by a maintainer and accepted, and Envoy picks the exact server_names chain over the wildcard one. What actually broke was two listeners with the same hostname (two filter chains with the same match). The #44889 review asked to reject that same-hostname pair; the intersect predicate also caught the wildcard-superset case, and nothing tested it: the scenario matrix has same-port disjoint hostnames (works) and same-port same hostname (rejected), nothing in between. #47590 hit it on 1.20.0 and was closed after the reporter withdrew, so it was never discussed on its own.

Why I care (Cozystack, cozystack/cozystack#3912): one Gateway with one address per tenant; on 443 a wildcard *.<apex> HTTPS listener for apps plus passthrough listeners for api.<apex> (management kube-apiserver, passthrough so clients see the real cert), vm-exportproxy.<apex> and cdi-uploadproxy.<apex>. One address per tenant is a hard constraint (every Gateway wants 443, so LB-IPAM sharing is out), and api.<apex>:443 is in every kubeconfig. With the intersect rule we have to drop the wildcard and render one HTTPS listener per hostname under the 64-listener cap. Works, but a wildcard next to a more specific listener is exactly what the spec's hostname precedence rule is for.

Describe the feature you'd like

Conflict a same-port HTTPS/Terminate + TLS/Passthrough pair only when the normalized hostnames are equal (both catch-all included), the case Envoy can't disambiguate. For a strict wildcard superset (*.example.com vs api.example.com) apply the spec's "exact matches MUST be processed before wildcard matches" and accept both, as two HTTPS listeners with those hostnames on one port are accepted today. That keeps the #44889 same-hostname rejection and makes the cross-protocol branch match the same-protocol one.

The spec lets an implementation call HTTPS and TLS on one port incompatible, so against the spec this is a request, not a conformance bug. Against v1.19 it is a regression fix, so I'd also ask for a backport there. Cilium already mixes the two protocols on one port for disjoint hostnames, and Envoy expresses the precedence.

Notify relevant community channels

@cilium/sig-servicemesh

(Optional) Describe your proposed solution

In listenerPairConflict (operator/pkg/gateway-api/gateway_reconcile.go; listenersHaveSamePortCrossProtocolHostnameConflict on v1.19/v1.20): conflict when normalizedListenerHostname(first) == normalizedListenerHostname(second), otherwise not, same as the same-protocol branch below it. Translation already emits both filter chains on one listener and the matcher picks the exact server name first. Plus a test scenario for same port, wildcard HTTPS, exact passthrough, traffic to both names, and a re-check of tlsroute-mixed-protocol-listeners.

I can do the PR if you want it; I'd rather agree on the rule here first.

Activity

  1. changed the title [-]gateway-api: same-port HTTPS and TLS passthrough listeners are rejected on any SNI overlap, including a wildcard HTTPS listener next to an exact passthrough hostname[/-] [+]gateway-api: 1.19.6 regression: same-port HTTPS and TLS passthrough listeners rejected on any SNI overlap, wildcard next to exact included[/+] on Sep 19, 2026
  2. lexfrei commented on Sep 19, 2026

    @lexfrei
    ContributorAuthor

    The check that rejects this pair came in with #44889 (commit 51ebb84), backported in #46826, shipped in v1.19.6. It was not what that PR set out to do. @mhofstetter asked in review to reject "a HTTPS & TLS listener on the same port with the same hostname" as a follow-up (#44889 (comment)). @eufriction implemented it in the same PR with SNIHostnamesIntersect, which also catches a wildcard HTTPS listener next to an exact passthrough hostname. The test data added there covers same-hostname and disjoint pairs, nothing in between. Earlier in the same review mhofstetter wrote that merging "might work if only one of them is a wildcard/catch-all listener and the other one defines a specific hostname(s)" (#44889 (comment)). That is the case the rule now rejects.

    @youngnick, this is the layout you posted as accepted and working in #32292: *.test HTTPS plus proxmox.test passthrough on 443 (#32292 (comment)). Your "shouldn't really support this by the spec" in that thread (#32292 (comment)) was about TLSRoutes attaching to HTTPS listeners, which became #32371. For listeners distinct by hostname the spec says "Exact matches MUST be processed before wildcard matches", and Envoy's filter chain match orders server_names the same way, so this pair maps to exactly one listener.

    @asauber, you noted on the backport that the status says Conflicted while the CEC still contains the listener (#46826 (comment)). Still true on 1.19.8: on v1.19 the conflicted set is only used for status and the listeners reach ingestion, so 1.19 users get a wrong status and working traffic. On 1.20.1 and main, #47457 filters them before ingestion, and the same Gateway serves nothing.

    The rule I am proposing stays as in the description: conflict only when the normalized hostnames are equal, which is what the same-protocol branch already does. Is that acceptable? If yes, I open the PR with a test for the wildcard-next-to-exact case. Labels kind/regression and affects/v1.19 would fit, 1.19.5 accepted this config and 1.19.6 does not.

  3. youngnick commented on Sep 21, 2026

    @youngnick
    Contributor

    @lexfrei, both the initial description and your followup comment are very hard to read. The sentence structure is very unusual - making a case or asking for things in English generally works its way from last specific to most specific, where here you are starting in with full specificity immediately. This means that readers have to parse the entire paragraph (or more) in order to understand what you are asking for, which in a highly technical discussion like this makes your requests hard to understand.

    As a native English speaker who is extremely fluent in this subject matter, I still had to read the first paragraph after "Describe the feature you'd like" four or five times to get the gist of it. This makes it harder to understand your ask, and more likely it will take longer.

    As you can see from the discussion in upstream Gateway API (at kubernetes-sigs/gateway-api#4271), the exact behavior here is not settled yet, which is one of the reasons that we haven't moved forward with handling this.

    I agree, as I did there, that it's reasonable to support this kind of multiplexing at some point, but I'd like to see more agreement in upstream on the correct way to do it before we move too far here.

    I also agree that it's almost certain that the more-specific beats less-specific behavior is correct, but I've been wrong before.

    So, let's work more on getting some clarity in upstream about it, and then we can apply that here.

  4. lexfrei commented on Sep 21, 2026

    @lexfrei
    ContributorAuthor

    @youngnick Noted, and I'll rework how I write these. Ask first, details after.


    I'd like to split this issue in two, because one half does not wait on upstream.

    The design half I'll leave alone and follow upstream instead. Whether Cilium should serve this pair at all belongs in #4271.

    The other half is a bug on 1.19, and it does not depend on what upstream decides. The listeners get Conflicted=True and Accepted=False, and the same listeners are still programmed into Envoy, so traffic keeps flowing. Status and datapath disagree on the same version.

    This is what costs us the upgrade. Our controller gates Gateway readiness on listener conditions, so every tenant install and upgrade waits on a Ready=False that the datapath contradicts, hits the Helm timeout and rolls back.

    The previous patch release does not do this. samePortCrossProtocolConflictedListeners appears in 1.19.6 and is absent in 1.19.5.

    That half is already filed. #46917 reports it for versions from 1.19.5 up to 1.20.0, which is the branch we are on. It was closed when the 1.20 backport merged, and it carries affects/main rather than affects/v1.19, so the branch it describes still has the bug. Can it be reopened for 1.19, or should I ask for the backport somewhere else? I can do the PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    kind/cfpCilium Feature Proposalkind/featureThis introduces new functionality.

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions