Unable to access ingress k8s resources after using rewrite-target annotation - kubernetes

I have a K8s cluster, with two services - one service serving the front end static files and the other for backend. To differentiate between the two, I am using an ingress and a rest call to xyz.com/ is directed to the frontend service and rest calls to xyz.com/rest/abc are directed to the backend service (which is an api gateway and collection of services behind it). When creating an ingress, if i use the rewrite target annotation to rewrite xyz.com/rest/abc to xyz/com/abc, then i start getting errors when trying to access the front end service..
The errors that I have faced are
Did not parse stylesheet .... because non css mime types are not allowed in strict mode
Syntax error: Unexpected token < (while parsing bundle.js)
but if i am not using the rewrite annotation, then all files are transferred without any issue and the page is rendered as it should
annotation being used:
nginx.ingress.kubernetes.io/rewrite-target: /$2
using nginx ingress controller
Not sure why this is happening, could anyone help, any pointers, or any error that I am making.
Instead of using the path: "/" for the frontend service, i tried giving a more exact path "/ui" but it still gives the same issue.
New to K8s and ingress, so stuck here, and not sure what to do.
Ingress ->
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: sample-ingress
labels:
name: sample-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
nginx.ingress.kubernetes.io/use-regex: "true"
spec:
rules:
- host: xyz.com
http:
paths:
- pathType: Prefix
path: /rest(/|$)(.*)
backend:
service:
name: backend-service
port:
number: 8080
- pathType: Prefix
path: /()
backend:
service:
name: frontend-service
port:
number: 3000

For me it's still not clear what the desired behavior is. If you want to have
/rest/restpath -> backend-service/restpath
and
/uipath -> frontend-service/uipath
then your ingress could look like this:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: sample-ingress
labels:
name: sample-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
nginx.ingress.kubernetes.io/use-regex: "true"
spec:
rules:
- host: xyz.com
http:
paths:
- pathType: Prefix
path: /rest/(.*)
backend:
service:
name: backend-service
port:
number: 8080
- pathType: Prefix
path: /(.*)
backend:
service:
name: frontend-service
port:
number: 3000

Related

K8S traffic to one service via two separate ingress (http + https)

So I have a bunch of services running in a cluster, all exposed via HTTP only ingress object, example:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
name: some-ingress
spec:
ingressClassName: nginx
rules:
- http:
paths:
- backend:
service:
name: some-svc
port:
number: 80
path: /some-svc(/|$)(.*)
pathType: Prefix
They are accessed by http://<CLUSTER_EXTERNAL_IP>/some-svc, and it works ofc.
Now I want to create an additional ingress object for every service which will force SSL connections and allow the use of a domain instead of an IP address.
The problem is that the newer SSL ingresses always return 404 while testing the connection.
The manifests are as follows:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: "some-ingress-ssl"
annotations:
ingress.kubernetes.io/ssl-redirect: "true"
ingress.kubernetes.io/app-root: "/some-svc"
spec:
tls:
- hosts:
- foobar.com
secretName: foobar-tls
rules:
- host: foobar.com
http:
paths:
- path: /some-svc(/|$)(.*)
pathType: Prefix
backend:
service:
name: some-svc
port:
number: 80
tests (foobar.com point to CLUSTER_EXTERNAL_IP):
> curl -I http://<CLUSTER_EXTERNAL_IP>/some-svc
HTTP/1.1 200 OK
> curl -I https://foobar.com/some-svc
HTTP/2 404
Is it possible to have both ingresses simultaneously? (one enforcing SSL, the other not)
If so what am I doing wrong here?
Figured out I was missing this annotation:
nginx.ingress.kubernetes.io/rewrite-target: /$2
in SSL ingress...
works like a charm now, maybe someone will find this usefull

Only allow requests to certain paths using k8s ingress

I've set up an ingress to route traffic to my http server, however I would like to leave some routes inaccessible from outside of the cluster.
Example routes:
/status -> end point to determine service status
/users/names -> returns users
/users/ages -> returns ages
current ingress:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
namespace: my-namespace
name: my-app-ingress
annotations:
kubernetes.io/ingress.class: nginx
spec:
rules:
- host: localhost
http:
paths:
- pathType: Prefix
path: /
backend:
service:
name: my-service
port:
number: 8080
this works currently but leaves all routes accessible. What I want to do is only have routes that fall under the /users path open, so that would be both /users/names and /users/ages. That would leave /status inaccessible from outside of the cluster. Is this achievable from changing the ingress configuration? Any help would be appreciated.
Just specify the path that you want to expose via the ingress like this:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
namespace: my-namespace
name: my-app-ingress
annotations:
kubernetes.io/ingress.class: nginx
spec:
rules:
- host: localhost
http:
paths:
- pathType: Prefix
path: /users # <- add the path here
backend:
service:
name: my-service
port:
number: 8080

K8S Ingress controller redirect to the wrong path

