Repository: envoyproxy/gateway

Issue:
Remove shadow host suffix from the mirrored requests
The current [HTTPRoute Request Mirroring](https://gateway.envoyproxy.io/v1.5/tasks/traffic/http-request-mirroring/) automatically appends a “-shadow” to the mirror requests Host header. According to the [Envoy doc](https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route_components.proto#envoy-v3-api-msg-config-route-v3-routeaction-requestmirrorpolicy), this is used for logging.   

However, this can be surprising to users, as the Host header is modified without explicit notice.  It may also cause issues for application that depends on the original Host header.

I suggest removing the suffix by default. Since the mirror policy already uses a different cluster, this should be sufficient to distinguish the mirroring traffic from regular requests in the access log.

Discussion:
@shreealt: I would like to take this up.

Just to confirm if the direction is correct, I think this issue can be fixed by this way:

<img width="2242" height="648" alt="Image" src="https://github.com/user-attachments/assets/2d047e0b-d69a-4219-9187-c9ee94bd402a" />@jukie: Wouldn't it also be surprising to users who are already using this and expect `-shadow` to be included? Could this be made configurable and default to existing behavior?@zhaohuabing: @jukie  do you have use cases for the  `-shadow` suffix? We probably could add a global option to EG. I prefer to disable this by default, since it silently modifies the original Host header. 

cc @envoyproxy/gateway-maintainers 

I'll bring this to this week's community meeting.@arkodg: my vote is for making a breaking change - change default behavior to remove `-shadow` . The gateway-api spec doesnt mention anything about adding this suffix.
https://gateway-api.sigs.k8s.io/reference/spec/#httprequestmirrorfilter

some more use case context from the proxy world https://github.com/envoyproxy/envoy/issues/9094@guydc: +1 to breaking, fine with adding an opt-in option in the future using policies or a custom http route filter

Solution patch:
diff --git a/internal/xds/translator/route.go b/internal/xds/translator/route.go
index 07a0dbf27..6100369fd 100644
--- a/internal/xds/translator/route.go
+++ b/internal/xds/translator/route.go
@@ -543,6 +543,8 @@ func buildXdsRequestMirrorPolicies(mirrorPolicies []*ir.MirrorPolicy) []*routev3
 			xdsMirrorPolicies = append(xdsMirrorPolicies, &routev3.RouteAction_RequestMirrorPolicy{
 				Cluster:         policy.Destination.Name,
 				RuntimeFraction: mp,
+				// We don't need to append the shadow host suffix as the mirror policy already uses a different cluster which is enough to distinguish the mirrored traffic
+				DisableShadowHostSuffixAppend: true,
 			})
 		}
 	}
diff --git a/release-notes/current.yaml b/release-notes/current.yaml
index 327197841..f7bb606ca 100644
--- a/release-notes/current.yaml
+++ b/release-notes/current.yaml
@@ -5,6 +5,7 @@ breaking changes: |
   ALPNProtocols in EnvoyProxy Backend TLS setting use [h2, http/1.1] if not set.
   When a Backend resource specifies TLS settings and SNI is not specified or a BackendTLSPolicy is not attached to it, the value of upstream TLS SNI is determined by the HTTP Host header.
   When a Backend resource specifies TLS settings and SNI is not specified or a BackendTLSPolicy is not attached to it, the upstream certificate is validated for DNS SAN matching the SNI value sent.
+  When a MirrorPolicy is used, the shadow host suffix is not appended to the mirrored cluster name.
 
 # Updates addressing vulnerabilities, security flaws, or compliance requirements.
 security updates: |



Test patch:
diff --git a/internal/xds/translator/testdata/out/xds-ir/http-route-mirrors-percentage.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/http-route-mirrors-percentage.routes.yaml
index 9f74797a1..4c871392d 100644
--- a/internal/xds/translator/testdata/out/xds-ir/http-route-mirrors-percentage.routes.yaml
+++ b/internal/xds/translator/testdata/out/xds-ir/http-route-mirrors-percentage.routes.yaml
@@ -12,6 +12,7 @@
         cluster: route-dest
         requestMirrorPolicies:
         - cluster: mirror-route-dest
+          disableShadowHostSuffixAppend: true
           runtimeFraction:
             defaultValue:
               denominator: MILLION
diff --git a/internal/xds/translator/testdata/out/xds-ir/http-route-multiple-mirrors-percentage.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/http-route-multiple-mirrors-percentage.routes.yaml
index c84213bd2..16dc0c1f1 100644
--- a/internal/xds/translator/testdata/out/xds-ir/http-route-multiple-mirrors-percentage.routes.yaml
+++ b/internal/xds/translator/testdata/out/xds-ir/http-route-multiple-mirrors-percentage.routes.yaml
@@ -12,11 +12,13 @@
         cluster: route-dest
         requestMirrorPolicies:
         - cluster: mirror-route-dest
+          disableShadowHostSuffixAppend: true
           runtimeFraction:
             defaultValue:
               denominator: MILLION
               numerator: 250000
         - cluster: mirror-route-dest1
+          disableShadowHostSuffixAppend: true
           runtimeFraction:
             defaultValue:
               denominator: MILLION
diff --git a/internal/xds/translator/testdata/out/xds-ir/http-route-multiple-mirrors.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/http-route-multiple-mirrors.routes.yaml
index 37b12b36d..bbf3f9366 100644
--- a/internal/xds/translator/testdata/out/xds-ir/http-route-multiple-mirrors.routes.yaml
+++ b/internal/xds/translator/testdata/out/xds-ir/http-route-multiple-mirrors.routes.yaml
@@ -12,10 +12,12 @@
         cluster: route-dest
         requestMirrorPolicies:
         - cluster: mirror-route-dest
+          disableShadowHostSuffixAppend: true
           runtimeFraction:
             defaultValue:
               numerator: 100
         - cluster: mirror-route-dest1
+          disableShadowHostSuffixAppend: true
           runtimeFraction:
             defaultValue:
               numerator: 100