
If you follow me on Instagram, then you know that I successfully implemented Duo MFA in my home lab. I’ve set up two environments, one with FreeRADIUS, and the other using Windows AD, as the primary authentication source. In today’s article, I’m going to demonstrate how to implement Duo Security MFA with FreeRADIUS as the primary authentication source.
Introduction
As you may already know, multi-factor authentication (MFA) isn’t new. Back in the day, the most popular MFA solution is RSA SecurID. Nowadays, one of the popular MFA solutions is Duo. It’s also popular with tech-savvy folks who are looking at deploying two-factor authentication (2FA) in their home lab since they offer free-tier pricing.
I’ve had a 2FA solution in my home lab since 2016. I’ve written a few articles about it. The first article was about adding 2FA when I connect remotely (SSH) to my Ubuntu Linux VMs. The second article was adding 2FA to FreeRADIUS, which gives RADIUS clients a 2FA solution. The third article was adding 2FA to TACACS+ using tac_plus daemon.
What’s needed
In this tutorial, you will need the following:
- Duo account (sign up for free)
- Two machines (virtual or physical)
The VM specs will depend on the environment. In my VMware ESXi home lab environment, the Duo VM has the following specs:
- 1 x vCPU
- 512MB RAM or more (Recommended is 4GB)
- 8GB drive space
- Ubuntu Server 18.04
My FreeRADIUS is running on a Docker container. Since I have multiple Docker containers in there, the VM has the following specs:
- 1 x vCPU
- 1GB RAM
- 8GB drive space
- Ubuntu Server 18.04
FreeRADIUS Docker container
Ever since my first FreeRADIUS 2FA article, I’ve migrated it to a Docker container. That said, it was easy for me to write a new Dockerfile without the Google Authenticator piece.
Dockerfile using Ubuntu 18.04
# Use Base Ubuntu image FROM ubuntu:18.04 # Author of this Dockerfile MAINTAINER Andrew Roderos# Update & upgrades RUN apt-get update && apt-get dist-upgrade -y # Install FreeRADIUS RUN apt-get install freeradius -y # Clear local repo RUN apt-get clean # Add user to container with home directory RUN useradd -m -d /home/networkjutsu -s /bin/bash networkjutsu # Add password to networkjutsu account RUN echo 'networkjutsu:makemypasswordgreatagain' | chpasswd # Edit /etc/pam.d/radiusd file RUN echo "auth required pam_unix.so use_first_pass" >> /etc/pam.d/radiusd # Edit /etc/freeradius/3.0/mods-config/files/authorize file # This is the real file for /etc/freeradius/3.0/users RUN sed -i '1s/^/# Instruct FreeRADIUS to use PAM to authenticate users\n/' /etc/freeradius/3.0/mods-config/files/authorize RUN sed -i '2s/^/DEFAULT Auth-Type := PAM\n/' /etc/freeradius/3.0/mods-config/files/authorize # Copy existing /etc/freeradius/sites-available/default file to container # This is the real file for /etc/freeradius/3.0/sites-enabled/default COPY default /etc/freeradius/3.0/sites-available/default # Change owner of the file to freerad RUN chown freerad:freerad /etc/freeradius/3.0/sites-available/default # Copy existing /etc/freeradius/clients.conf file to container COPY clients.conf /etc/freeradius/3.0/clients.conf # Create a symbolic link RUN ln -s /etc/freeradius/3.0/mods-available/pam /etc/freeradius/3.0/mods-enabled/pam # Expose the port EXPOSE 1812/udp 1813/udp 18120/udp # Run FreeRADIUS as a foreground process CMD ["freeradius","-f"]
Dockerfile using Ubuntu 20.04 or 22.04
# Use Base Ubuntu image FROM ubuntu:20.04 # Author of this Dockerfile MAINTAINER Andrew Roderos# Set timezone ENV TZ=America/Los_Angeles RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone # Update & upgrades RUN apt-get update && apt-get dist-upgrade -y # Install tzdata and FreeRADIUS RUN apt-get install tzdata freeradius -y # Clear local repo RUN apt-get clean # Add user to container with home directory RUN useradd -m -d /home/networkjutsu -s /bin/bash networkjutsu # Add password to networkjutsu account RUN echo 'networkjutsu:makemypasswordgreatagain' | chpasswd # Edit /etc/pam.d/radiusd file RUN echo "auth required pam_unix.so use_first_pass" >> /etc/pam.d/radiusd # Edit /etc/freeradius/3.0/mods-config/files/authorize file # This is the real file for /etc/freeradius/3.0/users RUN sed -i '1s/^/# Instruct FreeRADIUS to use PAM to authenticate users\n/' /etc/freeradius/3.0/mods-config/files/authorize RUN sed -i '2s/^/DEFAULT Auth-Type := PAM\n/' /etc/freeradius/3.0/mods-config/files/authorize # Copy existing /etc/freeradius/sites-available/default file to container # This is the real file for /etc/freeradius/3.0/sites-enabled/default COPY default /etc/freeradius/3.0/sites-available/default # Change owner of the file to freerad RUN chown freerad:freerad /etc/freeradius/3.0/sites-available/default # Copy existing /etc/freeradius/clients.conf file to container COPY clients.conf /etc/freeradius/3.0/clients.conf # Create symbolic link RUN ln -s /etc/freeradius/3.0/mods-available/pam /etc/freeradius/3.0/mods-enabled/pam # Expose the port EXPOSE 1812/udp 1813/udp 18120/udp # Run FreeRADIUS as foreground process CMD ["freeradius","-f"]
Note
This Dockerfile references local files that I already have. My first FreeRADIUS article might be able to help you. If not, you could always read the documentation.
Duo user creation

