istio: VirtualService rewrite to the root url - kubernetes

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

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

Conditional Istio EnvoyFilter based on Cookie presence

Currently we're using an EnvoyFilter to add an authentication check. This filter makes use of the envoy ext_authz filter.
We have a GraphQL endpoint that is used for both anonymus and authorised calls. Since the public calls don't need an auth check/filter I would like to be able to skip this filter based on a cookie. I tried searching for a solution online but wasn't able to find one.
See the configuration for the filter below:
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: oathkeeper
namespace: istio-system
spec:
workloadSelector:
labels:
istio: ingressgateway
configPatches:
- applyTo: HTTP_FILTER
match:
context: GATEWAY
listener:
filterChain:
filter:
name: "envoy.filters.network.http_connection_manager"
subFilter:
name: "envoy.filters.http.router"
patch:
operation: INSERT_BEFORE
value:
name: envoy.filters.http.ext_authz
typed_config:
'#type': type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz
failure_mode_allow: false
http_service:
path_prefix: /decisions
server_uri:
uri: http://oathkeeper-api.default.svc.cluster.local:4456
cluster: outbound|4456||oathkeeper-api.default.svc.cluster.local
timeout: 10s
authorization_request:
allowed_headers:
patterns:
- exact: accept
- exact: authorization
- exact: cookie
- exact: content-type
- exact: x-forwarded-for
- exact: x-forwarded-proto
- exact: x-forwarded-host
authorization_response:
allowed_upstream_headers:
patterns:
- exact: authorization
You could configure a second VirtualService route for the endpoint that matches on missing cookie
[...]
http:
- name: secured-graph-ql-endpoint
match:
- headers:
cookie:
regex: <some-regex>
uri:
prefix: /graph-ql-endpoint
route:
- destination:
host: graph-ql-endpoint
port:
number: 8000
- name: public-graph-ql-endpoint
match:
- uri:
prefix: /graph-ql-endpoint
route:
- destination:
host: graph-ql-endpoint
port:
number: 8000
with a regex (<some-regex>) depending on your cookie. You could also have a header like authenticated: true and match on that, instead of a (missing) cookie.
Create an EnvoyFilter to disable the ExtAuthz for that route.
apiVersion​: ​networking.istio.io/v1alpha3
kind​: ​EnvoyFilter
metadata​:
​ name​: bypass-ext-authz
​ namespace​: ​istio-system
spec​:
workloadSelector​:
​  labels​:
​    istio​: ​ingressgateway
​ configPatches​:
​  - ​applyTo​: ​HTTP_ROUTE
​    ​match​:
​      ​routeConfiguration​:
​        vhost​:
​          route​:
​           #​from virtual service http route name
​            name​: public-graph-ql-endpoint
​    ​patch​:
​      ​operation​: ​MERGE
​      ​value​:
         ​name​: ​custom.bypass_extauthz
​        ​typed_per_filter_config​:
​          ​envoy.ext_authz​:
​            ​"​#type​"​: ​type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute
​            ​disabled​: ​true
You could also add the configPatch to your existing EnvoyFilter.
Having said that:
From a design/security perspective I would rather have a different application that is publicly exposed and that queries the secured GraphQL endpoint for the anonymous user. That gives you much more control over traffic like rate limiting for external user, easier dos protection, etc.

Preflight (OPTIONS) returns 403, CORS

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.

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.