Desktop and Application Streaming

Integrating FreeRADIUS MFA with Amazon WorkSpaces

If you want an automated deployment of this solution, you can use the FreeRADIUS MFA with Amazon WorkSpaces reference architecture for an end-to-end deployment in your AWS account. This uses CloudFormation to deploy this solution in a new or existing Directory Service.

In this blog post, we show how to configure FreeRADIUS and LinOTP for multi-factor authentication to Amazon WorkSpaces. Amazon WorkSpaces is a managed, secure cloud desktop service. You can use Amazon WorkSpaces to provision either Windows or Linux desktops in a few minutes. With Amazon WorkSpaces, you can quickly scale to provide thousands of desktops to workers across the globe.

MFA adds an extra layer of protection to a user name and password (the first “factor”). With MFA, you must enter an authentication code (the second factor), which is provided by your MFA solution.

For MFA on Amazon WorkSpaces, you need a remote authentication dial-in user service (RADIUS) server that can authenticate the one-time password. You can implement this configuration using the free open source RADIUS server, FreeRADIUS. FreeRADIUS is a modular, high-performance free RADIUS suite. It is developed and distributed under the GNU General Public License, version 2, and is free for download and use. FreeRADIUS is the most popular open source RADIUS server and the most widely deployed RADIUS server in the world. FreeRADIUS is used by educational institutions, internet service providers and for enterprise networks.

Overview of the solution

This is how the authentication flow works when using MFA with Amazon WorkSpaces:

Steps 1 & 2: The Amazon WorkSpaces user gets the one time password (OTP) from an authentication app, such as Google Authenticator.

Step 3: The WorkSpaces client sends both the first factor domain user name and password and the second factor OTP to the AWS Directory Service.

Steps 4 & 5: Active Directory validates the primary authentication part (domain credentials) with the on-premises domain controllers for AD Connector or AWS Managed Domain Controllers if using AWS Managed AD.

Step 6: The Active Directory sends the secondary credentials OTP to the RADIUS server.

Step 7: The RADIUS server checks the OTP and responds with ‘success’ if it was correct.

Step 8: The AD Connector completes authentication and the customer can access the service

When MFA is enabled, the Amazon WorkSpaces client prompts for the MFA code.


It is recommended to deploy this configuration in a test environment before deploying to production. To follow the steps in the post, you need the following:

  • An AWS environment with Amazon WorkSpaces configured
  • An AWS Directory Service such as AWS Managed AD or AD Connector
  • An EC2 instance based on the Amazon Linux 2 AMI e.g a T3.medium
  • LinOTP for Active Directory integration (self-service portal)
  • MariaDB or MySQL (in this blog, we use MariaDB)
  • FreeRADIUS (RADIUS server) GPLv2 License
  • Google Authenticator (secret generation tool) Apache License 2.0 installed on a mobile device


Step 1: Prepare EC2 instance for RADIUS services

  1. Connect to the EC2 instance via SSH. Make sure that it is up-to-date, and enable the repository.
    sudo yum -y update
    sudo amazon-linux-extras install epel -y
    sudo yum localinstall -y
    sed -i 's,,,g' /etc/yum.repos.d/linotp.repo
    sed -i 's,,,g' /etc/yum.repos.d/linotp.repo
  2. Install MariaDB, enable the service and secure the database. Confirm steps to lockdown MariaDB, like removing the Root privilege for login into MariaDB, or setting Root password to something different.
    sudo yum install mariadb-server -y
    sudo systemctl enable mariadb
    sudo systemctl start mariadb
    sudo mysql_secure_installation
  3. Install LinOTP, Apache httpd and configure with MariaDB
    sudo yum install -y LinOTP LinOTP_mariadb
    sudo restorecon -Rv /etc/linotp2/
    sudo restorecon -Rv /var/log/linotp
    # Configure LinOTP and MariaDB credentials
    sudo linotp-create-mariadb
    # Lock python-repoze-who version
    sudo yum install yum-plugin-versionlock -y
    sudo yum versionlock python-repoze-who
    # Install apache and vhost config
    sudo yum install LinOTP_apache -y
    sudo systemctl enable httpd
    sudo systemctl start httpd

    sudo mv /etc/httpd/conf.d/ssl.conf /etc/httpd/conf.d/ssl.conf.back
    sudo mv /etc/httpd/conf.d/ssl_linotp.conf.template /etc/httpd/conf.d/ssl_linotp.conf

