Repository navigation
fix(gateway): pin identical allowedRoutes.kinds on port 443 listeners (cilium#45559) - #3084
Conversation
… (cilium#45559) Signed-off-by: shreyaabaranwal <[email protected]>
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request addresses a listener merging issue in Cilium where divergent Highlights
New Features🧠 You can now enable Memory (public preview) to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on Gemini (@gemini-code-assist) comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughWalkthroughTenantGateway now assigns the same ChangesTenantGateway port-443 route kinds
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related issues
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Code Review
This pull request addresses an issue (cilium#45559) where divergent allowedRoutes.kinds on the same port causes Cilium to collapse port-443 listeners and drop HTTPRoutes. To resolve this, both HTTPS-terminate and TLS-passthrough listeners on port 443 now share the same kinds set containing both HTTPRoute and TLSRoute. The corresponding unit tests have been updated, and a new regression test TestReconcile_Port443ListenersShareKinds has been added to ensure port-443 listeners share the same kinds. There are no review comments to assess, and the changes look correct and well-tested.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
internal/controller/tenantgateway/reconciler.go (1)
870-883: 🩺 Stability & Availability | 🟡 MinorTLS-passthrough listeners must advertise
TLSRoute, notHTTPRoute.The current configuration assigns
port443Kinds(HTTPRoute) to a listener withProtocol: TLSandMode: Passthrough. Per the Gateway API specification,HTTPRouteis incompatible with TLS-passthrough listeners. Cilium enforces this contract and will set the listener status condition toInvalidRouteKinds, preventing route attachment and marking the listener as not ready. The code comment claiming this behavior is "harmless" is incorrect.If the intent is TLS passthrough, update
AllowedRoutes.KindstoTLSRoute. If the intent is HTTP/HTTPS routing with termination, change theProtocoltoHTTPSand retainHTTPRoute.Relevant Diff
- passthroughAllowed.Kinds = port443Kinds // HTTPRoute - listeners = append(listeners, gatewayv1.Listener{ - Name: gatewayv1.SectionName("tls-" + svc), - Port: 443, - Protocol: gatewayv1.TLSProtocolType, - Hostname: &host, - TLS: &gatewayv1.ListenerTLSConfig{ - Mode: ptrTLSMode(gatewayv1.TLSModePassthrough), - }, - AllowedRoutes: &passthroughAllowed, - }) + passthroughAllowed.Kinds = []gatewayv1.RouteGroupKind{{Group: &v1.Group("gateway.networking.k8s.io"), Kind: gatewayv1.Kind("TLSRoute")}} + listeners = append(listeners, gatewayv1.Listener{ + Name: gatewayv1.SectionName("tls-" + svc), + Port: 443, + Protocol: gatewayv1.TLSProtocolType, + Hostname: &host, + TLS: &gatewayv1.ListenerTLSConfig{ + Mode: ptrTLSMode(gatewayv1.TLSModePassthrough), + }, + AllowedRoutes: &passthroughAllowed, + })🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@internal/controller/tenantgateway/reconciler.go` around lines 870 - 883, The TLS-passthrough listener setup in the tenant gateway reconciler is advertising the wrong route kind: the listener created for `TLSPassthroughServices` uses `Protocol: TLS` and `TLSModePassthrough` but still assigns `port443Kinds` to `AllowedRoutes.Kinds`. Update this block so the `Listener` built in the `TLSPassthroughServices` loop advertises `TLSRoute` when passthrough is intended, or switch the listener to `HTTPS` with `HTTPRoute` only if you mean terminated TLS routing. Keep the change aligned with the existing `allowedRoutes`, `port443Kinds`, and `gatewayv1.Listener` construction.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@internal/controller/tenantgateway/reconciler.go`:
- Around line 870-883: The TLS-passthrough listener setup in the tenant gateway
reconciler is advertising the wrong route kind: the listener created for
`TLSPassthroughServices` uses `Protocol: TLS` and `TLSModePassthrough` but still
assigns `port443Kinds` to `AllowedRoutes.Kinds`. Update this block so the
`Listener` built in the `TLSPassthroughServices` loop advertises `TLSRoute` when
passthrough is intended, or switch the listener to `HTTPS` with `HTTPRoute` only
if you mean terminated TLS routing. Keep the change aligned with the existing
`allowedRoutes`, `port443Kinds`, and `gatewayv1.Listener` construction.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 563cef8d-9314-425c-a4e0-17b970805a78
📒 Files selected for processing (2)
internal/controller/tenantgateway/reconciler.gointernal/controller/tenantgateway/reconciler_test.go
|
This should fix #3070. A quick note on the approach: the issue suggested just dropping the That said, this felt like a design call, so I'm totally open to switching to the simpler "omit kinds" version, or moving it to a design proposal first if you'd rather discuss it before merging. Let me know what you prefer! |
Aleksei Sviridkin (lexfrei)
left a comment
There was a problem hiding this comment.
NOT LGTM — the fix is correct and security-preserving (verified against the shipped Cilium 1.19.5 source), but the test suite is incomplete: it pins only positive/happy-path behavior in one cert mode and has no negative tests documenting what must not be rendered.
Business context: default TenantGateways on Cilium 1.19.x silently drop HTTPRoutes because divergent per-listener allowedRoutes.kinds on port 443 trigger cilium#45559 (issue #3070).
Blockers
B1: Tests are positive-only — missing negative tests and the bug's real cert mode
Treat the tests as the executable spec for this contract: they must document both how it should work and how it must not. Right now every assertion is happy-path ("the rendered listener carries {HTTPRoute, TLSRoute}"), and the one test that collects all port-443 listeners and asserts they're identical (TestReconcile_Port443ListenersShareKinds) runs in HTTP-01 only. Three things are unpinned:
- Negative — forbidden kinds (security boundary). No test asserts that
GRPCRoute/TCPRoute/UDPRoutenever appear on any port-443 listener. This is the whole reason the kinds set is restricted rather than dropped: those kinds aren't covered by thecozystack-route-hostname-policyVAP, so allowing them would let a route attach by hostname and bypass the apex check. Today this is only implied bylen(kinds)==2; it should be asserted by name so the contract is explicit. - Negative — no empty/default set. No test asserts that no port-443 listener has empty or
nilAllowedRoutes.Kinds. An empty set means the Gateway API default (all kinds for the protocol) applies — the same VAP-bypass hole. The "restricted, never default" property is the security invariant and isn't pinned. - Anti-collapse not covered in the bug's actual mode. The reported shape (#3070) is the DNS-01 / existingSecret root gateway: wildcard + apex + child-apex terminate listeners rendered together with TLS-passthrough on :443. The DNS-01 subtest of
TestReconcile_HTTPSListenersRestrictRouteKindsToHTTPRoutehas no passthrough services, andTestReconcile_ExistingSecretModeKeepsHTTPRedirectAndPassthroughrenders the mix but asserts only that the passthrough listener exists — not its kinds, not the cross-listener identity. So the fix could regress in exactly the mode the bug manifests in and the suite would stay green.
How to close it (guidance, not a prescription):
- Make the "collect every port-443 listener" assertion table-driven over all three cert modes (HTTP-01, DNS-01, existingSecret); each case seeds ≥1 terminate listener and
TLSPassthroughServices, and the DNS-01/existingSecret cases also seed an inheriting child namespace so the*.<child-apex>listener is included in the sweep. - In that sweep assert the full contract per listener: (a) kinds equal the canonical set
{HTTPRoute, TLSRoute}including the API group; (b) the set is identical across all :443 listeners; (c) it is non-empty; (d) it contains none ofGRPCRoute/TCPRoute/UDPRoute. - Add at least one explicitly negative case whose name and comment state the failure mode it guards (e.g. "forbidden route kinds never reach a :443 listener — they would bypass the route-hostname VAP" and "divergent kinds across :443 listeners — would re-trigger cilium#45559"). The test name should read as the requirement.
Non-blocking follow-ups
- The code comment ("listing HTTPRoute here is harmless") understates one effect: on Cilium 1.19.x every port-443 listener surfaces
ResolvedRefs=False / InvalidRouteKindson the raw Gateway. It's cosmetic (Accepted/Programmed, traffic, security, and TenantGateway readiness are all unaffected — readiness checks only Accepted+Programmed), but worth a one-line note so operators inspectingkubectl get gateway -o yamlaren't surprised. Removable once Cilium 1.20 (with #45693) ships. - Add
Closes #3070. - A gateway e2e run on a live 1.19.x cluster would turn the static proof that routing/passthrough still works into empirical confirmation.
… (cilium#45559) Signed-off-by: shreyaabaranwal <[email protected]>
|
Aleksei Sviridkin (@lexfrei) Addressed all three blockers:
Also added the one-line note about the cosmetic ResolvedRefs=False on Cilium 1.19.x near the passthrough loop. Re-requested your review — let me know if the contract coverage looks right now. |
Aleksei Sviridkin (lexfrei)
left a comment
There was a problem hiding this comment.
LGTM — the test-completeness blocker from the previous review is resolved.
The new assertPort443Contract sweep pins all three parts of the contract on every port-443 listener: (1) identical kinds across all listeners, (2) the forbidden kinds GRPCRoute/TCPRoute/UDPRoute never appear by name (with the route-hostname VAP-bypass rationale spelled out), and (3) the set is non-empty/non-nil. It runs table-driven across all three cert modes — HTTP-01, DNS-01, and existingSecret — each with a TLS-passthrough service so a terminate + passthrough mix is actually rendered on port 443. The DNS-01 and existingSecret cases seed an inheriting child namespace (namespace.cozystack.io/gateway + host labels) so collectInheritingChildApexes renders the per-child-apex listener and it is included in the sweep — covering the production root-gateway shape the bug manifests in, not just HTTP-01. I ran the package locally and all tests pass.
The reconciler.go comment now also documents the cosmetic ResolvedRefs=False/InvalidRouteKinds condition every port-443 listener surfaces on Cilium 1.19.x (Accepted/Programmed/traffic/TenantGateway-readiness all unaffected; removable once Cilium 1.20 ships), which addresses the earlier non-blocking note.
Approving.
f4a000e
into
cozystack:main
|
Thanks for the thorough reviews, Aleksei Sviridkin (@lexfrei) , the "tests as executable spec" framing was a great learning point for me. Happy to pick up the revert in #3087 once Cilium 1.20 lands. |
What this PR does
Cilium collapses all listeners that share a port when their
allowedRoutes.kindssets differ (cilium#45559). In the defaultTLSPassthroughServicesconfiguration both HTTPS-terminate listeners (kinds:[HTTPRoute]) and TLS-passthrough listeners (kinds:[TLSRoute]) land on port 443. The divergent kinds trigger the collapse, which then drops the HTTPRoutes that were accepted by the HTTPS listener.Fix (Option B — security intact): give every port-443 listener the same kinds set
[HTTPRoute, TLSRoute].port443Kindsslice inrenderGatewayand assigns it to bothhttpsAllowedRoutes.KindsandpassthroughAllowed.Kinds.cozystack-route-hostname-policy) continues to gate exactly the two expected route types. Gateway API itself rejects any HTTPRoute that references a PassthroughsectionNameat attach time, so the expanded kinds on passthrough listeners add no actual attach surface.TestReconcile_Port443ListenersShareKindsthat reconciles a TenantGateway with both an attached HTTPRoute and a TLS-passthrough service, then asserts every port-443 listener carries a non-empty, identical{HTTPRoute, TLSRoute}kinds set.TestReconcile_TLSPassthroughListenersRendered,TestReconcile_HTTPSListenersRestrictRouteKindsToHTTPRoute) that pinned the old single-kind behavior.Release note
Summary by CodeRabbit
Closes #3070