I have an Nginx ingress controller running on one k8s namespace,
and on another k8s namespace, I defined a pod, a service, and an ingress resource.
this is the ingress resource definition:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: my-app-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
ingressClassName: general-internal
rules:
- host: example.com
http:
paths:
- path: "/my-app(/|$)(.*)"
backend:
serviceName: my-app-svc
servicePort: 443
now, when I access this link:
http://example.com/my-app/some-path/
then everything is ok because the "my-app-svc" knows the path "/some-path/" and returns a 200 response (the forwarding is to http://my-app-svc/some-path and that's great because my-app-svc doesn't and shouldn't know or care for the /my-app prefix that exists only for the nginx ingress controller so it will know to forward that request to "my-app-svc" internally).
but when I access this link (notice no "/" in the end):
http://example.com/my-app/some-path
I get a redirection response from the "my-app-svc" service, and the "Location" header contains "/some-path/", so the redirection is to:
http://example.com/some-path/
which does not lead to the "my-app-svc" service because it doesn't have the "/my-app" prefix.
If the Location header was "/my-app/some-path/" instead of "/some-path/" then everything was ok because the redirection would be to:
http://example.com/my-app/some-path/
which would give me the 200 response.
the question is, how can I do that the ingress controller will add a "my-app" prefix to the Location header when it returns the redirection response to the client?
Thanks
Thanks to my co-worker, we found a solution for the problem:
The solution is to add these annotations to the ingess resource:
nginx.ingress.kubernetes.io/proxy-redirect-from: /
nginx.ingress.kubernetes.io/proxy-redirect-to: /my-app/
meaning:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: my-app-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
nginx.ingress.kubernetes.io/proxy-redirect-from: /
nginx.ingress.kubernetes.io/proxy-redirect-to: /my-app/
spec:
ingressClassName: general-internal
rules:
- host: example.com
http:
paths:
- path: "/my-app(/|$)(.*)"
backend:
serviceName: my-app-svc
servicePort: 443
It seems that the annotations above check the "Location" header in the redirection response to the client, and replace the first / with /my-app/ and only after this change - the redirection response is sent to the client.
For anyone landing here and finding the above solution not working (like myself), you might be using nginx-based ingress https://www.nginx.com/blog/guide-to-choosing-ingress-controller-part-4-nginx-ingress-controller-options/ which needs different annotation to your ingress resource:
nginx.org/rewrites: "serviceName=service1 rewrite=rewrite1[;serviceName=service2 rewrite=rewrite2;...]"
which worked for me.
A complete declaration from https://github.com/nginxinc/kubernetes-ingress/tree/v2.3.0/examples/rewrites copied here:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: cafe-ingress
annotations:
nginx.org/rewrites: "serviceName=tea-svc rewrite=/;serviceName=coffee-svc rewrite=/beans/"
spec:
rules:
- host: cafe.example.com
http:
paths:
- path: /tea/
pathType: Prefix
backend:
service:
name: tea-svc
port:
number: 80
- path: /coffee/
pathType: Prefix
backend:
service:
name: coffee-svc
port:
number: 80

Is it possible to use same hostname with multiple Ingress resources running in different namespaces?

I want to use the same hostname let's say example.com with multiple Ingress resources running in different namespaces i.e monitoring and myapp. I'm using Kubernetes nginx-ingress controller.
haproxy-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: haproxy-ingress
namespace: myapp
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
tls:
- hosts:
# fill in host here
- example.com
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: haproxy
port:
number: 80
grafana-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: grafana-ingress
namespace: monitoring
annotations:
nginx.ingress.kubernetes.io/use-regex: "true"
spec:
tls:
- hosts:
- example.com
rules:
- host: example.com
http:
paths:
# only match /grafana and paths under /grafana/
- path: /grafana(/|$)(.*)
pathType: Prefix
backend:
service:
name: grafana
port:
number: 3000
When I'm doing curl example.com then it is redirecting me to the deployment running in namespace one(as expected) but when I'm doing curl example.com/grafana then still it is redirecting me to namespace one deployment.
Please help.
Yes it is possible.
There can be two issues in your case.
One is you don't need the regex path for grafana ingress. Simple /grafana path will be fine with path type Prefix as with path type Prefix any /grafana/... will be redirected associated service. So the manifest file will be:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: grafana-ingress
namespace: monitoring
spec:
tls:
- hosts:
- example.com
rules:
- host: example.com
http:
paths:
- path: /grafana
pathType: Prefix
backend:
service:
name: grafana
port:
number: 3000
And the second issue can be the related service or deployment might not be the under same namespace monitoring. Please make sure the deployment/service/secret or other resources needed for grafana remains under the same namespace monitoring.

Kubernetes Nginx Ingress Controller missing path

I have two deffinitions for Nginx Ingress Controller. Each of them routes to services for web app(React app hosted on nginx) and web api(.Net Core).
First is workig fine, but it is cumbresome since I need to add entry in etc file for each specified host to make it work:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-nginx-controller
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: testapp-web-dev
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: testapp-portal-web-service
port:
number: 80
- host: testapp-api-dev
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: testapp-portal-api-service
port:
number: 80
I decided to modify it to have single host with multiple paths, so I will have only one entry in etc file. But it does not work. First request is routed correctly to http://testapp//testapp-web-dev but every other next
request fails i.e. request for manifest goes to http://testapp/manifest.json but it should go to http://testapp/testapp-web-dev/manifest.json.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-nginx-controller
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
rules:
- host: testapp
http:
paths:
- path: /testapp-web-dev(/|$)(.*)
pathType: Prefix
backend:
service:
name: testapp-portal-web-service
port:
number: 80
- path: /testapp-api-dev(/|$)(.*)
pathType: Prefix
backend:
service:
name: testapp-portal-api-service
port:
number: 80
Tried couple different url rewrite but without luck.
If you want to preserve the requested path, you need to remove the nginx.ingress.kubernetes.io/rewrite-target: /$2 annotation.
As per Nginx Ingress Rewrite:
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.
i.e., the annotation is redirecting http://testapp/testapp-web-dev/manifest.json to http://testapp/manifest.json.