Step 2 Configure LinOTP and integrate with your Active Directory.

  1. Create a password for the admin portal of LinOTP. You will be prompted to enter the password for “admin”.
    sudo htdigest /etc/linotp2/admins "LinOTP2 admin area" adminReboot the instance after setting password.
  2. Browse to: https://privateIPofInstance/manage, replace privateIPofInstance with the IP address of your Amazon Linux 2 RADIUS server. Log in with the user name of “admin” and the password you entered in step 2.1
  3. Select LinOTP Config menu, choose UserIdResolvers
  4. Select New, then choose LDAP
  5. Populate the Server Configuration fields. See sample fields below;
    Resolver name: Any text to describe the resolver
    Server-URI: ldap://[AD_DNS_IP]. You can have multiple IP addresses separated by comma.
    BaseDN: The is the root of your domain for LDAP search. E.g DC=example,DC=com. We recommend you use an OU where your users are situated as BaseDN rather than the root of your domain.
    BindDN: This is the distinguished name for a domain user with necessary permissions to perform LDAP search on your Active Directory. For example CN=MFAUser,OU=users,DC=example,DC=com
    Bind Password: Password of the BindDN user account above.
  6. Choose Test LDAP Server connection. On success, choose Preset Active Directory then choose Save.
  7. Create a new Realm. Select the UserIdResolver created above. Take note of the Realm name as you need this later.
  8. Choose Save. Select save as default.
  9. Select the User View tab, you can see the list of users in your Active Directory
  10. Create a file called samplepolicy.cfg. Copy and apste this simple configuration into your simplepolicy.cfg and save the file.
    realm = *
    name = Limit_to_one_token
    action = maxtoken=1
    client = *
    user = *
    time = * * * * * *;
    active = True
    scope = enrollment
    realm = *
    name = OTP_to_authenticate
    action = otppin = token_pin
    client = *
    user = *
    time = * * * * * *;
    active = True
    scope = authentication
    realm = *
    name = Require_MFA_at_Self_Service_Portal
    active = False
    client = *
    user = *
    time = * * * * * *;
    action = mfa_login
    scope = selfservice
    realm = *
    name = Default_Policy
    active = True
    client = *
    user = *
    time = * * * * * *;
    action = "enrollTOTP, reset, resync, setOTPPIN, disable"
    scope = selfservice
  11. Select the Policies tab. Choose Import Policies. Import the samplepolicy.cfg you created. You can customize settings to your environment. Refer here for more customization options –

Step 3 Enroll Users

  1. Ensure web ports 443, 80 and UDP 1812 are open on the security group of the instance.
  2. Users can navigate to https://IPofInstance (Replace IP with the EIP/public IP of your instance). There is a warning about the self-signed certificate. In a production environment, as security best practice, you should put this instance behind an Elastic Load Balancer, and configure Route 53.
  3. Users should login with their Active Directory user name and password
  4. On the Enrol TOTP token screen, choose “Generate Random Seed” and “Google Authenticator compliant”. Follow the prompts. When the QR code appears, scan with the authenticator (Google or Microsoft Authenticator) on your mobile
  5. Test the token by visiting https://[IPAddressofRADIUS]/validate/check?user=USERNAME&pass=PINOTP

If you get below response, then authentication is successful (note: the value is ‘true’)

