OPTIONS Preflight request gets declined with 404

I’m trying to understand how other folks are solving this issue or best-practices.

In our dev environment, we host multiple instances of the same service within a single K8s cluster to cater to multiple environments (dev1, dev2, dev3 etc), separated by namespaces.

In the example below we have deployed expense.dev2.svc.cluster.local into namespace dev2. All of this is exposed via single Load-balancer.

Inorder to achieve this., the caller need to pass-in additional header property (configured in Istio’s VirtualService) that helps route the request to appropriate namespace.

  http:
  - corsPolicy:
      allowCredentials: true
      allowHeaders:
      - '*'
      allowMethods:
      - GET
      - HEAD
      - POST
      - PUT
      - DELETE
      - TRACE
      - OPTIONS
      - CONNECT
      - PATCH
      allowOrigin:
      - '*'
    match:
    - headers:
        env:
          exact: dev2
      uri:
        prefix: /employee/
    route:
    - destination:
        host: expense.dev2.svc.cluster.local
        port:
          number: 8080

All this worked well (from Postman, cURL etc) until we got the UI wired-up to invoke the back-end.

With the UI, the browser now make the CORS OPTIONS preflight request as documented here-

Since the browser (not the application) making the OPTIONS request (to which we don’t have any control off), it does not pass-in the additional header property env=dev2. This ends-up with 404.

Adding additional header property is not a new thing. I would like to understand how others are solving similar issue where-in there is a need to pass additional header properties.

Appreciate any insights on this. Thanks !

Essentially here is the example from reference doc -

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ratings-route
spec:
  hosts:
  - ratings.prod.svc.cluster.local
  http:
  - match:
    - headers:
        end-user:
          exact: jason
      uri:
        prefix: "/ratings/v2/"
      ignoreUriCase: true
    route:
    - destination:
        host: ratings.prod.svc.cluster.local

How would CORS preflight request (OPTIONS) which just wouldn’t have end-user=jason in the request header pass through this filter ?

I tried routing based on the HTTP method; but this didn’t help !

  http:
  - match:
    - headers:
        env:
          exact: dev2
      uri:
        prefix: /employee/
    route:
    - destination:
        host: expense.dev2.svc.cluster.local
        port:
          number: 8080
  - match:
    - method:
        exact: OPTIONS
      uri:
        prefix: /employee/
    route:
    - destination:
        host: expense.dev2.svc.cluster.local
        port:
          number: 8080

It works for request method - GET, but not for OPTIONS

Does anyone know whats specific about OPTIONS ?

@howardjohn - Appreciate if you can help take a look at this