nginx ingress & rewrite-target nginx ingress & rewrite-target kubernetes kubernetes

nginx ingress & rewrite-target


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 valueFrom 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/v1beta1kind: Ingressmetadata:  name: myapi-ingannotations:  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


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/ --insecuresuccess - path: /api/$ curl https://$(minikube ip)/auth/api --insecurefailure - path: /auth/api$ curl https://$(minikube ip)/auth/api/blah/whatever --insecuresuccess - 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: v1kind: Servicemetadata:  name: ingress-rewite-examplespec:  selector:    app: ingress-rewite-example  ports:  - name: nginx    port: 80    protocol: TCP    targetPort: 80  type: NodePort---apiVersion: extensions/v1beta1kind: Deploymentmetadata:  name: ingress-rewite-examplespec:  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/v1beta1kind: Ingressmetadata:  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 mainimport (  "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))}