envoyproxy / envoyproxy/gateway
Health check Host header should use backend endpoint FQDN when auto-host-rewrite is configured
- Dominant language
- Go
- Stars
- 3k
- Forks
- 864
- Avg merge
- 2d 2h
- Merged PRs (30d)
- 140
Description
**What happened:**
When a Backend has multiple FQDN endpoints and the HTTPRoute uses `hostname.type: Backend` (auto-host-rewrite), active health checks still send the **route hostname** as the `Host` header instead of the **backend endpoint FQDN**. This causes health checks to fail for external backends that expect the correct `Host` header.
**Root cause:**
In `backendtrafficpolicy.go`, `SetHTTPHostIfAbsent(r.Hostname)` always sets the health check `HTTP.Host` to the route hostname. The xDS translator's `getHealthCheckOverridesHostname()` (added in #8452) supports per-endpoint hostname fallback, but only when `HTTP.Host` is empty — which it never is, because `SetHTTPHostIfAbsent` always fills it first.
So #8452 fixed the xDS translator to support per-endpoint health check hostnames, but the gatewayapi layer always pre-fills `HTTP.Host`, making the per-endpoint fallback dead code for HTTP health checks.
**Expected behavior:**
When `hostname.type: Backend` is configured on the route, health checks should use each endpoint's FQDN as the `Host` header. This mirrors how `auto_host_rewrite` works for request forwarding — the Host header is rewritten to the upstream hostname. The same should apply to health checks.
**Proposed fix:**
1. Add `UseEndpointHostname bool` to the IR `HealthCheck` struct — set to `true` when the route has `hostname.type: Backend` configured
2. Auto-derive `DestinationEndpoint.Hostname` from `FQDN.Hostname` when not explicitly set — so the endpoint always has a hostname available
3. In `buildHealthCheckConfig`, when `UseEndpointHostname` is true, set per-endpoint `HealthCheckConfig.Hostname` to the endpoint FQDN — this overrides the cluster-level Host in Envoy
`SetHTTPHostIfAbsent` still runs, so the cluster-level Host is set as a fallback and IR validation passes. The per-endpoint hostname simply overrides it in Envoy when the flag is set.
This is non-breaking: routes without `hostname.type: Backend` continue to use the route hostname for health checks (current behavior unchanged).
**Scenarios:**
| Config | Health check Host header |
|---|---|
| FQDN backend + `hostname.type: Backend` | Per-endpoint FQDN (NEW) |
| FQDN backend, no auto-host-rewrite | Route hostname (unchanged) |
| FQDN backend + explicit `http.hostname` | User's explicit value (unchanged) |
| Service backend (internal) | Route hostname (unchanged) |
**Related:**
- #7798 (original health check hostname issue, closed by #8452)
- #8452 (added per-endpoint hostname support in xDS, but bypassed by `SetHTTPHostIfAbsent`)
- [Comment by @Aditya7880900936](https://github.com/envoyproxy/gateway/issues/7798#issuecomment-3692815230) proposing the auto-fallback approach
/cc @arkodg @zirain
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.