Skip to content

BUG/MEDIUM: ingress: keep https frontend for REQ_DENY/REQ_CAPTURE when SSLPassthrough is cluster-wide - #830

Closed
KlausNie wants to merge 2 commits into
haproxytech:masterfrom
KlausNie:fix/req-deny-https-frontend-dropped-global-passthrough
Closed

KlausNie wants to merge 2 commits into
haproxytech:masterfrom
KlausNie:fix/req-deny-https-frontend-dropped-global-passthrough

Conversation

@KlausNie

Copy link
Copy Markdown
Contributor

Summary

haproxy.SSLPassthrough is a controller-wide flag: it becomes true as soon as any single ingress in the cluster uses ssl-passthrough, not just the ingress currently being processed. addRules() used that flag to decide where an ingress's allow-list/deny-list (REQ_DENY) or capture (REQ_CAPTURE) rule gets attached, swapping FrontHTTPS for FrontSSL whenever the flag was true — for every ingress, including ones that never opted into ssl-passthrough themselves.

But a non-passthrough ingress's TLS traffic still terminates on FrontHTTPS: HTTPS.toggleSSLPassthrough replaces FrontHTTPS's public binds with an internal PROXY-protocol socket once SSLPassthrough is active, and FrontSSL's default backend (ssl-backend) forwards non-passthrough SNIs there. Dropping FrontHTTPS from the rule's frontends left that traffic completely unchecked by its own allow-list/deny-list — independent of, and in addition to, the intermittent frontend-selection bug fixed in #770 / 79d754a. That earlier fix made frontend selection stable; it didn't change that the selection itself drops FrontHTTPS whenever any ingress anywhere uses passthrough.

Observed live: an ingress with haproxy.org/allow-list sharing a cluster with an unrelated ssl-passthrough ingress let non-allow-listed source IPs reach the backend over HTTPS (TCP and QUIC/HTTP3) with no enforcement at all, while the same allow-list correctly blocked plain HTTP.

Fix

Keep FrontHTTPS in the frontend list alongside FrontHTTP and FrontSSL so both traffic paths — genuine SNI-routed passthrough and internally-forwarded TLS termination — get the rule. Confirmed this is provably safe for the mixed-cluster case: a non-passthrough ingress's host is never written into the SNI map, so the extra FrontSSL placement it already had is inert there; the missing piece was purely FrontHTTPS.

Test plan

  • go build ./... and go vet pass
  • Added deploy/tests/e2e/https/allowlist_passthrough_test.go: deploys an unrelated ssl-passthrough sidecar ingress alongside a plain allow-list ingress and asserts the latter's HTTPS traffic is still denied for a non-allow-listed client
  • go build -tags e2e_https ./deploy/tests/e2e/... passes
  • Not run against a live cluster (no local e2e environment) — would appreciate a maintainer running the e2e suite

KlausNie added 2 commits July 12, 2026 15:18
…n SSLPassthrough is cluster-wide

haproxy.SSLPassthrough is a controller-wide flag: it becomes true as soon
as any single ingress in the cluster uses ssl-passthrough, not just the
ingress currently being processed. addRules() used that flag to decide
where an ingress's allow-list/deny-list (REQ_DENY) or capture
(REQ_CAPTURE) rule gets attached, swapping FrontHTTPS for FrontSSL
whenever the flag was true - for every ingress, including ones that never
opted into ssl-passthrough themselves.

But a non-passthrough ingress's TLS traffic still terminates on
FrontHTTPS: HTTPS.toggleSSLPassthrough replaces FrontHTTPS's public binds
with an internal PROXY-protocol socket once SSLPassthrough is active, and
FrontSSL's default backend (ssl-backend) forwards non-passthrough SNIs
there. Dropping FrontHTTPS from the rule's frontends left that traffic
completely unchecked by its own allow-list/deny-list, independent of
whatever intermittent frontend-selection bug affected REQ_DENY placement
before it (see haproxytech#770 / the fix in 79d754a).

Keep FrontHTTPS in the frontend list alongside FrontHTTP and FrontSSL so
both traffic paths - genuine SNI-routed passthrough and internally
forwarded TLS termination - get the rule.

Adds an e2e test (allowlist_passthrough_test.go) reproducing the bug: an
unrelated ssl-passthrough ingress coexisting with a plain allow-list
ingress, asserting the latter's HTTPS traffic is still denied.
- Fix new test file's copyright year (2019 -> 2026, matches the
  project's year-of-addition convention elsewhere in the repo).
- Match sibling test naming/doc-comment style in the https e2e package
  (Test_HTTPS_Redirect/Offload/Passthrough are terse; the new suite's
  wrapper comment and test method name were verbose outliers).
- Remove the sidecar ingress's deferred Delete() cleanup call: Test.Delete
  has no way to target the test's dynamic namespace (unlike Apply), so it
  was silently no-op'ing against the wrong namespace on every run.
  Documented the reliance on TearDownSuite's whole-namespace teardown
  instead of pretending per-test cleanup works.
- Drop the trailing period on the new inline comment in addRules() to
  match its immediate neighbor's style.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant