basic auth / ip filter only for path that contain special character in Ingress NGINX - nginx

I want my Ingress (NGINX) to filter by source IP address and show a basic auth before proxying to a service. While this is straightforward, the complicated part is, that I want it to do this only, if the URL contains a special character in the path.
Lets say I want to secure all paths that start with a "+" before proxying them to the correct service. On the other hand I still want that paths that do not start with a "+" will be routed (without basic auth) to the same service. It should also not change the URL that the service will see.
Examples would be:
/serviceA/what/ever -> http://192.168.0.2/what/ever
/serviceA/what/+ever -> BASIC_AUTH -> http://192.168.0.2/what/+ever
/serviceB/what/ever -> http://192.168.0.3/what/ever
/serviceB/+what/ever -> BASIC_AUTH -> http://192.168.0.3/+what/ever
Is it possible to achieve this either in Ingress or at least in a NGINX config?
The regex for the URL path is also quite simple in NGINX but is it possible without duplicating all path entries and also without adding a second proxy nginx in front?
The ideal solution would be in Ingress yml config but I'm more familar with NGINX, so here is an example what I want to achieve in NGINX-Syntax:
Location ~ /+ {
auth_basic ...;
auth_basic_user_file ...;
< route it somehow to the similar location as it would have no +, but don't cut out the + >
}
Location /serviceA {
proxy_pass ...;
}
... more Locations ...
Or in Ingress something similar with path-entries.

First of all, your:
location ~ /+ {
auth_basic ...;
auth_basic_user_file ...;
< route it somehow to the similar location as it would have no +, but don't cut out the + >
}
Would only match servicex/+something , not the servicex/something/+nice
The regex you are searching is something like:
location ~ ^/(.*)\+(.*) for the "+" to be anywhere
location ~ ^(.*)\/\+(.*) for the "+" to be only after a "/"
For the part:
< route it somehow to the similar location as it would have no +, but don't cut out the + >
Like this you'll send the uri exactly like it came:
proxy_pass http://192.168.0.2$request_uri;
And like this you'd take out the "+"
proxy_pass http://192.168.0.2$1/$2;
Where $1 is the (.*) before the /+ and $2 is everything after, and we add the lacking / in the middle.
I think that will help you on what I think you want to do.
If you have any questions ask them, I feel I'm lost at some part of your explanation and my answer is not 100% on point.
Hope I helped.

You can use nginx regexes in yaml path fields.
To have auth in one and not in the other, you have to create 2 ingresses (since the auth annotations are per-ingress, not per-path). Having 2 ingresses for the same host is perfectly OK, nginx-ingress will merge them.
Something like this should work:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: without-auth
spec:
rules:
- host: example.com
http:
paths:
- path: /
backend:
serviceName: your-backend-service
servicePort: 80
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: with-auth
annotations:
# type of authentication
nginx.ingress.kubernetes.io/auth-type: basic
# name of the secret that contains the user/password definitions
nginx.ingress.kubernetes.io/auth-secret: basic-auth
# message to display with an appropriate context why the authentication is required
nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required - foo'
nginx.ingress.kubernetes.io/use-regex: "true"
spec:
rules:
- host: example.com
http:
paths:
- path: ^/+
backend:
serviceName: your-backend-service
servicePort: 80
To debug if it doesn't work, or to check the result matches your expectations, you can view the generated nginx config like this (replace namespace and pod name with yours).
kubectl -n nginx-ingress exec nginx-ingress-controller-76458655df-sddg2 -- cat /etc/nginx/nginx.conf

Related

Using Nginx path prefix as a Kubernetes Ingress, breaks everything under subpaths even when using rewrite-target

