fix: respect user Host header override on HTTPProxy backends#159
Merged
Conversation
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.
scotwells
approved these changes
May 15, 2026
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" />
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The HTTPProxy controller unconditionally injected a
URLRewrite.Hostnamefilter alongside any user-suppliedrequestHeaderModifiersettingHost. Envoy applieshost_rewrite_literalafterrequest_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 returnsdirect_response 500from Envoy.This change teaches the controller to leave the user's override alone:
hasHostHeaderOverridehelper detects aRequestHeaderModifiersettingHost(case-insensitive per RFC 7230)tls.hostname) now skip injection when the rule or backend already specifies a Host overrideNo behaviour change for HTTPProxy resources without a Host override.
Validation
chat-8o30lhviadatumctl apply;curl https://chat.mdj-test.online/returned 500 before this fixcloud-portal#feat/http-proxy-host-header-ui, which writes the same documented shape from the UI