istio: Can't rewrite to empty string
Please see here for a workaround.
Describe the bug
I have a VirtualService
connected to a Gateway
to allow traffic into my cluster.
I want to remove /service-a
from the URL, so that http://site/service-a
hits /
on service-a
, http://site/service-a/metrics
hits /metrics
, etc.
Works, but not completely
This VirtualService
works for all cases except, of course, http://site/service-a
(without trailing slash)
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: service-a
spec:
hosts:
- "hostname.example.org"
gateways:
- hostname-gateway
http:
- match:
- uri:
prefix: "/service-a/"
rewrite:
uri: "/"
route:
- destination:
port:
number: 8080
host: service-a
Doesn’t work
http:
- match:
- uri:
prefix: "/service-a"
rewrite:
uri: ""
Passes to the envoy on the client and then returns a 404 for /service-a (a handler the service doesn’t have)
curl -D- http://hostname.example.org/service-a
HTTP/1.1 404 Not Found
x-powered-by: Express
content-security-policy: default-src 'self'
x-content-type-options: nosniff
content-type: text/html; charset=utf-8
content-length: 148
date: Mon, 20 Aug 2018 15:50:21 GMT
x-envoy-upstream-service-time: 1
server: envoy
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>Cannot GET /service-a</pre>
</body>
</html>
Tried ""
, ~
or ''
as the empty string. The empty string seems to be persisted:
$ kubectl get virtualservice/service-a -ojson
"http": [
{
"match": [
{
"uri": {
"prefix": "/service-a"
}
}
],
"rewrite": {
"uri": ""
},
Matching the prefix works if the replacement string is something
- match:
- uri:
prefix: "/service-a"
rewrite:
uri: "/"
Results in error Cannot GET //
- match:
- uri:
prefix: "/service-a"
rewrite:
uri: " "
Results in 400
http:
- match:
- uri:
prefix: "/service-a/"
rewrite:
uri: ""
Version
GitRevision: 6f9f420f0c7119ff4fa6a1966a6f6d89b1b4db84
User: root@48d5ddfd72da
Hub: docker.io/istio
GolangVersion: go1.10.1
BuildStatus: Clean
Client Version: version.Info{Major:"1", Minor:"11", GitVersion:"v1.11.0", GitCommit:"91e7b4fd31fcd3d5f436da26c980becec37ceefe", GitTreeState:"clean", BuildDate:"2018-06-27T22:29:25Z", GoVersion:"go1.10.3", Compiler:"gc", Platform:"darwin/amd64"}
Server Version: version.Info{Major:"1", Minor:"10+", GitVersion:"v1.10.5-gke.4", GitCommit:"6265b9797fc8680c8395abeab12c1e3bad14069a", GitTreeState:"clean", BuildDate:"2018-08-04T03:47:40Z", GoVersion:"go1.9.3b4", Compiler:"gc", Platform:"linux/amd64"}```
(No, I haven’t tested 1.0)
Is Istio Auth enabled or not? No
Environment GKE
About this issue
- Original URL
- State: open
- Created 6 years ago
- Reactions: 24
- Comments: 29 (10 by maintainers)
Adding another match uri accomplishes what you’re looking for, though a bit more verbose
I was having the same problem (double forward slash).
Got it working with this:
I’ve just replaced the uri parameter with a whitespace.
I tought it would throw me a configuration error but I guess it just strips of the whitespace when rewriting (I don’t know if this behavior is intended though).
Looks like this can solve your problem
hostname.example.org/service-a/xxxxxxx ======> hostname.example.org/xxxxxxx
Hope to help you!
Got it working
It feels like a bug that there’s no way to the empty string, so I would like it to stay open to track please.
Could we please just make it work the way we expect?
@mleneveut you aren’t doing it the way @buckhx described it
The matches are ordered. The first one to match is going to be executed. Thus you need to match the more specific prefix first.
Let’s say you call
/api/inspection-validation
, having the following match definedIt’s going to rewrite the path to
//inspection-validation
, the emphasis lies on the leading//
.That’s what’s causing the weird behaviour you encountered. Just change the order 😉
https://github.com/istio/istio/issues/8076#issuecomment-572394633
The above fix by @buckhx works nicely and I was using it for quite a while… Until I’ve found a weakness in it ! Say, you create another VirtualService (called ‘echotwo’) behind the same gateway. Now if you request:
example.com/echotwo
the gateway will route it to ‘echo’ not ‘echotwo’ VirtualService, because:prefix: "/echo"
matches everything:/echo
/echo/whattever
/echotwo
/echotwo/whatever
The fix is simple. Just replace:
prefix: "/echo"
with:exact: "/echo"
it will prevent overzealous match, and both VirtualServices will work correctly.So, the fixed example is:
I have something like it
the “/api” and “/api/” go to java-greeting-service “/”
This is a problem for us too. Empty space in a re-write goes to the API and route cannot be resolved. /token and /token/ rewrite do not work either.
We end up having two virtual services for every API:
External service should match on http://host/api-name/action and rewrite to http://api-name.cluster.svc.local/action. Since I can’t remove the /api-name/ prefix, I’m forced to have duplicate entries in internal and external virtual services. 30 services running within the mesh, each exposes 5-10 end-points and we have a lot of extra work on our hands. It would make a lot of sense to support replacement of URL prefixes.
Rewriting to " " seemed like a good idea, but doesn’t look like .net core trims empty spaces, so we end up with failed requests to the API. Given a number of discussions, it would be good to see this moved out of nebulous future milestone.
I have the same problem, and the solution of @buckhx does not work for me.
Istio 1.0.4 Kubernetes 1.11.3 in Azure (AKS)
(If I put the 2 prefix in the same match, the website does not respond. No specific logs in ingress or pilot)
The SPA is working, but any call to https://xxx.westeurope.cloudapp.azure.com/api/yyy get a 404. I can see in the ingress logs that it wants to redirect to the BFF, but does not seem to rewrite to / so that the BFF is called with /yyy instead of /api/yyy :
Any idea ?
Edit :
is working, but it’s too specific, I’d like to redirect /api/* to /*
@ClareChu solution works perfectly
Unfortunately, I don’t believe using
prefix: /example
and a single space works unless your request ends in a/
. That works great for requests to/example/
but not/example
. Setting the rewrite to/
does the opposite… it works for/example
but if you have anything after it (starting with another/
) you end up with the//
problem.The only way I see that actually solves this is the two-rule setup that @buckhx posted.
By having a rule that matches
/path/
followed by another rule for/path
, with both getting replaced with/
prevents the//
problem by making sure both get captured when they’re present.@craigbox I think we can close the issue if resolved.