Nginx Ingress block all path (/*) and allow only some specific path (/code-refiner/ and /v1/unsubscribed/*) - nginx

I wanted to create an nginx ingress which allows only few paths for users to connect and rest all block or provide an 403 error. Any way to achieve that ?
I only wanted users to allow to connect "/code-refiner/", /v1/unsubscribed/* and rest all should be blocked.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: code-refiner-service-ingress-external
namespace: backend
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
kubernetes.io/ingress.class: nginx-external
spec:
rules:
- host: code-refiner.example.com
http:
paths:
- backend:
service:
name: code-refiner-service
port:
number: 80
path: /
pathType: Prefix
I need to achieve something like this
location /* {
deny all;
}
location /code-refiner/ or /v1/unsubscribed/{
allow all;
}

As per this git link, you can create two Ingress and only add the annotations to the ingress with the path you want to protect
For your issues create two Ingresses first by default without any restriction.
Then, create a secret for auth as described in the doc.(Create a htpasswd and secret)
Creating the htpasswd
$ htpasswd -c auth foo
New password: <bar>
New password: \
Re-type new password:
Adding password for user foo
Creating the secret:
kubectl create secret generic basic-auth --from-file=auth secret
3.Second Ingress with auth for paths which you need to restrict.
kind: Ingress
apiVersion: extensions/v1beta1
metadata:
annotations:
kubernetes.io/ingress.class: nginx
ingress.kubernetes.io/rewrite-target: /
kubernetes.io/tls-acme: true
# type of authentication
ingress.kubernetes.io/auth-type: basic
# name of the secret that contains the user/password definitions
ingress.kubernetes.io/auth-secret: basic-auth
# message to display with an appropiate context why the authentication is required
ingress.kubernetes.io/auth-realm: "Authentication Required - foo"
# Below configuration-snippet is to pass on the authenticated user-name to serviceB
ingress.kubernetes.io/configuration-snippet: |
proxy_set_header X-AUTH-USER $remote_user;
name: my-nginx-ingress-auth
spec:
tls:
hosts:
myhost
secretName: mysecret
rules:
host: myhost
http:
paths:
path: /serviceB/
backend:
serviceName: serviceB-service
servicePort: 7070
For your reference adding these stack links [1] [2].
Second one is with usage of ConfigMaps and Server-snippet:
What you have to do is to locate your configMap:
kubectl get pod <nginx-ingress-controller> -o yaml
This is located the container args:
spec:
containers:
- args:
- /nginx-ingress-controller
- configmap=$(POD_NAMESPACE)/nginx-loadbalancer-conf
And then just edit it and place add the server-snippet part
apiVersion: v1
data: server-snippet: |
location /admin-access {
deny all;
}
This approach allows you to define restricted locations globally for all hosts defined in Ingress resource.
Please note that with usage of server-snippet the path that you are blocking cannot be defined in ingress resource object. There is however another way with location-snippet via ConfigMap:
location ~* "^/web/admin {
deny all;
}
With this for every existing path in ingress object there will be ingress rule but it will be blocked for specific uri (In the example above it will be blocked when admin will appear after web). All of the other uri will be passed through.

Related

ingress-nginx: How to insert access_by_lua_block{} only for specific location?

I have multiple location blocks under a single host:, something like this:
apiVersion: networking.k8s.io/v1
kind: ingress
metadata:
name: ingress-nginx
annotations:
kubernetes.io/ingress.calass: nginx
ngnx.ingress.kubernetes.io/use-regex: "true"
ngnx.ingress.kubernetes.io/rewrite-target: /$2
spec:
ingressClassName: nginx
rules:
- host: ingress.mydomain.org.local
http:
paths:
- path: /app1(/|$)(.*)
pathType: Prefix
backend:
service:
name: app1-service
port:
number: 5678
- path: /api(/|$)(.*)
pathType: Prefix
backend:
service:
name: api-service
port:
number: 5678
I need to insert access_by_lua_block{...} only for one location, say: /api - how do I do that? I tried with ngnx.ingress.kubernetes.io\configuration-snippet, like this:
annotations:
ngnx.ingress.kubernetes.io\configuration-snippet: |
location ~* "^/api(/|$)(.*)" {
access_by_lua_block {
....
}
}
but that's just adding a nested location ~* "^/api(/|$)(.*)" block under every other location entries. Is there any way that can be achieved?
As suggested by #mdaniel ,the answer is always to create a 2nd Ingress resource when you need to apply annotations to just one of them.
The smooth coexistence of multiple Ingress Controllers in one cluster is provided by the Ingress class concept, which mandates the following:
Every Ingress Controller must only handle Ingress resources for its particular class.
Ingress resources should have the ingressClassName field set to the value, which corresponds to the class of the Ingress Controller the user wants to use.
VirtualServer, VirtualServerRoute, Policy and TransportServer resources should have the ingressClassName field set to the value, which corresponds to the class of the Ingress Controller the user wants to use.
Refer to this documentation for more information on Ingress resources.

nginx.ingress.kubernetes.io/server-snippet annotation contains invalid word location

I am new to kubernetes and using AWS EKS cluster 1.21. I am trying to write the nginx ingress config for my k8s cluster and blocking some request using server-snippet. My ingress config is below
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: abc-ingress-external
namespace: backend
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
kubernetes.io/ingress.class: nginx-external
nginx.ingress.kubernetes.io/server-snippet: |
location = /ping {
deny all;
return 403;
}
spec:
rules:
- host: dev-abc.example.com
http:
paths:
- backend:
service:
name: miller
port:
number: 80
path: /
pathType: Prefix
When I apply this config, I get this error:
for: "ingress.yml": admission webhook "validate.nginx.ingress.kubernetes.io" denied the request: nginx.ingress.kubernetes.io/server-snippet annotation contains invalid word location
I looked into this and got this is something related to annotation-value-word-blocklist. However i don't know how to resolve this. Any help would be appreciated.
Seems there's issue using location with some versions. The following was tested successfully on EKS cluster.
Install basic ingress-nginx on EKS:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.1.0/deploy/static/provider/aws/deploy.yaml
Note: If your cluster version is < 1.21, you need to comment out ipFamilyPolicy and ipFamilies in the service spec.
Run a http service:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/docs/examples/http-svc.yaml
Create an ingress for the service:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: http-svc
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/server-snippet: |
location = /ping {
deny all;
return 403;
}
spec:
rules:
- host: test.domain.com
http:
paths:
- path: /
pathType: ImplementationSpecific
backend:
service:
name: http-svc
port:
number: 8080
Return 200 as expected:
curl -H 'HOST: test.domain.com' http://<get your nlb address from the console>
Return 200 as expected:
curl -H 'HOST: test.domain.com' -k https://<get your nlb address from the console>
Return 403 as expected, the snippet is working:
curl -H 'HOST: test.domain.com' -k https://<get your nlb address from the console>/ping
Use the latest release to avoid the "annotation contains invalid word location" issue.
Alternatively, replacing nginx.ingress.kubernetes.io/server-snippet by nginx.org/server-snippets fixed the issue for me. See for instance here

routing wildcard domain to different paths in nginx ingress

how do I achieve something similar to this.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
ingress.kubernetes.io/rewrite-target: /c/{word-maching-wildcard}
name: some-route
namespace: prod
spec:
rules:
- host: "*.example.com" # {hello}.example.com -> hello.example.com/hello
http:
paths:
- backend:
serviceName: svc
servicePort: 8080
path: /
Is there any way to capture the matching word in the subdomain and append it in the path before routing to the upstream service.
From the official doc:
Regular expressions and wild cards are not supported in the
spec.rules.host field. Full hostnames must be used.
See: nginx-ingress-matching.
However I have found similar problem which advice to write your own controller that writes out an nginx config that uses $http_host in the appropriate proxy_pass or redirect lines.
Read more: wildcard-url-mapping.

strip_path and preserve_host attributes in KongIngress object. What do they do?

I have a KongIngress object configuration attributes regarding to Ingress resource which call to kong as an Ingress controller. I actually have this configuration:
apiVersion: configuration.konghq.com/v1
kind: KongIngress
metadata:
name: echo-site-ingress
namespace: hello-world
annotations:
kubernetes.io/ingress.class: "kong"
proxy:
protocols:
- http
- https
# path: /
route:
methods:
- POST
- GET
strip_path: true
preserve_host: true
---
#My Ingress resource
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
kubernetes.io/ingress.class: kong
plugins.konghq.com: helloworld-customer-acceptance-basic-auth, hello-world-customer-acceptance-acl
name: echo-site-ingress
namespace: hello-world
spec:
rules:
- host: hello-world.bgarcial.me
http:
paths:
- backend:
serviceName: echo
servicePort: 80
path: /
tls:
- hosts:
- hello-world.bgarcial.me
secretName: letsencrypt-prod
The questions are:
What are doing in my kind:KongIngress object resource the strip_path and preserve_host attributes?
I read the documentation here, but it is not clear for me:
Regarding to strip_path I see this one:
When matching a Route via one of the paths, strip the matching prefix from the upstream request URL. Defaults to true.
but as we can see, I am not using the path attribute inside my KongIngress object (I commented for illustration purposes about my question)
So, how strip_path attribute value is applied here?
It is because I am using in my Ingress resource the path: / attribute and my Ingress and my KongIngress resources are working together?
I really don't have a clue about it, but I would like to know how is this about behind scenes.
When preserv_host annotation is enabled the host header of the request will be sent as is to the Service in Kubernetes. Well explained in the documentation.
strip_path can be configured to strip the matching part of your path from the HTTP request before it is proxied.
If it is set to "true", the part of the path specified in the Ingress rule will be stripped out before the request is sent to the service. For example, when it is set to "true", the Ingress rule has a path of /foo and the HTTP request that matches the Ingress rule has the path /foo/bar/something, then the request sent to the Kubernetes service will have the path /bar/something.
So when you use curl $YOUR_HOST/foo/bar/something, under real path value in the output you will see /bar/something
And if set to false no path manipulation is performed and in your case can be changed to such as there is no manipulation to be done.

Is it possible to rewrite HOST header in k8s Ingress Controller?

Due to some legacy application that relies on Host header to function correctly, I need to have an Ingress (proxy, etc) that capable of rewrite Host header and pass that to downstream (backend). Is there any Ingress Controller that supports this functionality?
Example:
End user access our website through foo.com/a for backend a and foo.com/b for backend b. But since a and b are legacy app, it only accept:
a accepts connection when Host: a.foo.com
b accepts connection when Host: b.foo.com
This can be done using this annotation: nginx.ingress.kubernetes.io/upstream-vhost: host.example.com
I'm not sure whether you can find appropriate annotation within NGINX Ingress Controller for Host header modification to match your requirement as well. However, you can consider using nginx.ingress.kubernetes.io/configuration-snippet annotation in order to append configuration snippet to the location block inside nginx.conf of the particular Nginx controller pod:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/configuration-snippet: |
proxy_set_header Host www.example-host.com;
name: my-app
spec:
rules:
- host: my-app.example.com
http:
paths:
- backend:
path: /app
serviceName: my-app
servicePort: http
We set here Host header www.example-host.com for target URL my-app.example.com.
I want to add my finding to this question of mine.
Although my solution is not using k8s Ingress Controller, our cluster is using Istio and Istio's VirtualService supports rewrite the uri and authority (Host header) as documented in this link: https://istio.io/docs/reference/config/istio.networking.v1alpha3/#HTTPRewrite
To know how I implement that in my case, you can take a look at this link: https://github.com/istio/istio/issues/11668
you can use ingress nginx controller on Kubernetes and set head and also transfer to backend and manage services connection from ingress objects.
here sharing link for rewrite target from header: https://kubernetes.github.io/ingress-nginx/examples/rewrite/
ingress nginx will be also good with SSL cert manager you can add it.
manage other thing using annotations of ingress.
check this out for ingress SSL setup you can modify it and per your need: https://www.digitalocean.com/community/tutorials/how-to-set-up-an-nginx-ingress-with-cert-manager-on-digitalocean-kubernetes
ingress will be like at last
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
tls:
- hosts:
- myapp.abc.com
secretName: ingress-tls
rules:
- host: myapp.abc.com
http:
paths:
- path: /my-service
backend:
serviceName: my-backend
servicePort: 80

Resources