Enable MFA on pfSense IKEv2 VPN Using Duo

Frank Ye
12 min readJan 26, 2022

Working from home has become a popular trend during the COVID-19 pandemic. However, with more employees having to access corporate infrastructure remotely, it poses increased security risk to the company. As a result, companies are elevating their security requirements, one of them being Multi-Factor Authentication (MFA) for remote access (e.g. VPN).

I was tasked with adding MFA to our existing IKEv2 VPN (see this blog for how it was set up). After some research plus trial-and-error, the following solution was adopted.

  1. A new Ubuntu 20.04 LTS server was set up as the authentication server. FreeRADIUS was installed on this server to provide centralized user authentication.
  2. The Duo proxy was installed on the authentication server as well. It will intercept the normal RADIUS requests from the pfSense server, send it to FreeRADIUS to verify credentials, while adding another MFA request to the Duo server. Only when both FreeRADIUS and Duo MFA server responded with positive reply would the original RADIUS request be allowed to proceed.
  3. The pfSense IPSec settings were updated to using the Duo proxy for user authentication, from the original setup of using its built-in EAP. This allowed the MFA process to be added into the authentication process.

In the following sections I will document the steps I took in setting up each of the components.

Installing and Configuring FreeRADIUS

On a freshly installed Ubuntu 20.04 LTS server, run the following commands to install the FreeRADIUS server.

sudo apt-get update
sudo apt-get install freeradius

This should install FreeRADIUS executable into the /usr/sbin folder and put its configuration files in the /etc/freeradius/3.0 folder.

FreeRADIUS is a very powerful and flexible software. You can find its full documentation here. Luckily, most of its default settings are “good enough” for our purpose. That said, there are still a few mandatory steps to go through after installing FreeRADIUS.

Editing /etc/freeradius/3.0/sites-enabled/default

As we are not exposing the FreeRADIUS server directly to pfSense, we need to update this file to change its listen settings, so that it only listens on localhost for connections from Duo proxy. Also, we’d want to change its listen port to something other than the default RADIUS port (1812), so Duo proxy can use default port to listen for incoming RADIUS requests.

To do this, we are changing the ipaddr and port entries in multiple sections in this file. Basically, we need to change ipaddr to “localhost” and port to either 2812 (for RADIUS auth) or 2813 (for RADIUS accounting).

Below are the changes we need to make to the default configuration from the fresh install, with its original comment lines removed. An inline comment has been added to each line I changed.

