Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

nginx ingress & rewrite-target

I have a pod that responds to requests to /api/

I want to do a rewrite where requests to /auth/api/ go to /api/.

Using an Ingress (nginx), I thought that with the ingress.kubernetes.io/rewrite-target: annotation I could do it something like this:

apiVersion: extensions/v1beta1 kind: Ingress metadata:   name: myapi-ing   annotations:     ingress.kubernetes.io/rewrite-target: /api     kubernetes.io/ingress.class: "nginx" spec:   rules:   - host: api.myapp.com     http:       paths:       - path: /auth/api         backend:           serviceName: myapi           servicePort: myapi-port 

What's happening however is that /auth/ is being passed to the service/pod and a 404 is rightfully being thrown. I must be misunderstanding the rewrite annotation.

Is there a way to do this via k8s & ingresses?

like image 910
matt Avatar asked Dec 15 '17 17:12

matt


People also ask

What is nginx ingress used for?

NGINX Ingress Controller provides a robust feature set to secure, strengthen, and scale your containerized apps, including: Advanced app‑centric configuration – Use role‑based access control (RBAC) and self‑service to set up security guardrails (not gates), so your teams can manage their apps securely and with agility.

What is the difference between nginx and ingress?

Ingress , or ingress rules are the rules that ingress controller follows to distribute the load. Ingress controller get the packet, checks ingress rules and determines to which service to deliver the packet. Nginx ingress controller uses LoadBalancer type service actually as entrypoint to the cluster.

What is ingress class nginx?

ingress-nginx can be used for many use cases, inside various cloud provider and supports a lot of configurations. In this section you can find a common usage scenario where a single load balancer powered by ingress-nginx will route traffic to 2 different HTTP backend services based on the host name.

Is nginx ingress controller open source?

There are two popular Kubernetes Ingress controllers that use NGINX – both are open source and hosted on GitHub.


2 Answers

I don't know if this is still an issue, but since version 0.22 it seems you need to use capture groups to pass values to the rewrite-target value From the nginx example available here

Starting in Version 0.22.0, ingress definitions using the annotation nginx.ingress.kubernetes.io/rewrite-target are not backwards compatible with previous versions. In Version 0.22.0 and beyond, any substrings within the request URI that need to be passed to the rewritten path must explicitly be defined in a capture group.

For your specific needs, something like this should do the trick

apiVersion: extensions/v1beta1 kind: Ingress metadata:   name: myapi-ing annotations:   ingress.kubernetes.io/rewrite-target: /api/$2   kubernetes.io/ingress.class: "nginx" spec:  rules:  - host: api.myapp.com    http:     paths:      - path: /auth/api(/|$)(.*)        backend:          serviceName: myapi          servicePort: myapi-port 
like image 153
Kerruba Avatar answered Sep 24 '22 04:09

Kerruba


I have created the following example that works and which I will explain. To run this minimal example, run these commands:

$ minikube start   $ minikube addons enable ingress # might take a while for ingress pod to bootstrap   $ kubectl apply -f kubernetes.yaml  $ curl https://$(minikube ip)/auth/api/ --insecure success - path: /api/ $ curl https://$(minikube ip)/auth/api --insecure failure - path: /auth/api $ curl https://$(minikube ip)/auth/api/blah/whatever --insecure success - path: /api/blah/whatever 

As you'll notice, the ingress rewrite annotation appears to be very particular about trailing slashes. If a trailing slash is not present, the request will not be rewritten. However, if a trailing slash is provided, the request uri will be rewritten and your proxy will function as expected.

After inspecting the generated nginx.conf file from inside the ingress controller, the line of code responsible for this behavior is:

rewrite /auth/api/(.*) api/$1 break; 

This line tells us that only requests matching the first argument will be rewritten with the path specified by the second argument.

I believe this is bug worthy.

kubernetes.yaml

--- apiVersion: v1 kind: Service metadata:   name: ingress-rewite-example spec:   selector:     app: ingress-rewite-example   ports:   - name: nginx     port: 80     protocol: TCP     targetPort: 80   type: NodePort  --- apiVersion: extensions/v1beta1 kind: Deployment metadata:   name: ingress-rewite-example spec:   template:     metadata:       labels:         app: ingress-rewite-example     spec:       containers:       - name: ingress-rewite-example         image: fbgrecojr/office-hours:so-47837087         imagePullPolicy: Always         ports:         - containerPort: 80  --- apiVersion: extensions/v1beta1 kind: Ingress metadata:   name: ingress-rewite-example   annotations:     ingress.kubernetes.io/rewrite-target: /api     kubernetes.io/ingress.class: "nginx" spec:   rules:   - http:       paths:       - path: /auth/api         backend:           serviceName: ingress-rewite-example           servicePort: 80 

main.go

package main  import (   "fmt"   "strings"   "net/http" )  func httpHandler(w http.ResponseWriter, r *http.Request) {   var response string   if strings.HasPrefix(r.URL.Path, "/api") {     response = "success"   } else {     response = "failure"   }   fmt.Fprintf(w, response + " - path: " + r.URL.Path + "\n") }  func main() {     http.HandleFunc("/", httpHandler)     panic(http.ListenAndServe(":80", nil)) } 
like image 43
frankgreco Avatar answered Sep 24 '22 04:09

frankgreco