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

2/28/2019

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.

-- Jens
basic-authentication
kubernetes
kubernetes-ingress
nginx
nginx-ingress

2 Answers

5/19/2020

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
-- Dirbaio
Source: StackOverflow

3/6/2019

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.

-- flaixman
Source: StackOverflow