Preflight (OPTIONS) returns 403, CORS - kubernetes

We are using Kubernetes with Istio and have configured a virtual service:
http:
- match:
- uri:
prefix: /api
rewrite:
uri: /api
route:
- destination:
host: svc-api
port:
number: 80
subset: stable
weight: 0
- destination:
host: svc-api
port:
number: 80
subset: vnext
weight: 100
corsPolicy: &apiCorsPolicy
allowOrigins:
- exact: '*'
allowMethods:
- GET
- POST
- OPTIONS
allowCredentials: true
allowHeaders:
- "*"
- match:
- uri:
prefix: /
rewrite:
uri: /
route:
- destination:
host: svc-api
port:
number: 80
subset: stable
weight: 0
- destination:
host: svc-api
port:
number: 80
subset: vnext
weight: 100
corsPolicy: *apiCorsPolicy
Making a request to https://[host]/api/* from a browser fails on OPTIONS request with 'from origin [request] has been blocked by CORS policy'.
Describing the service in k8 shows the correct configurations.
According to v 1.6.4 the structure using allowOrigins and exact instead of allowOrigin is correct.
What am I missing here?

Few things worth to mention here.
Recently in older istio versions there were a problem with cors and jwt combined together, take a look at below links:
Istio 1.5 cors not working - Response to preflight request doesn't pass access control check
https://github.com/istio/istio/issues/16171
There is another github issue about that, in this comment community member have the same issue, maybe it's worth to open a new github issue for that?
Additionally there is an answer from istio dev #howardjohn
Hi everyone. Testing CORS using curl can be a bit misleading. CORS is not enforced at the server side; it will not return a 4xx error for example. Instead, headers are returned back which are used by browsers to deny/accept. https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/cors.html?highlight=cors gives a good demo of this, and https://www.sohamkamani.com/blog/2016/12/21/web-security-cors/#:~:text=CORS%20isn't%20actually%20enforced,header%20in%20all%20its%20responses. is a good explanation.
So Istio's job here is simply to return these headers. I have added a test showing this works: #26231.
As I mentioned in comment worth to take a look at another community member configuration here, as he has a working options example, but have a 403 issue with POST.
Few things I would change in your virtual service
Use just corsPolicy instead of corsPolicy: &apiCorsPolicy
corsPolicy:
Instead of exact you can also use regex which may do the trick for wildcards.
allowOrigins:
- regex: '*'
About the / and /api paths, I think prefix is enough here, you don't need rewrite.

Related

Istio Virtual Service with Knative Service External Name

I feel like this should be a simple thing, to point an istio virtual service to a knative service, that gets stood up as an ExternalName type.
- match:
- authority:
prefix: demo.example.io
gateways:
- knative-serving/knative-ingress-gateway
- cert-manager/secure-ingress-gateway
uri:
prefix: /api
retries:
attempts: 5
perTryTimeout: 15s
retryOn: gateway-error,connect-failure,refused-stream
route:
- destination:
host: proxy.default.svc.local
port:
number: 80
This throws a 404. If I use a regular service it works fine. Or if I point to the first revision proxy-0001.default.svc... it works fine.

In a Virtual Service, the routing rules of second matching condition are over ridden by first

The following Virual Service consists of matching conditions for routing the Live DNS and Test DNS to two different versions of same service. Here, based on the second matching condition, the Test DNS must route to the Green subset, but instead it is routing to the Blue subset (as we have mentioned, the weight 100 for blue in first matching condition). That means the second matching condition's routing rules are getting overridden by the first matching condition's routing rules.
All the indentations are also same.
Just as a brief
So, now the routing should be
Live DNS--->Blue
Test DNS --->Green
But instead it is routing as
Live DNS--->Blue
Test DNS ---> Blue
How to solve this issue?
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: int-vs
namespace: stdy-ns
spec:
gateways:
- int-gateway
hosts:
- live.dns.com
- test.dns.com
http:
- match:
- headers:
host:
exact: live.dns.com
- uri:
prefix: /internal/platform/service
route:
- destination:
host: service
subset: blue
weight: 100
- destination:
host: service
subset: green
weight: 0
- match:
- headers:
host:
exact: test.dns.com
- uri:
prefix: /internal/platform/service
route:
- destination:
host: service
subset: green

