Based on Debian 11 "Bullseye" environment.

SSO with NGINX and Vouch Proxy

These configuration examples are based on the article "Use nginx to Add Authentication to Any Application" with some updates and additions.

In this way, you can enable OpenID Connect (OIDC) or AzureAD authentication with NGINX and Vouch Proxy. You don't need to implement the login mechanism for each application running behind the NGINX reverse proxy. In addition, user management can be completed on the ID management provider side (not within each application).

Prerequisites

System requirement

  1. NGINX with "auth_request" module
    • auth_request is included in any NGINX flavors of Debian package.
  2. Quay.io or golang environment
    • Vouch Proxy is not available as Debian package, but it offers a docker image through Quay.io.
      (Docker images on Docker Hub are outdated. Vouch-Proxy has moved to Quay.io)
    • Compiling from the source is another option if you like.

The case

These examples are based on the case below.

  • The application is running on "app.example.com"
    • There can be app2, app3, and more
  • Vouch Proxy server is on "vouch.example.com"
  • All sites (applications) are connected via HTTPS
    • Using HTTP will affect the Vouch Proxy configurations
  • Using Okta or AzureAD for SSO gateway.

Vouch Proxy is compatible with many kinds of ID providers, such as GitHub and Google. Please have a look at the official examples for them.

Okta application

Okta offers the developer account for testing (free of charge for up to 1,000 monthly active users). Visit developer.okta.com to start testing with this account.

The application should be set up according to the blog post.

  • This application doesn't show up in the User Home
  • To use this app as an authenticator, users have to visit directly to the application URL, not the Okta dashboard. (Then NGINX will redirect to the Vouch, Vouch will redirect to Okta.)

Azure AD application

In case you want to use AzureAD for the ID Provider, please contact your organization's Azure AD admin to make an application.


Set up Vouch Proxy

The easiest way to start Vouch Proxy is the docker image. To use the image, you'd better use NGINX as a reverse proxy.

Configure the NGINX site as a reverse proxy

Make a site configuration in /etc/nginx/sites-available and enable it. This will work as a reverse proxy to pass the connection to Vouch Proxy

Prepare configuration

Make /etc/vouch/config directory and store the following sample. This is based on the config example on the official site.
(keep the filename as config.yml)

Okta

AzureAD

Starting Vouch Proxy for the first time  (or upgrading)

Pull the docker image from Quay.io and run it with the prepared config file.

# docker run -d -p 9090:9090 --name vouch-proxy -v /etc/vouch/config:/config quay.io/vouch/vouch-proxy
  • "-d" to use detached mode (run in the background)
  • "-p 9090:9090" to connect port 9090 to the docker image 9090. If you want to use port 1090 redirected to Vouch Proxy, the option should be "-p 1090:9090"
  • "--name vouch-proxy" to use a short name to handle the image
  • "-v /etc/vouch/config:/config" to let the image use /etc/vouch/config host directory as /config directory

Stop and Start the image

Once the image is started with the command above, the image can be handled with the name "vouch-proxy"

# docker stop vouch-proxy
# docker start vouch-proxy

If you change config.yml, then you need to restart the image to reload it.

Remove image

When you want to upgrade, remove the image before pulling the latest docker image.

# docker rm vouch-proxy
# docker rmi quay.io/vouch/vouch-proxy

Then redo the initial docker run command above to pull the latest image and run.


Set up the application site

Set the NGINX as a reverse proxy, and let it redirect to the Vouch Proxy using the auth_request module.

Prepare the snippet for authentication

To reuse in the multiple sites, prepare a snippet in /etc/nginx/snippets

Configure the application site

Set up a site for "app.example.com" in /etc/nginx/sites-available

  • "snippets/ssl_example.com.conf" is a snippet to configure the ssl certificates and other related configurations.
  • user information is available with the following codes
    • PHP: $_SERVER['REMOTE_USER']
    • Ruby on Rails: request.env["HTTP_REMOTE_USER"]
    • Ruby Sinatra: same as above

