Skip to content

fix: respect user Host header override on HTTPProxy backends#159

Merged
mattdjenkinson merged 7 commits into
mainfrom
fix/httpproxy-host-header-override
May 15, 2026
Merged

fix: respect user Host header override on HTTPProxy backends#159
mattdjenkinson merged 7 commits into
mainfrom
fix/httpproxy-host-header-override

Conversation

@mattdjenkinson
Copy link
Copy Markdown
Contributor

@mattdjenkinson mattdjenkinson commented May 13, 2026

Summary

The HTTPProxy controller unconditionally injected a URLRewrite.Hostname filter alongside any user-supplied requestHeaderModifier setting Host. Envoy applies host_rewrite_literal after request_headers_to_add, so the implicit rewrite always overwrote the user's value — making the shape documented in the engineering wiki Set-Host-Header-With-datumctl effectively dead. Applying the wiki recipe verbatim against staging today returns direct_response 500 from Envoy.

This change teaches the controller to leave the user's override alone:

  • New hasHostHeaderOverride helper detects a RequestHeaderModifier setting Host (case-insensitive per RFC 7230)
  • Both URLRewrite injection branches (FQDN backends, HTTPS-IP backends with tls.hostname) now skip injection when the rule or backend already specifies a Host override
  • TLS validation for HTTPS-IP backends is unaffected — SNI/SAN matching happens via cluster TLS config, not URLRewrite

No behaviour change for HTTPProxy resources without a Host override.

Screenshot 2026-05-13 at 20 41 17

Validation

  • Unit tests cover FQDN rule-level, FQDN backend-level, HTTPS-IP rule-level, and case-insensitive header name matching — all pass alongside the existing URLRewrite cases
  • Repro: applied the wiki YAML to staging proxy chat-8o30lh via datumctl apply; curl https://chat.mdj-test.online/ returned 500 before this fix
  • Unblocks cloud-portal#feat/http-proxy-host-header-ui, which writes the same documented shape from the UI

The HTTPProxy controller unconditionally injected a URLRewrite.Hostname
filter for FQDN backends (and HTTPS-IP backends with tls.hostname),
clobbering any user-supplied Host override via requestHeaderModifier.
Envoy applies host_rewrite_literal after request_headers_to_add, so
the implicit rewrite always won regardless of filter ordering or
whether the user wrote the override at rule or backend level.

This matches the shape documented in the engineering wiki
(Set-Host-Header-With-datumctl) — the controller now leaves user
overrides intact.

Key changes:
- Add hasHostHeaderOverride helper that detects a RequestHeaderModifier
  setting Host (case-insensitive per RFC 7230)
- Skip URLRewrite injection in both FQDN and HTTPS-IP branches when the
  rule or backend already specifies a Host override
- Cover FQDN rule-level, FQDN backend-level, HTTPS-IP rule-level, and
  case-insensitive header name matching with unit tests

No behaviour change for HTTPProxy resources without a Host override.
…ite absent

When the user supplies a Host header override via requestHeaderModifier
on an HTTPProxy, the previous commit teaches the httpproxy controller
to suppress the implicit URLRewrite hostname injection so the override
is honoured at egress. That broke downstream HTTPRoute creation for
HTTPS backends because the gateway controller relied on the same
URLRewrite filter to source the BackendTLSPolicy hostname for cert
validation.

Fall back to the upstream EndpointSlice's FQDN address (which the
httpproxy controller already sets to the backend hostname) when no
URLRewrite filter is present. This is the same hostname that would
have been used by the implicit URLRewrite injection, so cert
validation behaviour is unchanged.
…e via EndpointSlice

Envoy Gateway rejects RequestHeaderModifier filters that touch the Host
header (status condition: "RequestHeaderModifier Filter did not provide
valid configuration to add/set/remove any headers"). The previous
revisions of this fix wrote the user override as a RequestHeaderModifier
filter and skipped URLRewrite injection — EG dropped the route as
unaccepted and the gateway never attached it, returning 404.

Translate the user-facing RequestHeaderModifier{Host: X} shape (which
datumctl and the cloud portal write) into the URLRewrite.Hostname value
Envoy actually honours at egress, and strip the now-redundant Host
entry from the RequestHeaderModifier so EG doesn't see the conflict.

URLRewrite.Hostname previously doubled as the BackendTLSPolicy SAN
hostname for cert validation, which broke once URLRewrite started
carrying user overrides instead of the real backend FQDN. Surface the
cert hostname via a new BackendCertHostnameAnnotation on the upstream
EndpointSlice; the gateway controller prefers it over URLRewrite when
building the BackendTLSPolicy, falling back to URLRewrite for
EndpointSlices that predate the annotation.

Unit tests updated and extended (FQDN rule-level, backend-level,
case-insensitive Host match, HTTPS-IP) — all assertions verify that
URLRewrite carries the user's value, RequestHeaderModifier{Host} is
stripped, and the cert hostname annotation captures the real backend
SAN.
… CreateOrUpdate

The CreateOrUpdate closure only synced AddressType/Endpoints/Ports, so
the BackendCertHostnameAnnotation added in the previous commit never
made it onto existing EndpointSlices. Without the annotation the gateway
controller falls back to URLRewrite.Hostname — which now carries the
user's Host override instead of the real backend FQDN — and the
BackendTLSPolicy validates against the wrong SAN, causing upstream 503s
because the backend cert doesn't match.
@mattdjenkinson mattdjenkinson merged commit 0c9baa1 into main May 15, 2026
11 checks passed
@mattdjenkinson mattdjenkinson deleted the fix/httpproxy-host-header-override branch May 15, 2026 14:00
mattdjenkinson added a commit to datum-cloud/cloud-portal that referenced this pull request May 18, 2026
Added the option to add a custom host header to an AI Edge. Also cleaned
up some AI UI bits.

NSO change:
datum-cloud/network-services-operator#159

Ref: datum-cloud/enhancements#569

<img width="1272" height="577" alt="Screenshot 2026-05-13 at 20 41 17"
src="https://github.com/user-attachments/assets/720dd4eb-b535-49ed-8856-474e7f7b3c80"
/>
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.

2 participants