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))}