what is the difference between / and /* in ingress spec/rules/http/paths/path - kubernetes

I have the following ingress resource
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: kubernetes-demo-ing
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: \"false\"
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: test.my-docker-kubernetes-demo.com
http:
paths:
- path: /*
backend:
serviceName: my-demo-service
servicePort: 3000
My app was not getting accessed here test.my-docker-kubernetes-demo.com i was getting too many redirects error
but when i replaced under path from path: /* to path: /, it worked.
But i am not able to find how it fixed the problem, any help in understanding or explaining this would be great.

The meaning of / and /* depends on your ingress implementation, for example there are different ways of selecting a range of paths using the NGINX vs GCE ingress implementations:
NGINX: https://kubernetes.github.io/ingress-nginx/user-guide/ingress-path-matching/
path: /foo/.*
GCE: https://cloud.google.com/kubernetes-engine/docs/tutorials/http-balancer#step_6_optional_serving_multiple_applications_on_a_load_balancer
path: /*
You can choose the implementation to use by setting the kubernetes.io/ingress.class annotation.
In your case, assuming you're using NGINX, /* isn't interpreted as a glob pattern so only allows connecting literally to /*. Anything else would be sent to the default backend.

You should check NGINX Ingress Controller - Rewrite.
Starting in Version 0.22.0, ingress definitions using the annotation nginx.ingress.kubernetes.io/rewrite-targetare 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
Captured groups are saved in numbered placeholders, chronologically, in the form $1, $2 ... $n. These placeholders can be used as parameters in the rewrite-target annotation.
You can check version in a following way:
kubectl exec -it <nginx-ingress-controller-pod-name> -n ingress-nginx -- /nginx-ingress-controller --version
I think your Ingress should look like the following:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: kubernetes-demo-ing
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "false"
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
rules:
- host: test.my-docker-kubernetes-demo.com
http:
paths:
- path: /(.*)
backend:
serviceName: my-demo-service
servicePort: 3000

You can find a short explanation for spec.rules[].http.paths[].path in k8s.io/api/extensions/v1beta1.

Related

Kubernetes Ingress Controller Redirect if contains characters like "?"

I have an ingress controller working for UI container service and backend container service. my ingress configuration is as follows:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: testapp
annotations:
rules:
- host: test1.example.com
http:
paths:
- path: /static
backend:
serviceName: ui-service
servicePort: 80
- path: /apicall
backend:
serviceName: backend-service
servicePort: 8080
Which is working fine. Now I need to forward this ingress URL if it contains ?.
For eg, if url is test1.example.com/?productid=10001 I need to add static before this ? and forward it to test1.example.com/static?productid=10001.
Is this behavior possible through below annotations?
nginx.ingress.kubernetes.io/rewrite-target: /
If yes, how to have that regex kind of url where if ? is present in the url followed by any string/characters, add static keyword before it?
First of all look at the YAML below to understand how works rewrite rule:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
name: rewrite
namespace: default
spec:
ingressClassName: nginx
rules:
- host: rewrite.bar.com
http:
paths:
- path: /something(/|$)(.*)
pathType: Prefix
backend:
service:
name: http-svc
port:
number: 80
In this ingress definition, any characters captured by (.*) will be assigned to the placeholder $2, which is then used as a parameter in the rewrite-target annotation.
For example, the ingress definition above will result in the following rewrites:
rewrite.bar.com/something rewrites to rewrite.bar.com/
rewrite.bar.com/something/ rewrites to rewrite.bar.com/
rewrite.bar.com/something/new rewrites to rewrite.bar.com/new
In your case, you will need to follow a similar procedure. But first, I suggest you do a separate ingress for each path. This will help you keep order later and additionally you will have an independent ingress for each path. Look at this question to see why and how you should create a separate ingress.
Now I need to forward this ingress URL if it contains ?. for eg if URL is test1.example.com/?productid=10001 i need to add static before this ? and forward it to test1.example.com/static?productid=10001.
You will need to create an appropriate capture group. For the data you presented it will look like this:
- path: /(/|$)(.*)
and the annotation should be like this:
nginx.ingress.kubernetes.io/rewrite-target: /static/$2
In this case, everything that gets captured from the URL after the / character will be rewritten to the new address, which will look like /static and the address that was before. There should be no problem with the question mark.
If you need to create a regex that will act on a question mark, you will need to prefix it with a \ character, which is described here.
Also, consider that you are currently targeting root / path and want to create 2 ingresses. I also suggest creating appropriate endpoints depending on the situation, so that you can easily create 2 different ingresses responsible for directing different traffic.

How to properly configure k8s nginx ingress base url and path to handle vuejs client side routing and nodejs server side api

I'm trying to deploy my frontend client application and backend API on the same domain and I want the frontend on the base path: /
However, I realized that the frontend and the backend need two different rewrite-target to accomplish this.
front-end works with:
nginx.ingress.kubernetes.io/rewrite-target: /
while the backend works with:
nginx.ingress.kubernetes.io/rewrite-target: /$2
I tried using two different ingress services in order to accommodate different rewrite-target, but that fails because the host was the same domain.
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: test-ingress
namespace: test
annotations:
kubernetes.io/ingress.class: nginx
cert-manager.io/cluster-issuer: letsencrypt-staging
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/add-base-url: "true"
nginx.ingress.kubernetes.io/service-upstream: "true"
nginx.ingress.kubernetes.io/rewrite-target: /$2
nginx.ingress.kubernetes.io/proxy-buffer-size: 128k
nginx.ingress.kubernetes.io/proxy-buffering: "on"
nginx.ingress.kubernetes.io/proxy-buffers-number: "4"
nginx.ingress.kubernetes.io/cors-allow-credentials: "true"
nginx.ingress.kubernetes.io/configuration-snippet: |
more_set_headers "server: hide";
more_set_headers "X-Content-Type-Options: nosniff";
more_set_headers "X-Xss-Protection: 1";
spec:
tls:
- hosts:
- test.eastus.cloudapp.azure.com
secretName: tls-secret
rules:
- host: test.eastus.cloudapp.azure.com
http:
paths:
- backend:
serviceName: webapp
servicePort: 80
path: /
- backend:
serviceName: api
servicePort: 80
path: /api(/|$)(.*)
I know I can make both work with the same rewrite-target /$2 if I change the frontend path to path: /app(/|$)(.*) but I don't want to that except it is the only option.
Is there a way for me to better configure a single ingress to work for 2 different rewrite-target?
Ingress with API version networking.k8s.io/v1 with k8s version 1.19+ can solve your problem. I have given an example below.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: simple-fanout-example
spec:
rules:
- host: foo.bar.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: frontend-service
port:
number: 80
- path: /api
pathType: Prefix
backend:
service:
name: backend-service
port:
number: 8080
According to kubernetes documentation:
In some cases, multiple paths within an Ingress will match a request. In those cases precedence will be given first to the longest matching path. If two paths are still equally matched, precedence will be given to paths with an exact path type over prefix path type.
So, when you are looking for a resource located at path "/home.html", it only matches with your frontend service. But when you are looking for a resource located at path "/api/something" then it matches both service. But it will go to backend service always because of maximum path match stated above.
I don't know would you take it or not but it can a be solution. You can use two ingress for achieving your target. Each one will use different annotations. It will work fine.
Just as like your current ingress yaml, make another yaml and put two different annotations in them and also put your front-end and back-end in them separately. host (host: test.eastus.cloudapp.azure.com) will be same as you provided here.

kubernetes nginx ingress server-snippet annotation not taking effect

I have following ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: nginx-configuration-snippet
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
nginx.ingress.kubernetes.io/server-snippet: |
location /base/path/v1/api/update {
deny all;
return 404;
}
spec:
rules:
- http:
paths:
- path: /base/path(/|$)(.*)
backend:
serviceName: myApi
servicePort: 8080
But when I send PUT request to /base/path/v1/api/update instead of getting 404 I am getting 500 which means that the path is reachable from ingress controller. Can anybody help me identify why ?
I changed to configuration-snippet and the error I got is :
Error: exit status 1
2020/08/06 18:35:07 [emerg] 1734#1734: location "/base/path/v1/api/update" is outside location "^/base/path(/|$)(.*)" in /tmp/nginx-cfg008325631:2445
nginx: [emerg] location "/base/path/v1/api/update" is outside location "^/base/path(/|$)(.*)" in /tmp/nginx-cfg008325631:2445
nginx: configuration file /tmp/nginx-cfg008325631 test failed
Adding my own answer :
The final config that worked for me was :
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: nginx-configuration-snippet
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
nginx.ingress.kubernetes.io/server-snippet: |
location ~* "^/base/path/v1/api/update" {
deny all;
return 403;
}
spec:
rules:
- http:
paths:
- path: /base/path(/|$)(.*)
backend:
serviceName: myApi
servicePort: 8080
Just for other coming along here looking for a solution, worth knowing that snippets are ignored unless the nginx controller is started with the -enable-snippet option on the command line. It should be noted that this applies to nginxinc/kubernetes-ingress project.
The docs say:
Before creating a Deployment or Daemonset resource, make sure to
update the command-line arguments of the Ingress Controller container
in the corresponding manifest file according to your requirements.
For instance if you are running the Daemonset, you will have to edit the sudo nano kubernetes-ingress/deployments/daemon-set/nginx-ingress.yaml manifest and add your argument as shown below:
args:
- -nginx-configmaps=$(POD_NAMESPACE)/nginx-config
- -default-server-tls-secret=$(POD_NAMESPACE)/default-server-secret
- -enable-snippets
#- -v=3 # Enables extensive logging. Useful for troubleshooting.
#- -report-ingress-status
#- -external-service=nginx-ingress
#- -enable-prometheus-metrics
#- -global-configuration=$(POD_NAMESPACE)/nginx-configuration
Also check other Command-line Arguments in the docs here
If you are looking for helm follow this guide in the docs

Kubernetes: path based only works with root

I have an EKS cluster and currently use path based routing. I previously posted this thread, so all my configuration is on there: Kubernetes: 502 (Bad getaway)
My ingress controller is from there: https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.24.1/deploy/mandatory.yaml
Here is my ingress:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: simple-fanout-example
namespace : default
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
rules:
- host: domain.com
http:
paths:
- path: /bleble(/|$)(.*)
backend:
serviceName: bleble-svc
servicePort: 8080
- path: /hello-world
backend:
serviceName: hello-world-svc
servicePort: 8080
This works absolutly fine, until you try to go anywhere that is not the domain.com/bleble or domain.com/hello-world. The services need to refer to each other, and the uri they request is just domain.com, which obviously doesn't work because the service is at domain.com/nameoftheservice.
The 2 problems are :
The service name is bleble, so we decided the path should be /bleble. I saw on this documentation (kubernetes.github.io/ingress-nginx/examples/rewrite) that adding (/|$)(.*) would allow rewrite. We want to use url as domain.com/bleble/swagger or domain.com/bleble/clients, ... But when we type those, it brings back to what was on /bleble
I need bleble to get an info from hello-world. Right now, instead of going from domain.com/bleble to domain.com/hello-world, it goes from domain.com/bleble to domain.com. it seems to only be able to call the host name, and not the path.
I've tried doing a single ingress resource and have nginx.ingress.kubernetes.io/app-root : /bleble but this doesn't seem to be working. I've tried the annotation as well nginx.ingress.kubernetes.io/rewrite-target: /coretest
Thanks for the help!

Troubleshooting kubernetes nginx controller routing

I can't get the nginx controller to route based on the hostname. The YAML below doesn't work - traffic goes to the default back-end / I get a 404. However, if I remove the value for host, the ingress controller successfully routes traffic to my-service. The service works successfully if I place it behind a load balancer but I want to have multiple services working for different host names so I want to use an ingress controller and use a single IP. Thoughts?
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-nginx
annotations:
ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: test1.mydomain.com
http:
paths:
- path: /
backend:
serviceName: my-service
servicePort: 80
The yaml looks slightly different than the rewrite example located here. The yaml is valid and kubectl apply or create should work but not produce the results you are expecting. Do you need the rewrite annotation or could you remove it and the back end service will respond without issue? If you don't need to rewrite anything try removing the yaml to just look like:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-nginx
spec:
rules:
- host: test1.mydomain.com
http:
paths:
- backend:
serviceName: my-service
servicePort: 80