Once you’ve created your account, it’s time to create a Duo user. This user must match the user accounts in your primary authentication source. In my case, it is the FreeRADIUS server.
If you have a paid account and use OpenLDAP, Windows AD, or Azure AD, there’s a Directory Synchronization feature that automatically imports the accounts to Duo.
Alternatively, you can import users by creating a CSV file. Since I only have one account, I don’t need to import users.
Add phone
Once you click on the Add Phone button, you will see a screen where you can add the user’s full name, email address, phone number, etc. For my purpose, I only added a phone.

In the next screen, this is where you will add the user’s phone number.

2FA device
Once you add the user’s phone number, it will automatically add a 2FA device. This next screen will allow you to change the device information.

Activate Duo Mobile
The next step is to activate the Duo Mobile app. On the screen where you were just at, click on the Activate Duo Mobile link. It will take you to another screen where you will click the Generate Duo Mobile Activation Code button.

The next screen will allow you to send instructions by SMS to the user.
Note
In my limited testing, this will count towards your telephony credits. The free account comes with over 490+ credits, so this isn’t a big deal. You can buy additional credits should you need it.

Protect an application
Since there’s no Duo Authentication Proxy as an application in the list, we need to use the Partner Auth API as the application.

Once you click the Protect button, the next screen will show the information you need when you start configuring the Duo authentication proxy host. Make sure to jot down the integration key, secret key, and API hostname.

Feel free to change the name of the application. The application name is the one that will show up in Duo mobile app when there’s a push.
Installing Duo Authentication Proxy
This step assumes that you have an Ubuntu Linux VM already installed and updated. To install Duo authentication proxy, issue the commands below.
$ sudo apt-get install build-essential libffi-dev perl zlib1g-dev make -y $ wget https://dl.duosecurity.com/duoauthproxy-latest-src.tgz $ tar -zxf duoauthproxy-latest-src.tgz
At this time of writing, the latest version is 4.0.1.8318f80. The directory may be different when you download the installer. That said, feel free to change the directory name in the command shown below.
Note
The make
command may take a while to finish.
$ cd duoauthproxy-4.0.1-8318f80-src $ sudo make $ cd duoauthproxy-build $ sudo ./install
When the installation process asks you where you wish to install the Duo authentication proxy, you can either hit Enter or change it to another directory. I prefer it in /etc/duoauthproxy
, so that’s where everything will sit for my installation. Everything else just hit Enter to accept the default except for the last question. Type Yes and hit Enter.
In what directory do you wish to install the Duo Authentication Proxy? [/opt/duoauthproxy] /etc/duoauthproxy Enter the name of a user account under which the Authentication Proxy should be run. We recommend a non-privileged and locked down account. Or you can pressand our default locked down user will be created for you: [duo_authproxy_svc] Enter the name of a group under which the Authentication Proxy logs will be readable. Or press and a default group will be created for you: [duo_authproxy_grp] Create an initialization script to run the proxy upon startup? [Yes/no] Yes
Optional
Delete the Duo files that you downloaded and extracted.
$ cd ~ $ sudo rm -rf duoauthproxy-4.0.1-8318f80-src $ rm duoauthproxy-latest-src.tgz
Configuring Duo Authentication Proxy
In this step, you will need to modify the authproxy.cfg
file. This configuration file will contain information about your Duo integration and secret key, authentication source, etc.
Before modifying the file, create a backup so you can always revert to the original file. Use the command below to create a backup configuration file.
$ sudo cp /etc/duoauthproxy/conf/authproxy.cfg /etc/duoauthproxy/conf/authproxy.cfg.bak
There are three sections in the configuration file: the main, client, and server. The main configuration section is optional. This section is where you can specify which interface to use, HTTP proxy info, log size, etc. In my lab environment, I don’t need any of them, so I left the default configuration.
The next configuration section is the client section. This section is where you will define the authentication source. At this time of writing, the configuration file has [ad_client]
as the default. Since I use the FreeRADIUS server as my authentication source, I will need to either delete or comment it out. I chose to comment it out.
#[ad_client] #host= #service_account_username= #service_account_password= #search_dn= [radius_client] host=192.168.10.51 secret=radius-key-here
The last configuration section is the server section. This section is where you will add your Duo integration key, secret key, API hostname, clients, etc.
[radius_server_auto] ikey=integration-key-here skey=secret-key-here api_host=api-hostname.duosecurity.com radius_ip_1=192.168.20.0/24 radius_secret_1=radius-key-here radius_ip_2=192.168.30.2-10 radius_secret_2=radius-key-here radius_ip_3=192.168.40.100 radius_secret_3=radius-key-here failmode=safe client=radius_client port=1812
You may have to restart the service so issue /etc/duoauthproxy/bin/authproxyctl restart
or sudo systemctl restart duoauthproxy
command.
Final Thoughts
It is pretty generous for Cisco to continue offering the free-tier pricing. I hope they don’t stop offering it for free since I happen to like it. While the free-tier is limited in features, it is enough for my needs.
As a matter of fact, I switched to Duo MFA as my 2FA solution for my remote access VPN. I configured my Ubiquiti EdgeRouter to point to my Duo Authentication Proxy host instead of my previous 2FA solution. It is no longer necessary for me to memorize the TOTP code before connecting to my VPN using my iOS devices.
You might like to read
Securing SSH with Google Authenticator
Adding Two-Factor Authentication to FreeRADIUS
Adding Two-Factor Authentication to TACACS+
BUY ME COFFEE ☕