Skip to content
/ kvauth Public

Lightweight, dynamic nginx IP/host allowlist that can be built on top of any Redis-compatible key-value store.

License

Notifications You must be signed in to change notification settings

ropsec/kvauth

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

kvauth

This is a lightweight, dynamic nginx IP/host allowlist that can be built on top of any Redis-compatible key-value store.

Having to systemctl reload nginx everytime you make a change to a list of allowed IPs, especially for a very dynamically permissive application, is a lot of overhead. kvauth attempts to solve this.

Nginx Plus offers the ngx_http_keyval_module which can be used to setup a dynamic allowlist. However, this is only offered with a paid subscription.

How it works

Your custom application will populate a Redis-compatible database with hashmaps containing allowed hostnames for specific requesting IPs.

Say you want to allow the requesting IP 1.1.1.1 to access mywebsite.com. Just create a key for 1.1.1.1 with the field mywebsite.com set to 1:

$ redis-cli
127.0.0.1:6379> hset 1.1.1.1 mywebsite.com 1

With a properly configured nginx, your website at mywebsite.com will check to see if the requesting IP is allowed to access it through kvauth. If access is not allowed, the requester will receive a 401 Unauthorized response. This all relies on nginx's auth_request directive (a better example of this kind of flow for LDAP authentication can be found here).

Since a Redis-compatible database is used on the backend, you can optionally set expiration times for IP access for short-lived grants.

Running the example

This repo contains an example setup that you can activate using docker compose up --build.

That will start a web service at http://127.0.0.1:8080/ that is protected by kvauth.

While the containers are running, visit the page to see the unauthorized message.

In the docker logs, you will see nginx spit out your requesting IP:

nginx-1   | 192.168.65.1 - - [30/Dec/2025:18:10:55 +0000] "GET / HTTP/1.1" 401 179 "-" "Mozilla/5.0 ..."

Run the example allow-ip.sh script to temporarily allow your 192.168.65.1 IP to 127.0.0.1:

# arguments are: [requester IP] [target host] [optional expiration time (in seconds)]
$ ./allow-ip.sh 192.168.65.1 127.0.0.1 20

You will then be able to access the page for the next 20 seconds.

Usage

Build kvauth from this repo's root directory:

$ make

In nginx

On your front-facing nginx server, drop the provided kvauth.conf file in /etc/nginx/includes.

Then, in your nginx site's server {} block, include the kvauth.conf file and protect your desired locations with an auth_request /kvauth;:

# example protected webserver running at port 9000
upstream protectedsite {
    server 127.0.0.1:9000;
}

server {
    listen 80;

    server_name mywebsite.com;
    # sets up kvauth authentication endpoint
    include /etc/nginx/includes/kvauth.conf;

    location / {
        # protect the whole site with kvauth
        auth_request /kvauth;
        # if kvauth succeeds, forward the user to the protected endpoint
        proxy_pass http://protectedsite/;
    }
}

Configuring kvauth

Stand up a Redis-compatible database and create a config file for kvauth with the host, port, and optional database number, username, and password:

kvdb:
  host: 127.0.0.1
  port: 6379
  # db: 0
  # username: testuser
  # password: secret-password

For this example, let's say this config file is at /kvauth.yml. You can optionally drop it at /etc/kvauth/config.yml and kvauth will automatically detect it without specifying a location on the command line.

Run kvauth and point at your config file:

$ ./bin/kvauth -c /kvauth.yml

This will run kvauth at 127.0.0.1:8888. You can easily change the port to something like 9999 by specifying -p 9999 in the kvauth command, then modifying this line in kvauth.conf:

- proxy_pass http://127.0.0.1:8888;
+ proxy_pass http://127.0.0.1:9999;

Once everything is up and running, you can now setup whatever application or automation you need to populate and manage the allow list within your Redis-compatible database.

If you want persistent allowlists within your database, you will need to configure your desired provider (Valkey, Redis, KeyDB) to do so.

Using the L1 Cache

By default, the L1 Cache is disabled since it may get out of sync with the database. If an administrator removes an entry from the backend database but the L1 cache containing the old TTL still exists, kvauth will still let that IP in.

Since this is a semi-dangerous option, you must manually enable it with --enable-l1-cache. Once enabled, if any manual database deletion/expiration occurs, it is good practice to send a SIGHUP to the kvauth process. This will completely clear out the L1 cache, allowing it to repopulate as requests are made again.

Using the L1 cache speeds up authenticated requests significantly since a network connection to the underlying database is not occurring. Only found entries in the database are added to the cache. A cache miss still makes a request to the database.

If a database entry does not have a TTL, the duration (in seconds) specified by --l1-default-duration is used. By default, this value is set to 5 minutes.

In the example docker-compose.yml, you can see the KVAUTH_ARGS environment variable is set to enable the L1 cache. This is so you can easily see this speed difference.

About

Lightweight, dynamic nginx IP/host allowlist that can be built on top of any Redis-compatible key-value store.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published