Enable rewrite for a particular host in ingress nginx configuration - nginx

I have below ingress-nginx configuration file.
It rewrites request for one.example.com. I have added another domain, but I don't want rewrite to happen for other domain.
I went through doc, but there is now rewrite example for multiple host setup.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-service
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/rewrite-target: /$1
certmanager.k8s.io/cluster-issuer: "letsencrypt-example-prod"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
tls:
- hosts:
- one.example.com
- two.example.com
secretName: super-secret
rules:
- host: one.example.com
http:
paths:
- path: /customer/?(.*)
pathType: Prefix
backend:
service:
name: customer-srv
port:
number: 3000
host: two.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: kube-prometheus-grafana
port:
number: 80
I could create two separate ingress files for each host.
What will happen in that case it will create two load balancers with different dns?
(cluster is hosted on aws)

You can create two separate ingress.
In that case, nothing will change your ingress controller IP would be same only for DNS.
What will happen in that case it will create two load balancers with
different dns?
No, it won't create two load balancers.

Related

Kubernetes ingress nginx route to same path (different service; different port)

I have some simple deployments, pods, services and nginx ingress in Kubernetes. I want to use ingress to route to the services (cluster-ip).
However, there are 2 services for 2 pods with the same path (i.e /abc/def). After I applied the ingress.yaml file, I got an error message saying "nginx: [emerg] duplicate location "/abc/def/" in /tmp/nginx/nginx-cfg728288520:2893".
May I know how to let ingress accepts the same paths with different service and different port?
Here is the ingress.yaml file:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/use-regex: "true"
name: ingress-nginx-default
namespace: default
spec:
rules:
- host:
http:
paths:
- path: /abc/def/
pathType: Prefix
backend:
service:
name: service1
port:
number: 8090
- path: /abc/def
backend:
service:
name: service2
port:
number: 8068
pathType: Prefix
ingressClassName: nginx
"nginx: [emerg] duplicate location "/abc/def/" in /tmp/nginx/nginx-cfg728288520:2893". This error indicates the same host with two same paths which is a duplicate location.
You can use simple fanout based on path or name based virtual hosting.
In order to do this you need to have two hosts that need to be mentioned in the ingress.
based on your example you'd most likely want to have something like foo.bar.com and bar.foo.com. Here's the example from the Kubernetes docs:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: name-virtual-host-ingress
spec:
rules:
- host: foo.bar.com
http:
paths: #path_name
- backend:
serviceName: service1
servicePort: 80
- host: bar.foo.com
http:
paths: #path_name
- backend:
serviceName: service2
servicePort: 80

Ingress rewrite to two different services from one DNS

I am trying to reach out to two services from my DNS.
Example:- myportal.com
myportal.com/app1
I have my SSO and SSL implementation on "myportal.com" and on the home page I have a button which calls a service "myportal.com/app1". I have tried multiple things but I am not able to configure both properly.
From below ingress config I am able to redirect to "myportal.com/app1" but its not working properly for "myportal.com". I have tried multiple thing including default backend and its not working for me. When I use default backend then "myportal.com" works but it stops redirecting to /app1.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myportal-ingress-test
namespace: appspace
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
nginx.ingress.kubernetes.io/use-regex: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- myportal.com
secretName: secret
rules:
- host: myportal.com
http:
paths:
- pathType: Prefix
path: /
backend:
service:
name: portal-service
port:
number: 8097
- pathType: Prefix
path: /app1(/|$)(.*)
backend:
service:
name: app-ui-service
port:
number: 8087
I am fairly new to kubernetes and I am not sure if it's the correct way to implement such things. I am open to new implementation too if it's using ingress and routing to different services using same dns on different path.
Thanks in advance for the help!
I was able to resolve this issue. The redirect in an ingress file would work for all the paths, so I created a separate ingress for each path with individual redirects.
Ingress 1 - myportal.com (with SSO and SSL)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: gcpportal-service-test
namespace: appspace
annotations:
nginx.ingress.kubernetes.io/x-forwarded-prefix: /myportal-service
nginx.ingress.kubernetes.io/ssl-redirect: 'true'
spec:
ingressClassName: nginx
tls:
- hosts:
- myportal.com
secretName: secret
defaultBackend:
service:
name: myportal-service
port:
number: 80
rules:
- host: myportal.com
Ingress 2 - myportal.com/app1 (application deployed)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: gcpportal-service-test-1
namespace: appspace
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
nginx.ingress.kubernetes.io/use-regex: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- myportal.com
secretName: secret
rules:
- host: myportal.com
- pathType: Prefix
path: /app1(/|$)(.*)
backend:
service:
name: app1-ui-service
port:
number: 8087
This helped me to resolve this issue. I also verified that this way is also a standard way and is provided in one of the documentation of nginx.
https://kubernetes.github.io/ingress-nginx/user-guide/ingress-path-matching/

