Skip to content

[Bug]: xDS paths disagree on same-vhost configs #2145

@mehara-rothila

Description

@mehara-rothila

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

  1. 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
  2. The deployment succeeds with 201 Created.

  3. 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
  4. Expected Result: The deployment is rejected with a 400 and the same clear error message the transform path produces, from both xDS paths consistently.

  5. 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

Metadata

Metadata

Labels

Area/GatewayAny issues related to API deployment in gateway, routing etc.Aspect/APIAPI definitions, contracts, OpenAPI, interfacesSeverity/Minor

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions