Dynamic Routing by Hostname only - Kubernetes Ingress Rules - kubernetes

I have a K8s cluster with multiple different services deployed and would like to use a single Ingress to route each incoming request to the appropriate service via a unique hostname DNS.
Currently, I've only been able to resolve a request when using the root path i.e. service-123.app.com.
As soon as I try to make a request with a path it doesn't resolve. The paths are valid paths to each service. For example, service-123.app.com/page/12345 would be expected by the application.
I might not fully understand how K8s Ingress rules are expected to work, but I hoped that it would match based on hostname only and simply forward on the path to the appropriate service.
Am I missing something very simple here? Any help is much appreciated. Thanks!
Here are my config files.
Ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
......
name: app-name
namespace: default
spec:
rules:
- host: service-123.app.com
http:
- path: "/*"
backend:
serviceName: service-123
servicePort: 80
- host: service-456.app.com
http:
paths:
- path: "/*"
backend:
serviceName: service-456
servicePort: 80
service.yaml
---
apiVersion: v1
kind: Service
metadata:
annotations: {}
labels:
app: service-123
name: service-123
namespace: default
spec:
ports:
- name: port8080
port: 80
targetPort: 8080
selector:
app: service-123
type: NodePort

Not sure which K8s and ingress controller you are using, but in the later K8s you can specify the pathType which takes care of path wildcards more nicely.
You would have something like this:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
......
name: app-name
namespace: default
spec:
rules:
- host: service-123.app.com
http:
- path: /
pathType: Prefix
backend:
serviceName: service-123
servicePort: 80
- host: service-456.app.com
http:
paths:
- path: /
pathType: Prefix
backend:
serviceName: service-456
servicePort: 80
If you are using an nginx ingress controller a good way to see the right nginx configuration is by looking at the actual nginx.conf generated by the ingress controller.
$ kubectl cp <nginx-ingress-controller-pod>:nginx.conf nginx.conf
$ cat nginx.conf

Related

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

Creating ingress resource

How do I create an ingress(ping) to expose a single service(hello) given a path (/hello )and a port (6789) in a given namespace (dev)?
the following is right? Also how to verify the same?
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ping
namespace: dev
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- http:
paths:
- path: /hello
pathType: Prefix
backend:
service:
name: hello
port:
number: 6789
You might need to add the host into the ingress YAML if you are looking forward to use the domain for resolution like
hello-world.info forward the traffic to hello service.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
rules:
- host: hello-world.info
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web
port:
number: 8080
to verify the changes you can use the Curl to check and test the endpoint also.
Once your YAML file is applied and ingress is created on cluster you can hit the endpoint and verify.
i would recommend checking out the part test your ingress :
https://kubernetes.io/docs/tasks/access-application-cluster/ingress-minikube/#test-your-ingress

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 ingress - access to web service container subpaths

I have a web service (dashboard-service) running in a container. The service provides the required webpages at:
http://192.168.1.100:3000/page2/
http://192.168.1.100:3000/page3/
etc
I have the dashboard-service running in a kubernetes cluster, and want to use ingress to control access like this:
so that I can access at: http://192.168.1.100:3000/dashboard/1
http://192.168.1.100:3000/dashboard/2
etc
I've tried the following ingress setup, but am getting "404 Not Found"
Is there some way of adding routes to subpaths?
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: dashboard-service
namespace: db
annotations:
ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- http:
paths:
- path: /dashboard/
pathType: Prefix
backend:
service:
name: dashboard-service
port:
number: 3000
First of all, there is no below configuration in ingress
backend:
service:
name: dashboard-service
port:
number: 3000
You should use next instead..
- backend:
serviceName: dashboard-service
servicePort: 3000
Next, I would propose you install, configure and use nginx ingress controller instead of regular kubernetes-ingress. Please note also, if you use nginx controller, your annotation should be nginx.ingress.kubernetes.io/rewrite-target: , not ingress.kubernetes.io/rewrite-target:
As per NGINX Ingress Controller rewrite documentation, your ingress should look like
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /page$2
name: dashboard-service
namespace: db
spec:
rules:
http:
paths:
- backend:
serviceName: dashboard-service
servicePort: 3000
path: /dashboard(/|$)(.*)
I tested regex and capture groups for you here: https://regex101.com/r/3zmz6J/1

How to whitelist only one path in kubernetes nginx ingress controller

Using the Nginx Ingress Controller, we would like to expose different paths of a Kubernetes service, with different security requirements.
/ is open to the public
/white-list only allows connections from a specific IP Address
/need-key requires an API key
I'm running in AWS EKS. Kubernetes version is as follows:v1.12.6-eks-d69f1b.
If we use Annotations, they apply to the entire service. Ideally I would like to apply an Annotation only to a path.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-myServiceA
annotations:
# use the shared ingress-nginx
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: myServiceA.foo.org
http:
paths:
- path: /
backend:
serviceName: myServiceA
servicePort: 80
- path: /white-list
backend:
serviceName: myServiceA
servicePort: 80
**NEED SOMETHING HERE TO WHITELIST**
- path: /need-key
backend:
serviceName: myServiceA
servicePort: 80
**NEED SOMETHING HERE TO USE API-KEY**
The results I've been having end up applying to all the paths.
I can live without API-Key as I can code that out, but ideally, I'd rather have it managed outside of the container.
Has anyone accomplished this with NGINX Ingress controller?
To apply annotation for each path, you could write one ingress rule for each path you want to apply. Nginx Ingress Controller will collect those ingress rules by itself and apply accordingly.
For example:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-myServiceA-root
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: myServiceA.foo.org
http:
paths:
- path: /
backend:
serviceName: myServiceA
servicePort: 80
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-myServiceA-white-list
annotations:
kubernetes.io/ingress.class: "nginx"
ingress.kubernetes.io/whitelist-source-range: X.X.X.X/32
spec:
rules:
- host: myServiceA.foo.org
http:
paths:
- path: /white-list
backend:
serviceName: myServiceA
servicePort: 80
...