"version": "LinOTP 2.11.2",
"jsonrpc": "2.0802",
"result": {
"status": true,
"value": true
"id": 0

Step 4: Install and configure FreeRADIUS.

  1. Log on to the EC2 instance.
  2. Install and configure FreeRADIUS
    sudo yum install freeradius freeradius-perl freeradius-utils perl-App-cpanminus perl-LWP-Protocol-https perl-Try-Tiny git -y
    sudo cpanm Config::File
    sudo mv /etc/raddb/clients.conf /etc/raddb/clients.conf.back
    sudo mv /etc/raddb/users /etc/raddb/users.back
  3. Create a file /etc/raddb/clients.conf. Open the file and copy the example configuration shown below. Replace MYSECRET with your own super secure secret. Replace [CIDR of Directory Service] with your AWS Directory Service Subnets or VPC and [YOUR-NETMASK] to allow VALID request from within the VPC. For example, CIDR = and Netmask =24. Note MYSECRET should be inside single quotes. This is the secret you will use to enable MFA on AWS Directory Service console.
    client localhost {
    ipaddr  =
    netmask= 32
    secret  = 'MYSECRET'
    client adconnector {
    ipaddr  = [CIDR of Directory Service subnets or VPC]
    netmask = [YOUR-NETMASK]
    secret  = 'MYSECRET'
  4. Download linotp perl module for FreeRADIUS
    sudo git clone /usr/share/linotp/linotp-auth-freeradius-perl
  5. To allow FreeRADIUS to execute the ‘linotp’ plugin, overwrite the file /etc/raddb/mods-available/perl with the configuration below
    perl {
    filename = /usr/share/linotp/linotp-auth-freeradius-perl/
  6. Activate the perl module
    sudo ln -s /etc/raddb/mods-available/perl /etc/raddb/mods-enabled/perl
  7. Configure LinOTP perl module for FreeRADIUS. Create the file /etc/linotp2/rlm_perl.ini with below contents. Change YOUR-REALM to the one you created in part 7 of Step 2.
    #IP of the linotp server
    #optional: limits search for user to this realm
    #optional: only use this UserIdResolver
    #optional: comment out if everything seems to work fine
    #optional: use this, if you have selfsigned certificates, otherwise comment out
  8. Remove the default-links for activated configurations
    sudo rm /etc/raddb/sites-enabled/{inner-tunnel,default}
    sudo rm /etc/raddb/mods-enabled/eap
  9. Activate ‘linotp’ within ‘FreeRADIUS’. Create a new file ‘/etc/raddb/sites-available/linotp‘ with the following content:
    server default {
    listen {
    type = auth
    ipaddr = *
    port = 0
    limit {
    max_connections = 16
    lifetime = 0
    idle_timeout = 30
    listen {
    ipaddr = *
    port = 0
    type = acct
    }authorize {
    update control {
    Auth-Type := Perl
    }authenticate {
    Auth-Type Perl {
    }preacct {
    }accounting {
    }session {
    post-auth {
    update {
    &reply: += &session-state:
  10. Activate the configuration by creating a soft linking to ‘/etc/raddb/sites-enabled’
    sudo ln -s /etc/raddb/sites-available/linotp /etc/raddb/sites-enabled/linotp
  11. Enable and start the radius service
    sudo systemctl enable radiusd
    sudo systemctl start radiusd

Step 5: Test the solution from the EC2 instance

You can test Google authentication locally on the RADIUS EC2 instance.


Where username is the test active directory user name. MFACODE is the OTP from your Google Authenticator app. PRIVATERADIUSIP is your EC2 instance IP address. SECRETWORD is your shared secret you configure in step 4 part 3.

You should get an Access-Accept response.

Step 6: Enable MFA on your AWS Directory

  1. Communication between the AWS Managed Microsoft AD RADIUS client and your RADIUS server require you to configure AWS security groups that enable communication over port 1812. Edit your Virtual Private Cloud (VPC) security groups to enable communications over port 1812 between your AWS Directory Service IP end points and your RADIUS MFA server.
  2. Navigate to your Directory Service console
  3. Click the Directory you want to enable MFA on. Select Network & Security tab, scroll down to Multi-factor authentication, click Actions and Enable. In Enable multi-factor authentication (MFA) configure MFA settings:
    Display label: Example
    RADIUS server IP address(es): Private IP of the Amazon Linux 2 instance
    Port: 1812
    Shared secret code: the one set in /etc/raddb/clients.conf
    Confirm shared secret code: as preceding
    Protocol: PAP
    Server timeout (in seconds): 30
    Max retries: 3

This operation can take between 5-10mins to complete. Once the Radius status is “completed” you can test MFA authentication from the WorkSpace client.

Cleaning up

To clean up your deployed resources:

1.  Disable MFA on the Directory of your WorkSpaces

2.  Shut down the Amazon EC2 instance, the RADIUS server


In this blog post, we have demonstrated how to integrate FreeRADIUS with your Active Directory. With FreeRADIUS you can use multi-factor authentication – an extra layer of security to your Amazon WorkSpaces. In a production environment, deploy multiple RADIUS server instances in different Availability Zones to have availability in the event of failure.