Skip to content

Commit 43a76f5

Browse files
committed
Document an Nginx config for OIDC authentication
1 parent 5c104d0 commit 43a76f5

File tree

1 file changed

+108
-10
lines changed

1 file changed

+108
-10
lines changed

README.md

Lines changed: 108 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@
33
[![Build Status](https://app.travis-ci.com/elonen/ldap_authz_proxy.svg?branch=master)](https://app.travis-ci.com/elonen/ldap_authz_proxy)
44
[![Release](https://img.shields.io/github/v/release/elonen/ldap_authz_proxy?include_prereleases)]()
55

6-
Authorize Nginx users against LDAP, optionally returning attributes.
6+
Secure any HTTP resource (static site, a web app, ...) with LDAP / Active Directory.
7+
That is, trasparently authorize Nginx users against LDAP, optionally returning attributes.
78

8-
Once a user has been authenticated by some other means (e.g. Kerberos, Basic auth, Token, ...),
9+
Once a user has been authenticated by some other means (e.g. OIDC, Kerberos, Basic auth, Token, ...),
910
this server can be used to authorize them to access some resource.
1011

1112
If one LDAP/Active Directory query is not enough, the program can perform sub-queries to
@@ -116,7 +117,7 @@ Corresponding **Nginx** configuration block would look roughly like this -- assu
116117
}
117118
```
118119

119-
(See a more complete example below.)
120+
(See more complete examples below.)
120121

121122
## Cache
122123

@@ -139,11 +140,12 @@ was served from cache, and `0` if it was a fresh query.
139140
The server is written in Rust and can be manually built with `cargo build --release`.
140141
Resulting binary is `target/release/ldap_authz_proxy`.
141142

142-
If you want Debian packages, see below.
143+
If you want Debian packages instead (recommended), see below.
143144

144145
## Running
145146

146-
The server can be run with `ldap_authz_proxy <configfile>`. Additional
147+
The recommended way to run the server is through a process manager (e.g. systemd),
148+
but it can also be run manually like this: `ldap_authz_proxy <configfile>`. Additional
147149
options are available (`--help`):
148150

149151
```
@@ -182,8 +184,8 @@ Options:
182184
-v --version Show version.
183185
```
184186

185-
The executable stays in foreground, so it's recommended to run it
186-
with a process manager such as `systemd` or `supervisord`. Example
187+
The executable stays in foreground, which is why it's recommended to use a
188+
process manager such as `systemd` or `supervisord`. Example
187189
`systemd` service file is included in `debian/service`.
188190

189191
## Security
@@ -218,7 +220,7 @@ This is the recommended way to install this on Debian systems.
218220
## Testing
219221

220222
Use `./run-tests.sh` to execute test suite. It requires `docker compose`
221-
and `curl`. The script performs an end-to-end integratiot test with a
223+
and `curl`. The script performs an end-to-end integration test with a
222224
real Active Directory server and an Nginx reverse proxy.
223225

224226
It spins up necessary containers, sets up example users, and then performs
@@ -246,7 +248,7 @@ server {
246248
server_name www.example.com;
247249
248250
249-
satisfy all; # Require 2 auths: auth_gss (Kerberos) for authn and auth_request (LDAP proxy) for authz
251+
satisfy all; # Require 2 auths: auth_gss (Kerberos) for authn and auth_request (ldap_authz_proxy) for authz
250252
251253
auth_gss on;
252254
auth_gss_keytab /etc/krb5.keytab;
@@ -293,6 +295,102 @@ The VM running Nginx (and ldap_authz_proxy) was joined to AD domain like this:
293295
Script(s) for building Nginx Kerberos (SPNEGO) module for Debian:
294296
https://github.com/elonen/debian-nginx-spnego
295297

298+
299+
### OpenID Connect (OIDC, e.g. Okta)
300+
301+
This example uses [Vouch Proxy](https://github.com/vouch/vouch-proxy) to authenticate against
302+
an OIDC ID provider (e.g. Okta), and then ldap_authz_proxy to authorize. Again, both authn and authz
303+
happen transparently on Nginx level; the application itself doesn't know anything about LDAP, OIDC or auth tokens.
304+
305+
This configuration is a bit more complex than the previous ones, because it needs to
306+
perform two `auth_request` calls: one for OIDC authentication and another for LDAP authorization.
307+
Nginx doesn't allow multiple `auth_request` calls in the same location, so we need to
308+
authenticate first, then proxy to another location that performs the authorization and finally
309+
serves the actual application.
310+
311+
(This doesn't cover Vouch Proxy setup, see other docmentation for that.)
312+
313+
```nginx
314+
# Phase 1: Authenticate and proxy to Phase 2
315+
server {
316+
listen 443 ssl;
317+
ssl_certificate /etc/ssl/private/example.com.fullchain.pem;
318+
ssl_certificate_key /etc/ssl/private/example.com.privkey.pem;
319+
320+
server_name my-app.example.com;
321+
322+
error_page 401 = @error401;
323+
location @error401 {
324+
return 302 https://vouch.example.com/login?url=https://$http_host$request_uri;
325+
}
326+
327+
location = /authn {
328+
internal;
329+
330+
proxy_pass https://vouch.example.com/validate;
331+
proxy_pass_request_body off;
332+
proxy_set_header Cookie $http_cookie;
333+
proxy_set_header Content-Length "";
334+
335+
# If Vouch Proxy JWT validation returns 401, the error_page above will redirect to login page
336+
}
337+
338+
location = / {
339+
# Authn against Vouch Proxy and store results in variables:
340+
341+
auth_request /authn;
342+
auth_request_set $authn_jwt $upstream_http_x_vouch_jwt;
343+
auth_request_set $authn_user $upstream_http_x_vouch_user;
344+
345+
# Pass authenticated username to phase 2:
346+
347+
proxy_pass http://127.0.0.1:8000;
348+
proxy_set_header X-Authn-User $authn_user;
349+
}
350+
}
351+
352+
# Phase 2: Authorize and serve the application
353+
server {
354+
listen 127.0.0.1:8000;
355+
356+
location = /authz {
357+
internal;
358+
proxy_pass http://127.0.0.1:10567/ldap_authz_example_app;
359+
proxy_pass_request_body off;
360+
proxy_set_header Content-Length "";
361+
proxy_set_header X-Ldap-Authz-Username $http_x_authn_user;
362+
}
363+
364+
location / {
365+
# Authz against ldap_authz_proxy.
366+
# Note that we already set X-Ldap-Authz-Username in phase 1, from where
367+
# ldap_authz_proxy reads it.
368+
369+
auth_request /authz;
370+
auth_request_set $ldap_displayname $upstream_http_x_ldap_res_displayname;
371+
auth_request_set $ldap_groups $upstream_http_x_ldap_res_pdugroups;
372+
373+
374+
# Example app: PHP script that gets, in headers, username from Vouch,
375+
# and display name + groups from ldap_authz_proxy.
376+
#
377+
# You could replace this with another proxy_pass to a different app,
378+
# or even just serve your top secret static files.
379+
380+
root /var/www/my-app;
381+
index index.php;
382+
try_files $uri $uri/ =404;
383+
location ~ \.php$ {
384+
include snippets/fastcgi-php.conf;
385+
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
386+
fastcgi_param X_REMOTE_USER_ID $http_x_authn_user;
387+
fastcgi_param X_USER_GROUPS $ldap_groups;
388+
fastcgi_param X_DISPLAY_NAME $ldap_displayname;
389+
}
390+
}
391+
}
392+
```
393+
296394
## Config option details
297395

298396
Configuration options (generated by `ldap_authz_proxy --help-config`):
@@ -431,7 +529,7 @@ Config options:
431529
Probably the easiest way to develop this is to spin up the LDAP server
432530
in Docker and then run program locally:
433531

434-
```bash
532+
```bash
435533
# Start test LDAP server
436534
cd test
437535
docker compose up --detach

0 commit comments

Comments
 (0)