CSRF cookie not set - possibly blocked by kubernetes ingress

I use Axios in React and Django Rest Framework with dj-rest-auth. After migrating from GCP to Azure and removing the unmaintained django-rest-auth, I got some new CSRF issues.
Initially I removed django-rest-auth and created my own LoginView from Django.contrib.auth.views. Noticed that this also gave the CSRF error in development. So I added dj-rest-auth, which solved my issue locally. Pushed to the AKS, but there the cookie still does not appear. I'm suspecting my ingress to be the problem, which is able to set INGRESSCOOKIE for both my backend and frontend, but no CSRF.
I know there's a million tickets about this topic, my Django settings are fine, the set-cookie resopnse header is set. Also use the right axios settings to make sure that if the cookie is there, it's used for requests. The problem is really with the fact that the set-cookie is not coming through, as it is being created in Django.
I use an Nginx controller with TLS on a static IP with and have my ingress defined as follows:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: basic-ingress
annotations:
kubernetes.io/ingress.class: nginx
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/rewrite-target: /
kubernetes.io/ingress.allow-http: "true"
spec:
tls:
- hosts:
- XXXXX
secretName: tls-secret
rules:
- host: XXXXXXXX
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: frontend
port:
number: 80
- path: /api/
pathType: Prefix
backend:
service:
name: backend
port:
number: 8080
The problems was indeed at the ingress, not so much with the settings, but with the routing. The routing used above, rewrites the targets to / for all requests. My backend actually has a page there, which is CSRF protected. It went to that page instead of the login page. Changing the ingress to below yielded better results.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: basic-ingress
annotations:
kubernetes.io/ingress.class: nginx
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/rewrite-target: /$1
kubernetes.io/ingress.allow-http: "true"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
tls:
- hosts:
- XXXXXXXXXX
secretName: tls-secret
rules:
- host: XXXXXX
http:
paths:
- path: /?(.*)
pathType: Prefix
backend:
service:
name: frontend
port:
number: 80
- path: /api/?(.*)
pathType: Prefix
backend:
service:
name: backend
port:
number: 8080

kubernetes ingress server-alias only applies to one ingress host

