Venkat-C-J opened a new issue, #2822:
URL: https://github.com/apache/apisix-ingress-controller/issues/2822

   ### Current Behavior
   
   Starting in v2.1.0 (commit `0d225ad`, PR #2743), the route translator no 
longer sets `route.Hosts`
   when building the APISIX route object for ADC sync.
   
   File: `internal/adc/translator/apisixroute.go`, function `buildRoute`
   
   The PR description states the line was removed intentionally:
   
   > "Hosts were being set redundantly at both the route level and the service 
level. Since the
   > service level is the canonical location, the route-level assignment was 
removed to prevent
   > spurious diff-detected events during ADC sync."
   
   This assumes APISIX inherits `service.hosts` for route matching. It does not 
— APISIX's
   radix-tree route matcher only reads the **route's own** `hosts` field. 
`service.hosts` has no
   effect on request routing/matching at all.
   
   As a result, every `ApisixRoute` CRD that specifies 
`spec.http[].match.hosts` in its source YAML
   gets translated into an APISIX route object with **no `hosts` field**, even 
though the CRD itself
   is correct. This makes every route match on **path + priority only**, 
regardless of the incoming
   `Host` header.
   
   **Impact:** In any multi-tenant setup where two different `ApisixRoute` 
resources (for two
   different hosts) happen to define overlapping/generic path patterns (e.g. 
`/`, `/user`, or a
   regex like `/(.*)/callback.*`), the route with the **higher `priority`** now 
wins for *all* hosts,
   not just the host it was intended for. Requests for Host B get silently 
routed to the backend
   configured for Host A, typically producing a 404 (or worse, being served 
with the wrong tenant's
   plugins/backend) instead of matching Host B's own route.
   
   ### Expected Behavior
   
   `buildRoute` should preserve the route-level hosts from the CRD:
   
   ```go
   route.Hosts = rule.Match.Hosts
   ```
   
   A route created from an `ApisixRoute` with `match.hosts: 
[tenant-a.example.com]` should only ever
   match requests carrying that `Host` header, irrespective of any other 
route's priority or the
   `hosts` set on the referenced `ApisixService`.
   
   
   ## Suggested Fix
   
   Restore the deleted line in `internal/adc/translator/apisixroute.go`, 
function `buildRoute`:
   
   ```go
   // APISIX route matching uses route.Hosts, NOT service.Hosts.
   // Removing this causes all routes to become host-agnostic.
   route.Hosts = rule.Match.Hosts
   ```
   
   If the original "spurious diff detected" issue (duplicate hosts assignment 
between route and
   service level) still needs solving, it should be solved by 
normalizing/deduplicating the diff
   comparison logic, not by dropping the route-level `hosts` field — since 
`service.hosts` has no
   bearing on actual request routing.
   
   ### Error Logs
   
   **1. Source `ApisixRoute` CRD (sanitized) — hosts are correctly specified:**
   
   ```yaml
   apiVersion: apisix.apache.org/v2
   kind: ApisixRoute
   metadata:
     name: service-b-routes
   spec:
     ingressClassName: apisix
     http:
       - name: service-b-user-route
         priority: 5
         match:
           hosts:
             - tenant-b.example.com
           paths:
             - /*
           exprs:
             - subject:
                 scope: Path
                 name: user-path
               op: RegexMatch
               value: '/user$'
         backends:
           - serviceName: service-b-backend
             servicePort: 8080
   ```
   
   **2. Resulting route object dumped from the APISIX Admin API (sanitized) — 
`hosts` is missing:**
   
   ```json
   {
     "key": "/apisix/routes/aaaa1111",
     "value": {
       "id": "aaaa1111",
       "name": "service-b_service-b-routes_service-b-user-route",
       "uris": ["/*"],
       "priority": 5,
       "service_id": "bbbb2222",
       "vars": [["uri", "~~", "/user$"]]
     }
   }
   ```
   
   Note: no `hosts` key at all, despite the source CRD above defining
   `match.hosts: [tenant-b.example.com]`.
   
   **3. Competing higher-priority route from a different tenant (sanitized), 
also missing `hosts`:**
   
   ```json
   {
     "key": "/apisix/routes/cccc3333",
     "value": {
       "id": "cccc3333",
       "name": "service-a_service-a-routes_service-a-user-route",
       "uris": ["/*"],
       "priority": 20,
       "service_id": "dddd4444",
       "vars": [["uri", "~~", "/user$|/user/$"]]
     }
   }
   ```
   
   **4. Observed test failure (sanitized E2E result):**
   
   ```
   Testcase: "user path via https"
   Request:  GET https://tenant-b.example.com/user
   Expected: 200 (service-b-backend response)
   Actual:   404 (request was routed to service-a-backend, which has no 
knowledge of tenant-b.example.com)
   ```
   
   Because both routes above lack a `hosts` field after translation, APISIX 
picks the route with the
   higher numeric `priority` (20, tenant-a's route) for **any** Host header 
hitting path `/user`,
   including requests for `tenant-b.example.com` that should have matched the 
priority-5 route
   instead.
   
   ### Steps to Reproduce
   
   1. Install APISIX Ingress controller v2.1.0 with the Helm chart, pointing at 
an APISIX data plane
      with two upstream services, `service-a-backend` and `service-b-backend`.
   2. Create two `ApisixRoute` resources:
      - `service-a-routes`: `match.hosts: [tenant-a.example.com]`, path `/*` 
with a regex `vars`
        condition matching `/user$`, `priority: 20`, backend 
`service-a-backend`.
      - `service-b-routes`: `match.hosts: [tenant-b.example.com]`, path `/*` 
with a regex `vars`
        condition matching `/user$`, `priority: 5`, backend `service-b-backend`.
   3. Wait for the ingress controller to sync both routes to APISIX via ADC.
   4. Dump the routes from the Admin API: `curl 
http://<apisix-admin>/apisix/admin/routes` — observe
      neither route object contains a `hosts` field, even though both source 
CRDs specify one.
   5. Send a request with `Host: tenant-b.example.com` and path `/user`.
   6. **Expected:** response comes from `service-b-backend` (matched by 
`service-b-routes`,
      priority 5, host `tenant-b.example.com`).
   7. **Actual:** response comes from `service-a-backend` (`service-a-routes`, 
priority 20) because
      route selection is now host-agnostic and priority alone decides — 
`service-a-backend` has no
      knowledge of `tenant-b.example.com` and returns 404 (or an unrelated 
response).
   
   ### Environment
   
   - APISIX Ingress controller version: `2.1.0` (regression introduced in PR 
#2743, commit `0d225ad`;
     confirmed working correctly on `2.0.1`)
   - ADC version: `v0.26.x`
   - APISIX data plane version: `3.16.x` (also reproduced on `3.15.x` — data 
plane version is not the
     cause; confirmed via changelog review that no route-matching semantics 
changed between these
     versions)
   - Kubernetes cluster version: `1.29.x` (generic — issue is not 
Kubernetes-version-specific)
   - OS: Linux (containerized); also reproduced with a local Docker Desktop / 
kind cluster on macOS
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to