0

We are migrating from ingress-nginx to istio. While migrating existing ingress definitions to istio VirtualServices, we came across nginx style rewriting and wanted to achieve the same in istio. When researched it was found that istio doesn't support backtrack replacement. There is an open bug regarding the same in istio. People suggest to handle this via enjoy filters. Since I'm new to istio I've tried creating an Envoy filter but still, the URL returns 404.

Here is the sample ingress-nginx definition that we want to convert

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/rewrite-target: /$2
    nginx.ingress.kubernetes.io/configuration-snippet: |
      rewrite ^(/sample)$ $1/ permanent;
    nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
  name: sample-ingress
spec:
  tls:
  - hosts:
    - '*.example.com'
    secretName: icog-ssl
  rules:
  - host: abc.example.com
    http:
      paths:
      - backend:
          service:
            name: sample-ingress
            port:
              number: 80
        path: /sample(/|$)(.*)
        pathType: ImplementationSpecific

Here is the Envoy filter that was created to handle Reference

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: sample-filter
spec:
  configPatches:
    - applyTo: HTTP_ROUTE
      match:
        routeConfiguration:
          vhost:
            name: "inbound|http|80"
      patch:
        operation: MERGE
        value:
          route:
            regex_rewrite:
              pattern:
                 google_re2:
                   max_program_size: 100
                 regex: "^/sample(/|$)(.*)$"
              substitution: "/\\2"
  workloadSelector:
    labels:
      app: sample

we also tried the following as well Reference

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: sample-filter
spec:
  configPatches:
    - applyTo: HTTP_ROUTE
      match:
        context: ANY
      patch:
        operation: MERGE
        value:
          route:
            regex_rewrite:
              pattern:
                 google_re2:
                   max_program_size: 100
                 regex: "^/sample(/|$)(.*)$"
              substitution: "/\\2"
  workloadSelector:
    labels:
      app: sample

Here is the Virtual Service:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: sample-vs
  namespace: default
spec:
  hosts:
  - "*.xyz.com"
  gateways:
  - sample-gateway
  http:
  - name: sample
    match:
    - uri:
        regex: /sample(/|$)(.*)
    rewrite:
      uri: /$2
    route:
    - destination:
        host: sample
        port:
          number: 80

Gateway

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: sample-gateway
  namespace: default
spec:
  selector:
    istio: ingressgateway # use istio default controller
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    tls:
      httpsRedirect: true
    hosts:
    - "*.xyz.com"
  - port:
      number: 443
      name: https
      protocol: HTTPS
    tls:
      mode: SIMPLE
      credentialName: sample-ssl 
    hosts:
    - "*.xyz.com"

Api REquests with Both the Envoyfilter returns 404. Not sure how to make this work with istio.

Mani
  • 5,401
  • 1
  • 30
  • 51
  • Along with envoy filters, gateway and virtual service would be required for routing to take place. For envoy filters rules pls refer istio documentation https://istio.io/latest/docs/reference/config/networking/envoy-filter/ – Nataraj Medayhal Jul 01 '22 at 14:43
  • @NatarajMedayhal thanks for the update I tried adding virtual service along with gateway it still didn't work. Have added both here. – Mani Jul 01 '22 at 14:55
  • How are the services being invoked? Any load balancer attached to ingress gateway. Or through node port. If re write is done virtual service then envoy filters wouldn’t be required. At envoy filter the workload for the app is selected – Nataraj Medayhal Jul 01 '22 at 15:18
  • Services are invoked via aws loadbalancer created by mentioned istio gateway. Should add the service as well? It is a cluster ip service which exposes TCP port 80. – Mani Jul 03 '22 at 02:54
  • 1
    if you are looking for simple rewrite to root path you can use the following match: - uri: prefix: /sample rewrite: uri: / Also you can refer old post https://stackoverflow.com/questions/56476847/istio-uri-rewrite-with-uri-regex-match and istio virtual service documentation for more details – Nataraj Medayhal Jul 03 '22 at 05:41
  • Nope i want to rewrite /sample(/|$)(.*) with \2. So if it it /sample/xyz it should be rewritten as /xyz. If it is /sample it should be rewritten as /. Now this /xyz may be anything like /abc,/def, /ghi,...etc.. That's why we are doing a regex and replacing 2nd match group. – Mani Jul 03 '22 at 06:05
  • i am afraid its supported. – Nataraj Medayhal Jul 03 '22 at 08:01
  • It should be. I'm sure something is missing not sure what it is. – Mani Jul 03 '22 at 08:13
  • It's not supported. HTTP Rewrite URI only allows string : https://istio.io/latest/docs/reference/config/networking/virtual-service/#HTTPRewrite – Peter Claes Jul 08 '22 at 11:10
  • Did you try the suggestion from Nataraj Medayhal ? – Peter Claes Jul 08 '22 at 11:15
  • This is resolved i handled it via simple rewrite will update the answer – Mani Jul 08 '22 at 12:51

1 Answers1

0

Finally, I was able to crack it down. It's actually simple. We can just use rewrite along with match in virtual service and there is no need to complicate it using filter. Here is the virtual service.

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: sample-vs
  namespace: default
spec:
  hosts:
  - "*.xyz.com"
  gateways:
  - sample-gateway
  http:
  - name: sample-trailing
    match:
    - uri:
        prefix: /sample
    redirect:
      uri: /sample/ # This ensures that the trailing slash is added to the path. same as **rewrite ^(/sample)$ $1/ permanent;**
  - name: sample
    match:
    - uri:
        prefix: /sample/
    rewrite:
      uri: / #This ensures that internally it gets routed to **/$2**
    route:
    - destination:
        host: sample
        port:
          number: 80

We are misguided by rewrite here we think rewrite rewrites the HTTP URL in the browser whereas it actually rewrites and forwards the request to the respective destination.

Mani
  • 5,401
  • 1
  • 30
  • 51