Please select the area the issue is related to
Area/Gateway (Routing, API deployment in gateway etc.)
Please select the aspect the issue is related to
Aspect/API (API backends, definitions, contracts, interfaces, OpenAPI)
Description
When a RestApi configures both a main and a sandbox upstream and both vhosts resolve to the same value, the two xDS builders disagree about whether the configuration is valid. The RuntimeDeployConfig transform path rejects it with an explicit guard, but the Envoy xDS translator path has no equivalent check and deploys it. The deployment API returns 201 Created, while the transform failure is only logged and swallowed, so the main xDS gets routes for the API but the policy xDS gets no configuration at all. With the policy engine running fail-closed, every request to the API then returns 500.
Root Cause
The transform path guards against the collision in restapi.go:
// Guard: sandbox and main vhosts must differ, otherwise sandbox routes would
// overwrite main routes (same route key) and the sandbox patch would leave only
// a sandbox-cluster route with no main-cluster route at all.
if hasSandbox && effectiveMainVHost == effectiveSandboxVHost {
return nil, fmt.Errorf("sandbox upstream is configured but resolves to the same vhost %q as the main upstream; configure distinct vhosts to avoid route conflicts", effectiveMainVHost)
}
The Envoy xDS translator in translator.go has no equivalent guard: it builds the main routes and then appends sandbox routes for the same vhost, producing route entries with identical match criteria.
Because the transform failure does not fail the deployment, the request still returns 201, and the error only appears in the controller log:
level=ERROR msg="Failed to upsert runtime config from replica sync"
error="failed to transform config: sandbox upstream is configured but resolves to the same vhost \"collide.local\" as the main upstream; configure distinct vhosts to avoid route conflicts"
Impact
- An invalid configuration is accepted with
201 instead of being rejected at deploy time.
- The main xDS and policy xDS become inconsistent: Envoy has routes for the API, the policy engine has nothing.
- Every request to the API returns
500 at runtime (verified live), with no indication to the API author beyond a swallowed log line.
Steps to Reproduce
-
Deploy a RestApi whose main and sandbox vhosts are identical:
apiVersion: gateway.api-platform.wso2.com/v1alpha1
kind: RestApi
metadata:
name: same-vhost-demo-v1.0
spec:
displayName: Same-Vhost-Demo
version: v1.0
context: /same-vhost-demo/$version
vhosts:
main: collide.local
sandbox: collide.local
upstream:
main:
url: http://backend:8080/main-be
sandbox:
url: http://backend:8080/sb-be
operations:
- method: GET
path: /endpoint
-
The deployment succeeds with 201 Created.
-
Send a request through the router using the shared vhost:
curl -i -H "Host: collide.local" http://localhost:8080/same-vhost-demo/v1.0/endpoint
-
Expected Result: The deployment is rejected with a 400 and the same clear error message the transform path produces, from both xDS paths consistently.
-
Actual Result: The deployment returns 201, every request returns 500, and the transform-path rejection only appears as a swallowed error in the controller logs.
Severity Level of the Issue
Severity/Minor (Non-critical functionality. Can be fixed in future releases)
Environment Details (with versions)
- Operating System: Windows
- Go Version:
go1.26.2
- Git Version:
2.53.0.windows.1
- Docker Version:
29.1.4-rd, build 3c6914c
- Envoy Router Version:
v1.35.3 (envoyproxy/envoy:v1.35.3)
- Gateway-Controller Version:
0.0.1-SNAPSHOT
Please select the area the issue is related to
Area/Gateway (Routing, API deployment in gateway etc.)
Please select the aspect the issue is related to
Aspect/API (API backends, definitions, contracts, interfaces, OpenAPI)
Description
When a RestApi configures both a main and a sandbox upstream and both vhosts resolve to the same value, the two xDS builders disagree about whether the configuration is valid. The RuntimeDeployConfig transform path rejects it with an explicit guard, but the Envoy xDS translator path has no equivalent check and deploys it. The deployment API returns
201 Created, while the transform failure is only logged and swallowed, so the main xDS gets routes for the API but the policy xDS gets no configuration at all. With the policy engine running fail-closed, every request to the API then returns500.Root Cause
The transform path guards against the collision in restapi.go:
The Envoy xDS translator in translator.go has no equivalent guard: it builds the main routes and then appends sandbox routes for the same vhost, producing route entries with identical match criteria.
Because the transform failure does not fail the deployment, the request still returns
201, and the error only appears in the controller log:Impact
201instead of being rejected at deploy time.500at runtime (verified live), with no indication to the API author beyond a swallowed log line.Steps to Reproduce
Deploy a RestApi whose main and sandbox vhosts are identical:
The deployment succeeds with
201 Created.Send a request through the router using the shared vhost:
curl -i -H "Host: collide.local" http://localhost:8080/same-vhost-demo/v1.0/endpointExpected Result: The deployment is rejected with a
400and the same clear error message the transform path produces, from both xDS paths consistently.Actual Result: The deployment returns
201, every request returns500, and the transform-path rejection only appears as a swallowed error in the controller logs.Severity Level of the Issue
Severity/Minor (Non-critical functionality. Can be fixed in future releases)
Environment Details (with versions)
go1.26.22.53.0.windows.129.1.4-rd, build 3c6914cv1.35.3(envoyproxy/envoy:v1.35.3)0.0.1-SNAPSHOT