This example is specifically about Nextcloud, although I had the same (unsolved issue) in the past with others.
What I simply want to do, is to access nextcloud under www.myserver.com/nextcloud.
I am able to kind of accessing Nextcloud front page with my present setup, but everything that's not directly under the basepath, is broken. Images and JS for instance.
Sure enough, I can manually enter in my browser web address something like www.myserver.com/nextcloud/core/css/guest.css, and it's there. But the issue is that the front page from Nextcloud, tries to access everything under: www.myserver.com/core/css/guest.css
Here is my ingress:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nextcloud
namespace: homeserver
annotations:
kubernetes.io/ingress.class: nginx
cert-manager.io/cluster-issuer: letsencrypt-staging
nginx.ingress.kubernetes.io/configuration-snippet: |
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $http_connection;
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
rules:
- host: www.myserver.com
http:
paths:
- path: /nextcloud(/|$)(.*)
pathType: Prefix
backend:
service:
name: nextcloud
port:
number: 80
You should have to use the relative path in backend or HTML if you are using that.
However you can do one thing
if your all request getting by the application at : www.myserver.com/core and there is no other folder exist or endpoint
you can create some redirection rules like :
www.myserver.com/core -> www.myserver.com/nextcloud/
once redirect redirected to new URL further another ingress that you have created will take care of the path and serve.
Ingrss example
metadata:
name: ingress-test
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/enable-rewrite-log: "true"
nginx.ingress.kubernetes.io/location-snippet: |
location = /core/ {
proxy_pass http://[hostname]/nextcloud/;
}
spec:
still, it depends on your application config and structure.
Well, there is no general solution as the problem is not on the Ingress configuration side itself; the problem is, as you noticed, that your application is generating link for dependencies using absolute path /, (like /core/css etc.) which of course is not working as Ingress does not have definition for /core/css etc. The dependencies are available under /nextcloud/core/css path. Your app is not aware that it is running under /nextcloud. Ingress can't change calls that are made from inside the application, you must configure properly your application.
How to resolve it in proper way? Fix your application. Configure it to use proper basepath (by passing proper environment variable) or to use relative paths. Some examples:
mongo-express has a ME_CONFIG_SITE_BASEURL environment variable
ASP.NET Core application can be written with possibility to load environment variable which will be base path
Set HTML file to use relative paths

kubernetes nginx ingress controller rewrites

We have deployed a mockserver on kubernetes. Currently, we only have one hostname which is shared by couple other applications (using a different path). However, the dashboard is not working because of the css location. What's the best way to solve this problem?
Failed to load resource: the server responded with a status of 404 (), hostname/mockserver/dashboard/static/css/main.477cab2a.chunk.css
The ingress manifest:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
app.kubernetes.io/instance: mock-server
kubernetes.io/ingress.class: nginx-ingress-protected
nginx.ingress.kubernetes.io/rewrite-target: /$2
name: mock-server-ingress
namespace: my-namespace
spec:
rules:
- host: hostname
http:
paths:
- backend:
serviceName: mock-server-svc
servicePort: 80
path: /testing(/|$)(.*)
This works fine if I request resource like hostname/testing/mockserver/expectation, the rewrites will be sending /mockserver/exepctation to the backend.
However, if for path hostname/testing/mockserver/dashboard, it is a html page which will loads hostname/mockserver/dashboard which doesn't exist. I can't wrap my head around this. Should I create another ingress with path /mockserver just to serve the css?
Your rewrite is working as expected. However,
there are some options you can choose from:
Create a second rule for the /mockserver (the simplest solution).
Play with capture groups:
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.
Use a paid solution.
The easiest would be to go for option 1 and create a second rule which would satisfy the path for the css.

Nginx rewrite-target overwritting domain/suffix/index.php to domain/index.php