istio: VirtualService rewrite to the root url

I have an Istio 1.4.6 VirtualService with a match and a url rewrite defined as follows:
match:
- authority:
prefix: example.com
uri:
prefix: /foo/bar
rewrite:
uri: /
route:
- destination:
host: some-service
port:
number: 80
I would like a rewrite like follows:
Traffic directed to /foo/bar or any subpath of that should be rewritten to / plus any subpath on some-service.
i.e.
example.com/foo/bar -> some-service
example.com/foo/bar/subpath -> some-service/subpath
example.com/foo/bar/subpath/anothersubpath -> some-service/subpath/anothersubpath
However, when I sysdig the traffic coming into some-service, I see that Istio has rewritten the path to:
GET //subpath/anothersubpath HTTP/1.1
Notice the two slashes in the GET request. In the VirtualService spec rewrite.uri field, I can't seem to leave that field empty or add an empty string there. Doing so causes the resource not to validate.
I.e. I can NOT do this:
rewrite:
uri: ""
And can NOT do this
rewrite:
uri:
How can I define a VirtualService rewrite to send traffic to the root of the destination service? Any help is much appreciated.
There is a github issue about this.
The simplest fix is to add whitespace in the uri as long as You are not running .net core application.
rewrite:
uri: " "
Other workaround can be found here,
Hope it helps.
another way of doing this is:
- match:
- uri:
prefix: "/v2/my-service/"
- uri:
exact: "/v2/my-service"
rewrite:
uri: "/"
route:
- destination:
host: my-internal-service
port:
number: 6666

I want to rewrite URI in VirtualService for from regex to regex

I want to run the following API. While I want to run the following script. But I am not able to get the expected output.
- match:
uri:
regex: \/test\/pune/\/(.+)\/bk
rewrite:
uri: \/pune/\/(.+)\/bk
route:
- destination:
host: yerwada
port:
number: 8080
But I am getting following output -
{"level":50,"time":1581684841254,"pid":18,"hostname":"test-ob-scheduled-payments-7cfb6779b8-x6f9b","err":{"type":"Error","message":"Parse
Error","stack":"Error: Parse
Error","bytesParsed":4,"code":"HPE_INVALID_URL","rawPacket":{"type":"Buffer","data":[71,69,84,32,92,47,99,100,115,45,97,117,92,47,118,49,92,47,98]}},"v":1}
HttpRewrite cannot use regex, it can only accept string values.

How to achieve logical OR in an Istio VirtualService regex?

The problem
The pipe character does not seem to work in Istio's VirtualService.
The example below is intended to route requests based on the user-agent header. Requests from a mobile device should go to myapp and requests from a desktop user should go to deskt-app, handled by next match block. The <REGEX> field works when I use this regex:
^.*\bMobile\b.*$
But the powers that be require a more sophisticated regex to identify mobile users. My routing breaks entirely when I use these:
^.*\b(iPhone|Pixel)\b.*$
^.*\b(iPhone|Pixel)+\b.*$
^.*\biPhone|Pixel\b.*$
Expected behavior
Using a regex with a pipe (logical OR) I expect to be routed to myapp when I have a user-agent header that contains the word "iPhone" or "Pixel".
Actual behavior
I get routed to deskt-app.
The question
How do I achieve a logical OR in an Istio VirtualService regex pattern? And is that my problem or am I overlooking something obvious?
Example VirtualService
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
...
...
http:
- match:
- headers:
user-agent:
regex: "<REGEX>" <------
uri:
prefix: /foo/bar
route:
- destination:
host: myapp
port:
number: 80
- match:
- uri:
prefix: /foo/bar
route:
- destination:
host: deskt-app
port:
number: 80
EDIT: Github Issue
Your configuration is correct, so the issue must be with the Regex, or the contents of the user-agent are different, give this a try '^.*(iPhone|Pixel).*$'
Just verified that the configuration below routes correctly when the header contains android or iphone:
- match:
- headers:
user-agent:
regex: '^.*(Android|iPhone).*$'
And tested with:
[match] curl -H "user-agent: Mozilla/5.0 (Linux; U; iPhone 4.4.2; en-us;)" ...
[no match] curl -H "user-agent: Mozilla/5.0 (Linux; U; Iphne 4.4.2; en-us;)" ...