server default {
listen {
type = auth
ipaddr = localhost # changed from "*" to "localhost"
port = 2812 # changed from "0" to "2812" (note the "type" above is auth)
limit {
max_connections = 16
lifetime = 0
idle_timeout = 30
}
}
listen {
ipaddr = *
port = 0
type = acct
limit {
}
}
listen {
type = auth
ipv6addr = ::1 # changed from "::" to "::1" (i.e. from "any" to "localhost")
port = 2812 # changed from "0" to "2812" (note the "type" above is auth)
limit {
max_connections = 16
lifetime = 0
idle_timeout = 30
}
}
listen {
ipv6addr = ::
port = 0
type = acct
limit {
}
}

# No change to the remainder of the file
# ....

Editing /etc/freeradius/3.0/clients.conf

We will then need to edit this file to add a client definition. This file already contains a default “localhost” client for testing purposes. We will need to comment out or delete this existing client before adding our own definition.

Again, here is the updated content of the file, with original comments removed.

client duo-proxy {
ipaddr = localhost
secret = <secret_for_duo_proxy>
}

The Duo proxy need to know the secret string specified here in order to communicate with the FreeRADIUS server. I used combination of upper case, lower case and numbers for it. I did not test if including special characters in this secret string would work.

Editing /etc/freeradius/3.0/users

In FreeRADIUS 3.0 this file has become a symbolic link to /etc/freeradius/3.0/mods-config/files/authorize.

We need to change it contents as the following.

# add this line (note the absolute path)
$INCLUDE /etc/freeradius/3.0/users.pfsense

DEFAULT Framed-Protocol == PPP
Framed-Protocol = PPP,
Framed-Compression = Van-Jacobson-TCP-IP

DEFAULT Hint == "CSLIP"
Framed-Protocol = SLIP,
Framed-Compression = Van-Jacobson-TCP-IP

DEFAULT Hint == "SLIP"
Framed-Protocol = SLIP

By adding the include instruction we can manage our Pfsense users in a separate file. Please note the absolute path here. If you didn’t use absolute path and included just users.pfsense you should put this file in the /etc/freeradius/3.0/mods-config/files/ folder, as this is the actual path to the destination of the symbolic link.

Editing /etc/freeradius/3.0/users.pfsense

Now let’s create our users file with the following content.

alice	Cleartext-Password := "<password_for_alice>"
Class := "vpn-users"

bob Cleartext-Password := "<password_for_bob>"
Class := "admins;vpn-users"

Here we defined two users. Alice will only be allowed to connect to VPN while Bob will be allowed to connect to VPN and manage the pfSense server. Multiple groups need to be separated by semi-colon. We will look at how to set up the ‘admins’ and ‘vpn-users’ groups in the Configuring pfSense section later.

Also, it should be noted that the usernames here are important. When you enrol your users for Duo MFA, the usernames set up in Duo must match the usernames in this file.

Now, as we store sensitive information in this file, let’s protected it properly.

sudo chown freerad:freerad /etc/freeradius/3.0/users.pfsense
sudo chmod 400 /etc/freeradius/3.0/users.pfsense

Testing FreeRADIUS Configurations

We should now test our FreeRADIUS server. First, let’s stop the background daemon and run the service in foreground.

sudo systemctl stop freeradius
sudo freeradius -X

This will start FreeRADIUS process in foreground and turn on its full debug mode.

In a separate terminal, run the following command to test your FreeRADIUS server.

radtest bob <password_for_bob> localhost:2812 0 <secret_for_duo_proxy>

Here we attempt to connect to port 2812 of localhost (remember we changed the ‘auth’ port) and authenticate user bob. FreeRADIUS will only respond if we know the “client secret”, which is set up in /etc/freeradius/3.0/clients.conf.

If everything works well, you should see a reply containing Received Access-Accept. If not, please read the debug output from the foreground freeradius process and fix the issue.

With the FreeRADIUS working in our foreground testing, we should now start our background daemon again.

sudo systemctl start freeradius
sudo systemctl enable freeradius

Congratulations! You have now completed the preparation work for our FreeRADIUS server.

Enrolling Duo MFA

Now we should sign up for a Duo account (if you don’t already have one) and start enrolling our users for MFA.

There is not much to say about how to sign up a Duo account. Please just click the sign-up link on their home page and follow through the process. This will include validating your email address and phone number, downloading the Duo Mobile app, and activating MFA for the owner account.

After all these have been done, log in to the Admin Panel, and go to the user section. In this section, we could manually add users one-by-one, or bulk-import users by uploading a CSV file, or import users from other directory service (e.g. Active Directory). For our purposes, I manually created the two users, alice and bob.

When you select one of the users, you will see a “Send Enrollment Email” link on the top-right of the page.

Click this link, and a system-generated enrollment email will be sent to the user’s email address. You can modify the Enrollment Email in your account settings, but if you didn’t it looks like this.

Hello,

Your organization is now rolling out Duo Security, a friendly and secure way for you to log into your applications. Your administrator has invited you to set up your account for Duo so you can start logging in.

To begin, click this link to enroll a phone, tablet, or other device:

<Enrollment Link Here>

When you click the link, you will be led to the enrollment page. Click “Start Setup” to continue.

It will first ask “What type of device are you adding”, I chose “Mobile phone”, then provided my mobile phone number. This number will be used for receiving SMS code as another MFA method (besides Duo Push).

After answering the question about the type of phone (mine is an iPhone), you will be asked to download and install the Duo Mobile app from the App Store of your phone. Go on and install it before continuing.

When you click “I have Duo Mobile Installed”, you will see a QR code being displayed. Pick up your phone, start the Duo Mobile app, grant camera and notification permissions to it when being asked, then use it to “Add an Account” by selecting the “Use QR code” option.

Your account will be added after scanning the QR code on your screen. Remember to name it properly so in the future you will know which account is being used. In my case, I named this new account “Bob for pfSense”.

Click “Continue” once Duo Mobile has been successfully activated. You now have the option to choose which method will be used for MFA by default. For greater flexibility I kept the default setting of “Ask every time” but feel free to set default to Duo Push if you’d like.

Congratulations! You have now enrolled your users for MFA.

Configuring Application in Duo Admin Panel

Now we need to create a “protected application” in the Duo Admin Panel. Once this is configured, we will have the api keys required by the Duo proxy to connect to Duo MFA server.

First, go to the Application section of the Admin Panel and select “Protect an Application”. You will be presented with a big list of applications that Duo could protect. Scroll down until you find “RADIUS” in the list.

Click the “Protect” button next to it. Duo will generate a set of “Integration Key”, “Secret Key” and “API hostname” for this application. You could also give it a better name. If you do that, remember to scroll down to the bottom of the page and click “Save”.

We will now continue on our new server to set up the Duo proxy.

Installing and Configuring Duo Proxy

The official documentation for installing and configuring the Duo proxy can be found here. So I will not get into explaining each configuration entries but instead focusing on the changes I made to the default configuration files.

First, let’s install the Duo proxy.

# install dependencies
sudo apt-get install build-essential libffi-dev perl zlib1g-dev

# download source code from Duo
cd /tmp
curl -L -O https://dl.duosecurity.com/duoauthproxy-latest-src.tgz

# build
tar xzf duoauthproxy-latest-src.tgz
cd duoauthproxy-<version>-src
sudo make # not sure why but it appears that the make command without sudo would cause errors

# install
cd duoauthproxy-build
sudo ./install

The build and installation process takes a while. When it completes, Duo proxy binary is installed into the /opt/duoauthproxy/bin folder and its configuration file is at /opt/duoauthproxy/conf/authproxy.cfg.

Connecting to FreeRADIUS

In the /opt/duoauthproxy/conf/authproxy.cfg, comment out the [ad_client] section and add the following section instead.

[radius_client]
host=127.0.0.1 # this points to the network interface FreeRADIUS was configured to listen on
port=2812 # this points to the port FreeRADIUS was configured to listen on
secret=<secret_for_duo_proxy> # this must match the FreeRADIUS client configuration
pass_through_all=true # we need this so our FreeRADIUS "Class" setting can be sent to pfSense

A note about the “host” setting. I got an error when I used “localhost” here so I was forced to use “127.0.0.1”.

Connecting to Duo MFA Server

Update the [radius_server_auto] section of the configuration file to the following.

[radius_server_auto]
client=radius_client
failmode=secure # changed from default "safe" to "secure" to enforce MFA
ikey=... # Integration Key from Duo Admin Panel
skey=... # Secret Key from Duo Admin Panel
api_host=... # Api Host from Duo Admin Panel
radius_ip_1=... # IP address of your pfSense server (see notes below)
radius_secret_1=<secret_for_pfsense> # secret shared with pfSense server
port=1812 # Our Duo proxy should listen on default 1812 port for incoming requests

Testing the Duo Proxy

To test our configuration, we need to use 127.0.0.1 for the radius_ip_1 entry above. Let’s replace our pfSense IP with 127.0.0.1.

Now we can start the Duo proxy.

/opt/duoauthproxy/bin/authproxyctl start

If you get an error, find out why and fix the configuration file. Otherwise, we can test the proxy. Using the same command as we used in the last section when we configured FreeRADIUS, we now send the test request to Duo proxy.

radtest bob <password_for_bob> localhost:1812 0 <secret_for_pfsense>

Note the two changes here. We are now using port 1812 (the default), and the secret for pfSense.

If everything goes as expected, you will receive a push notification from your Duo Mobile app, requesting MFA.

If not, restart the two services and re-try.

sudo systemctl stop freeradius
sudo /opt/duoauthproxy/bin/authproxyctl stop
sudo systemctl start freeradius
sudo /opt/duoauthproxy/bin/authproxyctl start

If this still does not resolve the issue, read the logs at /opt/duoauthproxy/conf/authproxy.cfg and/or run the FreeRADIUS in debug mode to figure out why.

After a successful testing, let’s revert the IP address back to the one our pfSense server uses and restart Duo proxy before continuing to our last step.

Configuring pfSense

Now that we have a working FreeRADIUS + Duo Proxy server, we should connect our pfSense server to it.

Authentication Server

The first step is to create a new connection in the Authentication Server section. Click “System”-“User Manager”, then go to the “Authentication Servers”.

Click the “Add” button to add a new one with the following.

Here you need to use the “<secret_for_pfsense>” you specified while configuring the Duo proxy. Also note we changed the default “Authentication Timeout” setting to 60 seconds to allow for MFA delays.

User Groups

Now we need to create a group called “vpn-users” and grant “User — VPN: IPsec auth Dialin” to it. In my experiment, when you first create the group you will not be asked for its permission setting. You need to create the group and then edit it to get to the screen below.

After creating the “vpn-users” group, your groups list should look like this. Note that we have two interesting groups here, the “admins” and the “vpn-users”. These are the two groups we specified in our FreeRADIUS “Class” reply (in our /etc/freeradius/3.0/users.pfsense file. The group names there must exactly match the group names here for things to work.

Settings

In the Settings section, we need to change the default Authentication Server to the new one we just created.

Testing User Authentication via FreeRADIUS+Duo

First, go to “Diagnosis”->”Authentication”. Select the new Authentication Server we created, and try logging in as bob. As we assigned this user in our FreeRADIUS setting to be a member of group admins, Bob should be able to login as an administrator of our pfSense server (with MFA, of course). In the result you should see both “admins” and “vpn-users”.

Once you completed the authentication testing with the built-in test tool, you could also log out and then log back in as Bob to confirm everything is working as expected.

Update IPSec Settings

Now we have our new Authentication Server working, our last step will be updating the IPsec settings so it starts to use this new server for user authentication.

Go to “VPN”->”IPsec”->”Tunnels”, then edit your Phase 1 settings by changing the Authentication Method to “EAP-RADIUS”.

Then go to “VPN”->”IPsec”->”Mobile Clients” and change “User Authentication” to use our new server.

You can tweak the RADIUS Advanced Parameters if you wish, but using the default worked perfectly fine in my case.

Once these changes are made, apply the changes (or re-start pfSense server). You can now enjoy a VPN service that is significantly more secure than before!

--

--

Frank Ye

CTO with broad interest in technology topics. Quick learner and problem solver.