Repository navigation
Description
Is there an existing issue for this?
I searched existing issues. The closest ones I found are:
- Gateway: Combining listeners with HTTPS and TLS protocol #32292 – Combining HTTPS and TLS listeners
- TLSRoutes break when upgrading to 1.19.2 #45050 – TLSRoutes break after upgrade
- gateway-api: rejected ProtocolConflict listeners still serve traffic #46917 – Conflicted listeners are still translated into Envoy
- Graph-Driven Validation for Gateway API Reconciler #46681 – Graph-driven validation for the Gateway API reconciler
However, none appear to track this exact regression in Cilium v1.20.0 where an HTTPS wildcard listener and a more-specific TLS passthrough listener on the same port are rejected with ProtocolConflict.
What happened?
After upgrading to Cilium v1.20.0 and Gateway API CRDs v1.6.1, a previously working Gateway configuration stopped working.
The Gateway uses:
- An
HTTPSlistener with TLS termination for*.example.comon port443. - A more-specific
TLSpassthrough listener forargocd.example.comon the same port. - HTTPRoutes attached to the wildcard HTTPS listener.
- A TLSRoute attached explicitly to the passthrough listener using
sectionName.
Before the upgrade, Cilium routed traffic as expected:
argocd.example.commatched the exact TLS listener and was passed through to the Argo CD backend.- Other subdomains such as
web.example.commatched the wildcard HTTPS listener and were terminated at the Gateway.
After upgrading, Cilium marks both the wildcard HTTPS listener and the exact TLS passthrough listener as conflicted:
message: >-
Listener conflicts with listener "tls-argocd": same port 443 has
overlapping HTTPS and TLS passthrough hostnames.
reason: ProtocolConflict
status: "True"
type: ConflictedThe wildcard HTTPS listener then becomes:
reason: Invalid
status: "False"
type: AcceptedAs a result, all HTTPRoutes attached to the wildcard HTTPS listener stop working.
Removing the TLS passthrough listener immediately causes the wildcard HTTPS listener to become accepted/programmed again, and all HTTPRoutes start working.
The overall Gateway still reports:
conditions:
- reason: Accepted
status: "True"
type: Accepted
- reason: Programmed
status: "True"
type: ProgrammedThis is because the HTTP listeners and the non-overlapping apex HTTPS listener remain valid, while the wildcard HTTPS listener itself is rejected.
What did you expect to happen?
I expected the exact hostname listener to take precedence over the wildcard hostname listener:
argocd.example.com:443→ exactTLS/Passthroughlistener- Other
*.example.com:443hostnames → wildcardHTTPS/Terminatelistener example.com:443→ apexHTTPS/Terminatelistener
How can we reproduce the issue?
Prerequisites
The following are installed and enabled:
- Cilium
v1.20.0 - Gateway API CRDs
v1.6.1 - Cilium Gateway API controller
TLSRoutesupport- A valid TLS Secret named
example-wildcard-certingateway-system - The backend Services referenced by the Routes
1. Apply the GatewayClass, Gateway and Routes
apiVersion: gateway.networking.k8s.io/v1
kind: TLSRoute
metadata:
name: argocd-tls
namespace: argocd
spec:
hostnames:
- argocd.example.com
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: public-gateway
namespace: gateway-system
sectionName: tls-argocd
rules:
- backendRefs:
- group: ""
kind: Service
name: argocd-server
port: 443
weight: 1
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: web
namespace: web
spec:
hostnames:
- web.example.com
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: public-gateway
namespace: gateway-system
sectionName: https-wildcard
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- group: ""
kind: Service
name: web
port: 80
weight: 1
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: pla
namespace: openldap
spec:
hostnames:
- pla.example.com
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: public-gateway
namespace: gateway-system
sectionName: https-wildcard
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- group: ""
kind: Service
name: phpldapadmin
port: 8080
weight: 1
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: keycloak
namespace: keycloak
spec:
hostnames:
- keycloak.example.com
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: public-gateway
namespace: gateway-system
sectionName: https-wildcard
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- group: ""
kind: Service
name: keycloak
port: 8080
weight: 1
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: apex
namespace: web
spec:
hostnames:
- example.com
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: public-gateway
namespace: gateway-system
sectionName: https-apex
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- group: ""
kind: Service
name: web
port: 80
weight: 1
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: public-gateway
namespace: gateway-system
spec:
addresses:
- type: IPAddress
value: 162.xxx.xxx.xxx
gatewayClassName: cilium
listeners:
- name: http-wildcard
hostname: "*.example.com"
port: 80
protocol: HTTP
allowedRoutes:
namespaces:
from: All
- name: http-apex
hostname: example.com
port: 80
protocol: HTTP
allowedRoutes:
namespaces:
from: All
- name: https-wildcard
hostname: "*.example.com"
port: 443
protocol: HTTPS
allowedRoutes:
namespaces:
from: All
tls:
mode: Terminate
certificateRefs:
- group: ""
kind: Secret
name: example-wildcard-cert
- name: https-apex
hostname: example.com
port: 443
protocol: HTTPS
allowedRoutes:
namespaces:
from: All
tls:
mode: Terminate
certificateRefs:
- group: ""
kind: Secret
name: example-wildcard-cert
- name: tls-rhacs
hostname: rhacs.example.com
port: 443
protocol: TLS
allowedRoutes:
namespaces:
from: All
tls:
mode: Passthrough
- name: tls-argocd
hostname: argocd.example.com
port: 443
protocol: TLS
allowedRoutes:
namespaces:
from: All
tls:
mode: Passthrough
---
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: cilium
spec:
controllerName: io.cilium/gateway-controller
description: Cilium GatewayClass
parametersRef:
group: cilium.io
kind: CiliumGatewayClassConfig
name: cilium-lb-gateway-config
namespace: gateway-systemThe TLSRoute explicitly attaches to the tls-argocd listener using:
sectionName: tls-argocdEach HTTPRoute explicitly attaches to either https-wildcard or https-apex.
2. Check the Gateway status
kubectl -n gateway-system get gateway public-gateway \
-o jsonpath='{range .status.listeners[*]}{.name}{"\tattachedRoutes="}{.attachedRoutes}{"\t"}{range .conditions[*]}{.type}{"="}{.status}{"/"}{.reason}{" "}{end}{"\n"}{end}'Observed result:
http-wildcard attachedRoutes=0 ResolvedRefs=True/ResolvedRefs Accepted=True/Accepted Programmed=True/Programmed
http-apex attachedRoutes=0 ResolvedRefs=True/ResolvedRefs Accepted=True/Accepted Programmed=True/Programmed
https-wildcard attachedRoutes=3 Conflicted=True/ProtocolConflict Accepted=False/Invalid Programmed=False/Pending
https-apex attachedRoutes=1 ResolvedRefs=True/ResolvedRefs Accepted=True/Accepted Programmed=True/Programmed
tls-argocd attachedRoutes=1 Conflicted=True/ProtocolConflict Accepted=False/Invalid Programmed=False/Pending
The relevant observed status is:
status:
addresses:
- type: IPAddress
value: 162.xxx.xxx.xxx
conditions:
- message: Gateway successfully scheduled
reason: Accepted
status: "True"
type: Accepted
- message: Gateway Programmed
reason: Programmed
status: "True"
type: Programmed
listeners:
- name: https-wildcard
attachedRoutes: 3
supportedKinds:
- group: gateway.networking.k8s.io
kind: HTTPRoute
conditions:
- message: >-
Listener conflicts with listener "tls-argocd": same port 443 has
overlapping HTTPS and TLS passthrough hostnames.
reason: ProtocolConflict
status: "True"
type: Conflicted
- message: >-
Listener not valid. Listener conflicts with listener "tls-argocd":
same port 443 has overlapping HTTPS and TLS passthrough hostnames.
reason: Invalid
status: "False"
type: Accepted
- message: Address not ready yet
reason: Pending
status: "False"
type: Programmed
- name: https-apex
attachedRoutes: 1
supportedKinds:
- group: gateway.networking.k8s.io
kind: HTTPRoute
conditions:
- message: Resolved Refs
reason: ResolvedRefs
status: "True"
type: ResolvedRefs
- message: Listener Accepted
reason: Accepted
status: "True"
type: Accepted
- message: Listener Programmed
reason: Programmed
status: "True"
type: Programmed
- name: tls-argocd
attachedRoutes: 1
supportedKinds:
- group: gateway.networking.k8s.io
kind: TLSRoute
conditions:
- message: >-
Listener conflicts with listener "https-wildcard": same port 443
has overlapping HTTPS and TLS passthrough hostnames.
reason: ProtocolConflict
status: "True"
type: Conflicted
- message: >-
Listener not valid. Listener conflicts with listener
"https-wildcard": same port 443 has overlapping HTTPS and TLS
passthrough hostnames.
reason: Invalid
status: "False"
type: Accepted
- message: Address not ready yet
reason: Pending
status: "False"
type: ProgrammedThe overall Gateway is still reported as Accepted=True and Programmed=True, even though the https-wildcard listener serving three HTTPRoutes is rejected.
3. Test the routes
The three routes attached to https-wildcard fail:
curl -vk --resolve web.example.com:443:162.xxx.xxx.xxx \
https://web.example.com/
curl -vk --resolve pla.example.com:443:162.xxx.xxx.xxx \
https://pla.example.com/
curl -vk --resolve keycloak.example.com:443:162.xxx.xxx.xxx \
https://keycloak.example.com/The apex route is attached to the independent https-apex listener and continues working:
curl -vk --resolve example.com:443:162.xxx.xxx.xxx \
https://example.com/4. Remove the TLS passthrough listeners
Remove tls-argocd and tls-rhacs from the Gateway while leaving the HTTPS listeners unchanged:
kubectl -n gateway-system edit gateway public-gatewayRemove:
- name: tls-rhacs
hostname: rhacs.example.com
port: 443
protocol: TLS
tls:
mode: Passthrough
allowedRoutes:
namespaces:
from: All
- name: tls-argocd
hostname: argocd.example.com
port: 443
protocol: TLS
tls:
mode: Passthrough
allowedRoutes:
namespaces:
from: AllAfter reconciliation, check the status again:
kubectl -n gateway-system get gateway public-gateway \
-o jsonpath='{range .status.listeners[*]}{.name}{"\tattachedRoutes="}{.attachedRoutes}{"\t"}{range .conditions[*]}{.type}{"="}{.status}{"/"}{.reason}{" "}{end}{"\n"}{end}'The https-wildcard listener becomes:
https-wildcard attachedRoutes=3 ResolvedRefs=True/ResolvedRefs Accepted=True/Accepted Programmed=True/Programmed
All three wildcard HTTPRoutes immediately start working again.
5. Re-add only the Argo CD passthrough listener
Re-add:
- name: tls-argocd
hostname: argocd.example.com
port: 443
protocol: TLS
tls:
mode: Passthrough
allowedRoutes:
namespaces:
from: AllThe conflict immediately returns:
https-wildcard Conflicted=True/ProtocolConflict Accepted=False/Invalid Programmed=False/Pending
tls-argocd Conflicted=True/ProtocolConflict Accepted=False/Invalid Programmed=False/Pending
The three HTTPRoutes attached to https-wildcard become unavailable again.
This demonstrates that the failure is caused specifically by combining:
HTTPS/Terminate *.example.com:443
TLS/Passthrough argocd.example.com:443
The same design worked on 1.20.0-rc.1 before upgrading to Cilium v1.20.0 with Gateway API v1.6.1.
Cilium Version
1.20.0
Kernel Version
7.0.0-27-generic #27-Ubuntu SMP PREEMPT_DYNAMIC Thu Jun 18 19:13:49 UTC 2026 x86_64 GNU/Linux
Kubernetes Version
1.36.2
Regression
1.20.0-rc.1
Sysdump
No response
Relevant log output
Anything else?
root@kubernetes-master-1:~# cat cilium.yaml
certgen:
generateCA: true
ipam:
mode: "cluster-pool"
hubble:
enabled: true
relay:
enabled: true
ui:
enabled: true
frontend:
server:
ipv6:
enabled: false
metrics:
enabled:
- dns
- drop
- tcp
- flow
- port-distribution
- icmp
- http
- kafka
- l7-proxy
- l7-requests
enableOpenMetrics: true
l2announcements:
enabled: true
bpf:
masquerade: true
pmtuDiscovery:
enabled: true
egressGateway:
enabled: true
tunnelProtocol: geneve
gatewayAPI:
enabled: true
enableAppProtocol: true
enableAlpn: true
gatewayClass:
create: 'false'
prometheus:
metricsService: true
enabled: true
k8sClientRateLimit:
burst: 20
qps: 10
k8sServiceHost: "172.20.0.5"
k8sServicePort: "6443"
kubeProxyReplacement: trueCilium Users Document
- Are you a user of Cilium? Please add yourself to the Users doc
Code of Conduct
- I agree to follow this project's Code of Conduct
Activity
mkhazamipour commentedon Jul 29, 2026
After further testing, I no longer believe this is a regression.
I tested the same configuration with
v1.20.0-rc.1. The Gateway status already reported the overlapping HTTPS termination and TLS passthrough listeners as:However, the routes still worked because the rejected listeners were incorrectly translated into the Envoy configuration. This appears to be the behavior described in #46917 and subsequently fixed by #47306.
Therefore, the configuration only worked accidentally in previous versions despite already being considered invalid. The final
v1.20.0correctly enforces the listener status by excluding conflicted listeners from the Envoy configuration.For this use case, the correct alternatives appear to be:
HTTPRoute/GRPCRoutewithBackendTLSPolicywhen encrypted traffic to the backend is required.Based on this, I do not think the current
v1.20.0behavior is a bug.asauber commentedon Aug 3, 2026
As you mentioned, this issue was fixed with #47306 (and other cases were fixed by #47457).
Since you no longer thingk that the behavior is unexpected, I will close this issue.