recently I have deployed an kubernetes cluster which is running wordpress instance and phpmyadmin. I'm using Nginx ingress controller to perform path based routing for both the services. However, request to / is happening without any hassle but when I request domain.com/phpmyadmin/ I get a login page after which I have been redirected to domain.com/index.php instead of domain.com/phpmyadmin/index.php. Please suggest me possible turn around for this. Thank you guys for the support :)
My ingress.yaml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: ingress-nginx
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/ssl-redirect: "false"
nginx.ingress.kubernetes.io/add-base-url : "true"
nginx.ingress.kubernetes.io/rewrite-target: "/$2"
# ingress.kubernetes.io/rewrite-target: "^/phpmyadmin/"
spec:
rules:
- host: example.domain.com
http:
paths:
- path: /
backend:
serviceName: wordpress
servicePort: 80
- path: /phpmyadmin(/|$)(.*)
backend:
serviceName: phpmyadmin
servicePort: 80
I'd say issue is not on Nginx Ingress side.
nginx.ingress.kubernetes.io/rewrite-target: "/$2"
...
- path: /phpmyadmin(/|$)(.*)
Should work properly for you.
However there is second part, configuration of myphpadmin. As you didn't provide this configuration I would guess what could cause this issue.
Like mentioned in phpmyadmin docs, sometimes you need to set $cfg['PmaAbsoluteUri']
In some setups (like separate SSL proxy or load balancer) you might have to set $cfg['PmaAbsoluteUri'] for correct redirection.
As I based on this configuration, many depends on how you configured PMA_ABSOLUTE_URI, is it http://somedomain.com/phpmyadmin or different?
Is important as you might encounter situation like:
When you enter to http://somedomain.com/phpmyadmin and login you will be redirected to http://somedomain.com/ so Ingress will redirect you to path: / set in ingress
If you will again enter http://somedomain.com/phpmyadmin you will be able to see phpmyadmin content, like you would be already logged in.
You could try to add env in your myphpadmin deployment. It would look similar like below:
env:
- name: PMA_ABSOLUTE_URI
value: http://somedomain.com/myphpadmin/
Last thing, its not recommended to use expose phpmyadmin without https.
For some extra information you can read this article.
In short:
Nginx ingress configuration looks ok
Check your myphpadmin configuration, especially PMA_ABSOLUTE_URI.

Kuberentes Ingress rate lmiting altering rewrite-target base

I have an Ingress file which contains only one annotation:
---
apiVersion: "extensions/v1beta1"
kind: "Ingress"
metadata:
name: "logging-microservice-ingress"
namespace: "000000001"
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
-
host: "ms-shared-nad.techmahindra.com"
http:
paths:
-
backend:
serviceName: "logging-microservice-000000001"
servicePort: 3000
path: "/logging-microservice"
When I call https://example.com/logging-microservice/logs backend service generates,
GET /logs --> 200
When I added two more annotations like
nginx.ingress.kubernetes.io/limit-connections: 1
nginx.ingress.kubernetes.io/limit-rps: 1
backend gives
GET /logging-microservice/logs --> 404
I don't have access to see the actual nginx configuration being generated there. But, wondering how applying rate limiting can alter the rewrite base.
I have tried rate limiting in open source nginx server and it works as expected. What could be the change to remove path from the url which is passed to the upstream api backend?
Update :
I have accessed the cluster and record the changes happening:
location ~* "^/logging-microservice" {
rewrite "(?i)/logging-microservice" / break;
}
location ~* "^/" {
}
is changing to
location /logging-microservice {
}
location / {
}
when rate limiting annotations are added.
Even if you were given with Ingress.yaml with
nginx.ingress.kubernetes.io/rewrite-target: /
and everything was working fine, you need it like
nginx.ingress.kubernetes.io/rewrite-target: "/"
Other thing is, order of annotations matters;
it can't be :
nginx.ingress.kubernetes.io/rewrite-target: "/"
nginx.ingress.kubernetes.io/limit-connections: "1"
nginx.ingress.kubernetes.io/limit-rps: "1"
it should be :
nginx.ingress.kubernetes.io/limit-connections: "1"
nginx.ingress.kubernetes.io/limit-rps: "1"
nginx.ingress.kubernetes.io/rewrite-target: "/"
learned the hard way!

Kubernetes Ingress controllers for wildcard url mapping

I need for each of my users to access a service at a custom url eg. abccompany.mycloudapp.com , each service being a kubernetes service I'm looking at ingress controllers but I need a way to use a wildcard host field and somehow read the value into the path: and service: fields ; here's a sample ingress controller of what I have in mind:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test
spec:
rules:
- host: *.bar.com
http:
paths:
- path: /{{ value of * in * .bar.com }}
backend:
serviceName: {{value of * in *.bar.com }}Svc
servicePort: 80
If you use the stock controllers you will be able to switch on hostname and go to different backends services. It sounds like you don't want to enumerate all the subdomains -> service mappings, in which case you probably need to write your own controller that writes out an nginx config that uses $http_host in the appropriate proxy_pass or redirect lines. Give it a shot (https://github.com/kubernetes/contrib/tree/master/ingress/controllers) and file bugs in that same repo if you need help.

Resources