According to this doc (https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#server-alias), I'm able to add additional server_name to the nginx config file.
However, it adds the extra server_name to all of my hosts, which cause conflicts for sure.
Is there a way to add server-alias only for one of my hosts? Say I only want to add 10.10.0.100 to my test1 host.
Ingress example:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-ingress
namespace: default
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/server-alias: 10.10.0.100
spec:
rules:
- host: test1.com
http:
paths:
- path: /
backend:
service:
name: test1-service
port:
number: 8000
pathType: Prefix
- host: test2.com
http:
paths:
- path: /
backend:
service:
name: test2-service
port:
number: 8000
pathType: Prefix
TL;DR
You can split your Ingress resource on multiple objects (which will work together) to add Annotations to only specific hosts.
Annotations can only be set on the whole kubernetes resource, as they are part of the resource metadata. The ingress spec doesn't include that functionality at a lower level.
-- Stackoverflow.com: Questions: Apply nginx-ingress annotations at path level
Extending on the answer to give an example of how such setup could be created. Let's assume (example):
All required domains pointing to the Service of type LoadBalancer of nginx-ingress-controller:
hello.kubernetes.docker.internal - used in host .spec
hello-two.kubernetes.docker.internal - used in annotations .metadata
--
goodbye.kubernetes.docker.internal - used in host .spec
goodbye-two.kubernetes.docker.internal- used in annotations .metadata
Skipping the Deployment and Service definitions, the Ingress resources should look like below:
hello-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: hello-ingress
annotations:
nginx.ingress.kubernetes.io/server-alias: "hello-two.kubernetes.docker.internal"
spec:
rules:
- host: hello.kubernetes.docker.internal # <-- IMPORTANT
http:
paths:
- path: /
backend:
service:
name: hello-service
port:
number: 80
pathType: Prefix
goodbye-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: goodbye-ingress
annotations:
nginx.ingress.kubernetes.io/server-alias: "goodbye-two.kubernetes.docker.internal"
spec:
rules:
- host: goodbye.kubernetes.docker.internal # <-- IMPORTANT
http:
paths:
- path: /
backend:
service:
name: goodbye-service
port:
number: 80
pathType: Prefix
Above definitions will create 2 Ingress resources that will be merged:
hello-service will respond for:
hello.kubernetes.docker.internal
hello-two.kubernetes.docker.internal
goodbye-service will respond for:
goodbye.kubernetes.docker.internal
goodbye-two.kubernetes.docker.internal
Running:
$ kubectl get ingress:
NAME CLASS HOSTS ADDRESS PORTS AGE
goodbye-ingress <none> goodbye.kubernetes.docker.internal localhost 80 36m
hello-ingress <none> hello.kubernetes.docker.internal localhost 80 36m
Additional resources:
Kubernetes.io: Docs: Concepts: Services networking: Ingress
Kubernetes.github.io: Ingress NGINX: Annotations: Server alias

Per-path rewrite in an Kubernetes NGINX reverse proxy ingress controller

I'm setting up a Kubernetes cluster which contains three applications, each running within their own respective pod and service. The web frontends of these applications should be accesible at ports 80, 9000 and 15672. There are also a number of Backend-APIs running in their own pods and services, which should be accesible at their respective ports. The cluster is accessed through a NGINX reverse proxy with the following ingress-definition:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: my-ingress
namespace: my-namespace
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/use-regex: "true"
spec:
tls:
- hosts:
- myapp.com
secretName: my-certificat
rules:
- host: myapp.com
http:
paths:
- backend:
serviceName: my-service-1
servicePort: 8092
path: /api/someroute/(.*)
- backend:
serviceName: my-service-2
servicePort: 30003
path: /api/someotherroute/(.*)
- backend:
serviceName: my-other-frontend
servicePort: 9000
path: /other/(.*)
- backend:
serviceName: my-yetanother-frontend
servicePort: 15672
path: /yetanother/(.*)
- backend:
serviceName: my-main-frontend
servicePort: 80
path: /(.*)
This works for the api-services, but not for the frontends. Was I to enter a URI like myapp.com/other/ in my browser it would make a call to my-other-frontend:9000/other/, instead of my-other-frontend:9000/. This can of course be solved with a rewrite annotation like nginx.ingress.kubernetes.io/rewrite-target: /$1, the problem is, that this would also apply to the api-services, and those actually need the complete route in their call, so a general rewrite rule would break them.
So my question is: Is it possible to define rewrite rules that only apply to specific paths?
I would advise to split your ingress into 2 based on your different annotations.
1) First one for api-services, called my-api-ingress
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: my-api-ingress
namespace: my-namespace
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/use-regex: "true"
spec:
tls:
- hosts:
- myapp.com
secretName: my-certificat
rules:
- host: myapp.com
http:
paths:
- backend:
serviceName: my-service-1
servicePort: 8092
path: /api/someroute/(.*)
- backend:
serviceName: my-service-2
servicePort: 30003
path: /api/someotherroute/(.*)
2) And second one, lets say my-front-ingress with nginx.ingress.kubernetes.io/rewrite-target: /$1 annotation for rest of your frontends. Based on your question I believe you dont need the detailed instruction for ingress creation with rewrite annotation.
EDIT1:
Yes, its possible to create multiple ingresses with the same host. But please pay attention which exactly nginx ingress. Refer to #LazerBass answer with his investigations.
In short, based on nginx ingress comparation table,
The nginxinc controller does not support merging Ingress rules with the same host. You can use it only with Mergeable Ingresses
The easiest way is to use regular kubernetes/ingress-nginx
Hope that helps.

Resources