Enable configurations

Reload NGINX to enable the site configurations.

# systemctl reload nginx

Tips

Logs for troubleshooting

There should be some hints on the logs.

NGINX logs are located in /var/log/nginx/
Vouch Proxy logs are available with the following command.
To get more logs (debug log) for Vouch Proxy, set vouch.jwt.logLevel to "debug" in config.yml.

# docker logs vouch-proxy

If you want to follow the logs like tail command, add --follow option.

# docker logs --follow vouch-proxy

allowAllUsers

The default configuration offers to specify the domains. Here is the difference.

Specifying the domains.

  • Application: app.example.com
  • Vouch Proxy: vouch.example.com
  • Users' mail addresses: name@mail.example.jp

With the above situation, the configuration should look like below.

vouch:
  domains:
  - example.com
  - example.jp

If the users' mail addresses have a variety of domains, you have to list all of them to permit access.
This can be used to restrict the users with the specific mail domains by extracting them in the configuration, but that kind of management should be controlled on the OIDC provider side.

Instead of listing the domains, use "allowAllUsers: true" to accept anybody who is allowed on the OIDC provider side.
Even if you prefer this type, you still need to specify which domain to be used for the cookies. This will be the domain to be protected, i.e., callback and application domain.

vouch:
  allowAllUsers: true
  cookie:
    domain: example.com

Skipping the check

With the configuration explained on this page, any access will be checked. This means the batch jobs from the localhost will be redirected to the check, too.
For example, if a cronjob accesses the protected site with the headless chromium, it will still be redirected to the authentication (and probably that job will fail).

I couldn't find a good way to set the exception of accesses on NGINX or Vouch Proxy, this can be solved by opening another port for the HTTPS service.

Port 443 for any inbound HTTPS access

  • This connection requires the authentication

Port 1443 for the HTTPS only from the localhost

  • This connection doesn't require the authentication
  • The firewall will block the inbound access to this port except for the localhost loopback

Both ports redirect to the backend application, but 1443 doesn't require authentication and is only available for local loopback access.

Directly connecting to the backend port is another solution, only if the application uses the TCP port. (This is useful if the backend runs on the docker, but many native applications may use Unix sockets...)

Less frequent authentication

If you feel there are too frequent redirections to the OIDC provider, you can extend the expiration of jwt.
Extend vouch.jwt.maxAge as well as vouch.cookie.maxAge.
In my case, it's 900 minutes (15 hours) to aim for the "once a day on the business hours" frequency.

vouch:
  cookie:
    maxAge: 900
  jwt:
    maxAge: 900

Get IdToken information (AzureAD)

In the ID Token from AzureAD, there are several pieces of information other than the user ID (email address). For example, "name" may have the full name with the division of the user. The application can get this information through Nginx.

Add headers in config.yml

vouch:
  (snip)
  headers:
    idtoken: X-Vouch-IdP-IdToken

Add another auth_request_set in snippets/vouch.conf

auth_request_set $auth_user $upstream_http_x_vouch_user;
auth_request_set $auth_resp_x_vouch_idp_idtoken $upstream_http_x_vouch_idp_idtoken;

If the application is PHP, add another fastcgi_param.

fastcgi_param REMOTE_USER $auth_user;
fastcgi_param REMOTE_IDTOKEN $auth_resp_x_vouch_idp_idtoken;

If the application is the backend over the proxy, add another proxy_set_header.

proxy_set_header Remote-User $auth_user;
proxy_set_header Remote-Idtoken $auth_resp_x_vouch_idp_idtoken;

The ID Token format is "jwt"
Use a dedicated tool to decode full data on it, or you can decode only the payload manually.

An encoded jwt has three sections, header, payload, and signature, separated by ".(period)". Each part is Base64 encoded json string.
So splitting them with periods, get the second section (payload) and decode it to get the payload in json format.


Update History

2022-11-08

  • Correct some sentences
  • Add configuration for AzureAD case
  • Add how to get ID Token information