App Support.

We're here to help.



Setting up an OpenVPN server with Okta Single Sign-on Web Authentication and Viscosity

After setting up your own OpenVPN server, you may want to enhance it's security. One way to do that and streamline your authentication process is to use Single Sign-in or Single Sign-On (SSO), also sometimes referred to as SAML (This is an SSO protocol). This adds another security measure to prevent unwanted users connecting to your server while at the same time integrating with your existing user, identity or client management system or authentication process.

This guide provides an example of how this might work with Okta, a popular cloud-based identity platform. This example's basics translate to most Identity Management Systems (IDMS) with just changes to how you communicate with your IDMS of choice.

Please note this example is designed to show the basics of how an IDM or SSO system can integrate with OpenVPN on the server side, it is not designed to be used on it's own as-is.

Preparation

For this guide, we assume:

  • You have an Okta account (this guide will work with Okta's free trial)
  • You have already installed the latest LTS version of Ubuntu (22.04 at time of writing)
  • You have root access to this installation
  • You have public access to this System on port 80 and 443 for HTTP & HTTPS access, and a DNS A-NAME pointing to it (for example, openvpnsso.server.com)
  • You already have a copy of Viscosity installed on your client device and already setup for this server

Documentation for Okta can be found at https://help.okta.com/en-us/content/index.htm

Further Okta example can be found on their GitHub page at https://github.com/okta

This guide should only be used as an example for setting up SSO on your server. The provided Python Flask website is designed as an example only and is not intended for production use.

If you are starting from scratch with a fresh Ubuntu 22.04 install, this process from here to finishing should only take about 20 minutes.

Okta Setup

First, we need to configure Okta for the new website that will handle communication between OpenVPN and Okta.

  • Login to Okta on your admin account
  • On the left expand the menu, and go to Applications > Applications
  • Click Create App Integration
  • Select ODIC - OpenID Connect, then Web Application and click Next
  • Give your App integration name a name you'll recognise like 'My OpenVPN Server'
  • Ensure Authorization Code is the only option checked under 'Client acting on behalf of a user' under 'Grant type'
  • Replacing '<yourserver.com>' in the following, set your Sign-in redirect URIs to https://<yourserver.com>/authorization-code/callback
  • Optionally, again replacing '<yourserver.com>' in the following, set your Sign-out redirect URIs to https://<yourserver.com>/logout
  • Set Controlled access to your choice, for testing purposes if this is a trial account, just select Allow everyone in your organization to access
  • Click Save

After saving, the page will reload. Either keep this page open, or take a note now of the Client ID, Client secret, and Okta domain, we will need these later.



 

Server Setup

Next, we need to setup the server. In summary, we need an OpenVPN server ready to go, to install nginx as a proxy for the Python Flask application, make some small firewall changes, install an SSL certificate, configure the flask application and make some small changes to OpenVPN.

Server Preparation

First, login to your server via SSH or open a Terminal, and run the following to make sure everything is up to date

sudo apt update
sudo apt -y upgrade


OpenVPN Server Setup

First we will need an OpenVPN Server ready to go. If you don't already have one on this server, follow the Setting up an OpenVPN server with Ubuntu and Viscosity.

Once setup, ensure that you can connect.

Next, we need to add a few lines to the OpenVPN Server config:

  • Edit the configuration sudo nano /etc/openvpn/server.conf
  • At the end of the file, add the following:
management 127.0.0.1 50123
auth-user-pass-optional
management-client-auth
  • Press Ctrl+X, to exit, Y to save, then Enter to confirm the path
  • Restart the server with sudo systemctl restart openvpn@server

If you try to connect now, the connection should eventually fail with an authentication failed message.

Notes:

If you have an existing server that has any authentication scripts or plugins, these will need to be removed as SSO will replace them. Okta can be configured with 2FA options though we won't cover them in this guide, consult Okta's documentation.

Web Server Setup

Firewall

If you followed the Setting up an OpenVPN server with Ubuntu and Viscosity guide, first we need to open the firewall to allow HTTP & HTTPS traffic, run the following:

  • sudo ufw allow http
  • sudo ufw allow https
  • sudo ufw reload

Install ningx

Next we need to install nginx. nginx is a HTTP and reverse proxy server which will serve components of our web application out and enable the use of features like TLS/SSL. Do the following on your Ubuntu Server:

  • Run sudo apt -y install nginx
  • Edit sudo nano /etc/nginx/sites-enabled/default
  • Scroll down to the line server_name _;, and replace the underscore (_) with your server DNS name, for example myserver.com, so it looks like this - server_name myserver.com;
  • Press Ctrl+X, to exit, Y to save, then Enter to confirm the path
  • Reload nginx with sudo nginx -s reload


Setup Let's Encrypt

If you already have an SSL certificate for this section, you can skip to the next section. Otherwise, Let's Encrypt and Certbot make getting an SSL certificate simple.

  • Run sudo apt install -y certbot python3-certbot-nginx
  • Run the following, replacing myserver.com with your FQDN, and follow the prompts sudo certbot --nginx -d myserver.com. You can specify extra domains if you require them, for example sudo certbot --nginx -d myserver.com -d www.myserver.com -d sso.myserver.com.
  • It may take a few minutes for certbot to respond after answering prompts


Setup nginx

Now you have an SSL certificate, we can finish the nginx setup.

  • Edit sudo nano /etc/nginx/sites-enabled/default
  • Remove the following section:
location / {
  # First attempt to serve request as file, then
  # as directory, then fall back to displaying a 404.
  try_files $uri $uri/ =404;
}
  • Scroll down to after the lines # managed by Certbot, but before the }, and paste in the following:
  real_ip_header X-Real-IP;
  real_ip_recursive on;
  proxy_connect_timeout       600;
  proxy_send_timeout          600;
  proxy_read_timeout          600;
  send_timeout                600;

  location / {
    try_files $uri @proxy;
  }

  location @proxy {
    proxy_pass http://127.0.0.1:8080;
    proxy_pass_header Server;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_pass_header Server;
    proxy_connect_timeout 3s;
    proxy_read_timeout 10s;
  }
  • Press Ctrl+X, to exit, Y to save, then Enter to confirm the path
  • Reload nginx with sudo nginx -s reload


Web App Install

Now we can install the webapp and start it. We'll create a user to run the web application as it creates a bit more security. Run the following:

  • sudo apt install -y python3-pip Install python pip so we can install Flask dependencies
  • sudo adduser --system --no-create-home --group ssoappuser Create a user to run the webapp as
  • cd /home
  • sudo mkdir ssoapp
  • sudo chown ssoappuser:ssoappuser ssoapp
  • cd ssoapp
  • sudo git clone https://github.com/thesparklabs/openvpn-okta-sso-example.git Download the web application from GitHub
  • cd openvpn-okta-sso-example
  • sudo python3 -m pip install -r requirements.txt Install dependencies for the web application
  • sudo cp ssoapp.service /lib/systemd/system/ssoapp.service Install the service file
  • sudo chown root:root /lib/systemd/system/ssoapp.service
  • sudo systemctl daemon-reload

Web App Setup

Finally, we just need some quick setup work for the web application to work and talk to Okta. This is where you will need Client ID, Client secret, and Okta domain we gathered setting up Okta earlier.

  • Make a copy of the secrets template with sudo cp client_secrets.json.dist client_secrets.json
  • Create a random secret with the following and copy it openssl rand -hex 20
  • Edit the config with sudo nano client_secrets.json
  • Replace {{THIS_IS_A_SECRET}} with the random string we generated two steps ago
  • Replace {{OKTA_DOMAIN}} in auth_uri, issuer, token_uri and userinfo_uri with your Okta domain
  • Replace {{CLIENT_ID}} with your Client ID
  • Replace {{CLIENT_SECRET]] with your Client secret
  • Replace {{YOUR_DOMAIN}} with your server address, e.g. myserver.com
  • Press Ctrl+X, to exit, Y to save, then Enter to confirm the path
  • Reload nginx with sudo nginx -s reload

We can now enable and start the application service with

  • Enable the service to start when the system does sudo systemctl enable ssoapp
  • Start the service sudo systemctl start ssoapp

Client Setup

If you have followed this guide through including using our Setting up an OpenVPN server with Ubuntu and Viscosity guide, there is nothing you need to do, simply connect with Viscosity.

If you have modified an existing server, the only change you will need to make is to turn off user/password authentication if it is on. To do this, edit the connection, go to Authentication and uncheck "User Username/Password authentication", Save the connection and connect.


 

Auth Tokens

OpenVPN auth-gen-token

The example application includes support for auth-gen-token. As we are not using username/password via OpenVPN, this needs to be handled via the management interface. To enable it, simply add auth-gen-token 0 external-auth to your server configuration.

Okta Token Refresh

The above example can be extended to use Okta tokens instead of OpenVPN's auth-tokens for reauthentication. We will not provide an example of this as OpenVPN's built in support will cover the vast majority of setups.

However, if you do wish to use Okta instead, here are the main things to keep in mind:

  • You will need to modify the clientAllow function reply to push your auth-token.
  • You will need to modify the clientReauth function to take the password from the client environment that is passed via the management interface, follow Oktas documentation to refresh this token, then send a client-auth reply similar to clientAllow including the refreshed token.
  • You will need to modify the server and client configuration to ensure that the reneg-sec is less than the expiry of the Okta tokens