Configuring Duo Security MFA for Horizon Unified Access Gateway

In my last post, I went through the steps for deploying a Horizon Access Point/Unified Access Gateway using the PowerShell deployment script.  That post walked through the basic deployment steps.

The Unified Access Gateway supports multiple options for two-factor authentication, and many real-world deployments will use some form of two-factor when granting users access to their desktops and applications remotely.  The Unified Access Gateway supports the following two-factor authentication technologies:

  • RSA Secur-ID
  • Certificate Based/Smart-Cards

Because I’m doing this in a lab environment, I decided to use a RADIUS-based technology for this post.  I’ve been using Duo Security for a while because they support RADIUS, have a mobile app, and have a free tier.  Duo also supports VMware Horizon, although they do not currently have any documentation on integrating with the Access Point/Unified Access Gateway.

Duo Security for Multi-factor Authentication

Duo Security is a cloud-based MFA provider.  Duo utilizes an on-premises Authentication Proxy to integrate with customer systems.  In addition to providing their own authentication source, they can also integrate into existing Active Directory environments or RADIUS servers.

When using Active Directory as the authentication source, Duo will utilize the same username and password as the user’s AD account.  It will validate these against Active Directory before prompting the user for their second authentication factor.

Understanding Unified Access Gateway Authentication Path

Before I configure the Unified Access Gateway for two-factor authentication with Duo, let’s walk through how the appliance handles authentication for Horizon environments and how it compares to the Security Server.  There are some key differences between how these two technologies work.

When the Security Server was the only option, two-factor authentication was enabled on the Connection Servers.  When users signed in remotely, the security server would proxy all authentication traffic back to the connection server that it was paired with.  The user would first be prompted for their username and their one-time password, and if that validated successfully, they would be prompted to log in with their Active Directory credentials.  The reliance on connection servers meant that two sets of connection servers needed to be maintained – one internal facing without multi-factor authentication configured and one external facing with multi-factor configured.

Note: When using Duo in this setup, I can configure Duo to use the same initial credentials as the user’s AD account and then present the user with options for how they want to validate their identity – a phone call, push to a mobile device, or passcode.  I will discuss that configuration below.

The Unified Access Gateway setup is, in some ways, similar to the old Security Server/Connection Server setup.  If 2FA is used, the user is prompted for the one-time password first, and if that is successful, the user is prompted for their Active Directory credentials.  But there are two key differences here.  First, the Unified Access Gateway is not tied to a specific Connection Server, and it can be pointed at a load-balanced pool of connection servers.  The other difference is 2FA is validated in the DMZ by the appliance, so 2FA does not need to be configured on the Connection Servers.

Horizon has a couple of multi-factor authentication options that we need to know about when doing the initial configuration.  These two settings are:

  • Enforce 2-factor and Windows user name matching (matchWindowsUserName in UAG) – enabled when the MFA and Windows user names match.
  • Use the same username and password for RADIUS and Windows authentication (WindowsSSOEnabled in UAG) – Used when the RADIUS server and Windows have the same password.  When this setting is enabled, the domain sign-on prompt is skipped.

If my two-factor authentication system supports Active Directory authentication, I can use my Windows Username and Password to be authenticated against it and then receive a challenge for a one-time password (or device push).  If this second factor of authentication is successful, I will be automatically signed into Horizon.

Configuring Duo

The Duo environment needs to be configured before Horizon MFA can be set up.  Duo requires an on-premises authentication proxy.  This proxy acts as a RADIUS server, and it can run on Windows or Linux.  The steps for installing the Duo authentication proxy are beyond the scope of this article.

Once the authentication proxy is installed, it needs to be configured.  Duo has a number of options for configuration, and it’s important to review the documentation.  I’ll highlight a few of these options below.

The first thing we need to configure is the Duo client.  The client determines what type of primary authentication is performed.  Duo supports three methods:

  • ad_client: Duo uses Active Directory for primary authentication.  Users sign in with their Active Directory username and password.
  • radius_client: Duo uses the specified RADIUS server, such as Microsoft NPS or Cisco ACS, for primary authentication.
  • duo_only_client: Duo does not perform primary authentication.  The authentication proxy only performs secondary authentication, and primary authentication is handled by the configured system.

I don’t have a RADIUS server configured in my lab, so I did testing with both the ad_client and the duo_only_client. I prefer a single sign-on solution in my lab, so this setup will be configured with the ad_client.

The authentication proxy configuration is contained in the authproxy.cfg file located in C:\Program Files (x86)\Duo Security Authentication Proxy\conf.  Open this file in a text editor and add the following lines:


Duo includes a number of options for configuring an Active Directory client, including encrypted passwords, LDAPS support, and other security features.  The configuration above is a simple configuration meant for a lab or PoC environment.

Note: If Duo will not be performing primary authentication, simply add [duo_only_client] to the configuration.

Before the RADIUS server settings can be configured, a new application needs to be created in the Duo Administration Console.  The steps for this are:

1. Log into the Duo Admin Console.

2. Click Applications

3. Click Protect an Application

4. Scroll down to VMware View and select “Protect this Application.”

5. Copy the Integration Key, Secret Key, and API Hostname.

6. Change the username normalization option to “Simple.”

7. Click “Save Changes.”

The next step is to configure the authentication proxy as a RADIUS service.  Duo also has a number of options for this.  These determine how Duo interacts with the client service.  These options include:

  • RADIUS_Auto: The user’s authentication factor, and the device that receives the factor, is automatically selected by Duo.
  • RADIUS_Challenge: The user receives a textual challenge after primary authentication is complete.   The user then selects the authentication factor and device that it is received on.
  • RADIUS_Duo_Only: The RADIUS service does not handle primary authentication, and the user’s passcode or factor choice is used as the RADIUS password.

Duo also has multiple types of authentication factors.  These options are:

  • Passcode: A time-based one-time password that is generated by the mobile app.
  • Push: A challenge is pushed to the user’s mobile device with the Duo mobile app installed.  The user approves the access request to continue sign-in.
  • Phone Call: Users can opt to receive a phone call with their one-time passcode.
  • SMS: Users can opt to receive a text message with their one-time passcode.

RADIUS_Challenge will be used for this setup.  In my testing, the combination of an ad_client and RADIUS_Auto meant that my second authentication factor was a push to the mobile app.  In most cases, this was fine, but in situations where my laptop was online but my phone was not (such as on an airplane), meant that I was unable to access the environment.  The other option is to use RADIUS_Duo_Only with the Duo_Only_Client, but I wanted a single sign-on experience.

The RADIUS server configuration for the Horizon Unified Access Gateway is:

ikey=[random key generated by the Duo Admin Console]
skey=[random key generated by the Duo Admin Console] [generated by the Duo Admin Console]
failmode=secure [in the event that Duo cannot be contacted, users will not be able to sign in even if primary authentication succeeds]
radius_ip_1=IP Address or Range
prompt_format=short [a short text message will be displayed listing available authentication factors]

Save the authproxy.cfg file and restart the Duo Authentication Proxy service for the new settings to take effect.

The next step is to configure the Unified Access Gateway to use RADIUS.  The following lines need to be added to the [Horizon] section:

authMethods=radius-auth [Note: Configures the UAG to only use RADIUS authentication. If doing Duo only, set this to radius-auth && sp-auth]

matchWindowsUserName=true [Note: Configures the UAG to use the same username for both RADIUS and AD Authentication. When this setting is enabled, users cannot change the username in the second logon screen.]

windowsSSOEnabled=true [Note:Used when the RADIUS username and passcode match the AD username and password.  If using the Duo only option, set this to false.  Users will then be prompted for a password  after authenticating with Duo.]

A new section needs to be added to handle the RADIUS configuration.  The following lines need to be added to create the RADIUS section and configure the RADIUS client on the Unified Access Gateway.  If more than one RADIUS server exists in the environment, you can add an _2 to the end of hostname and auth_port.

[RADIUSAuth] [IP of the primary RADIUS server]



radiusDisplayHint=XXX Token

Save the UAG configuration file and deploy, or redeploy, your Unified Access Gateway.  When the deployment completes, and you log in externally, you should see the following screens:



Horizon 7.0 Part 13 – Deploying The Horizon Access Point

In the last part of this series, I walked through the different remote access options for a Horizon 7 environment.  In this post, I’ll cover how to install and configure an Access Point appliance for a Horizon environment.

Note: The Access Point appliance has been renamed to the Unified Access Gateway as of Horizon 7.1.  This post began before the product was renamed, and the old naming convention will be used.

Before we go into deploying the appliance, let’s dive into what the appliance does and how it’s built.

As I said in the previous post, the Access Point is a purpose built virtual appliance that is designed to be the remote access component for VMware Horizon, VMware Identity Manager, and Airwatch.  The appliance is hardened for deployment in a DMZ scenario, and it is designed to only pass authorized traffic from authenticated users into a secure network.  In some ways, the Access Point is designed to replace VPNs, but it doesn’t provide full access to an internal network like a VPN would.

When deploying an Access Point, I highly recommend using the PowerShell Deployment Script.  This script was written by Mark Benson, the lead developer of the Access Point.  The script uses an INI configuration file that can be customized for each appliance that is deployed.  I like the PowerShell script over deploying the appliance through vCenter because the appliance is ready to use on first boot, it allows administrators to track all configurations in a source control system such as Github or Bitbucket Server, and this provides both documentation for the configuration and change tracking.  It also makes it easy to redeploy or upgrade the access point because I rerun the script with my config file and the new OVA file.

The PowerShell script requires the OVF Tool to be installed on the server or desktop where the PowerShell script will be executed.  The latest version of the OVF Tool can be downloaded from the My VMware site.  PowerCLI is not required when deploying the Access Point as OVF Tool will be deploying the Access Point and injecting the configuration.

The steps for deploying the Access Point are:

1. Download the PowerShell deployment script for the version of the Access Point you will be deploying.  You can download the script from here.

2.  Right click on the downloaded zip file and select Properties.

3. Click Unblock.  This step is required because the file was downloaded from the Internet, and is untrusted by default, and this can prevent the script from executing.

4. Extract the contents of the downloaded ZIP file to a folder on the system where the deployment script will be run.  The ZIP file contains the apdeploy.ps1 script file and five INI template files.  As of January 2017, four of the template files are example configurations for Horizon, and one is a sample configuration for vIDM. 

When deploying the access points for Horizon, I recommend starting with the AP2-Advanced.ini template.  This template provides the most options for configuring Horizon remote access and networking.  Once you have the AP deployed successfully, I recommend copying the relevant portions of the SecurID or RADIUS auth templates into your working AP template.  This allows you to test remote access and your DMZ networking and routing before adding in MFA.

5. Before we start filling out the template for our first access point, there are some things we’ll need to do to ensure a successful deployment. These steps are:

A. Ensure that the OVF Tool is installed on your deployment machine.

B. Locate the Access Point’s OVA file and record the full file path.  The OVA file can be placed on a network share.

C. We will need a copy of the certificate, including any intermediate and root CA certificates, and the private key in PEM format.  The certificate files should be concatenated so that the certificate and any CA certificates in the chain are in one file, and the private key should not have a password on it.  Place these files into a folder on the local or network folder and record the full path.

D. We need to create the path to the vSphere resources that OVF Tool will use when deploying the appliance.  This path looks like: vi://user@PASSWORD:vcenter.fqdn.orIP/DataCenter Name/host/Host or Cluster Name/

Do not replace the uppercase PASSWORD with any value.  This is an OVF Tool variable that prompts the user for a password before deploying the appliance.  OVF Tool is case sensitive, so make sure that the datacenter name and host or cluster names are entered as they are displayed in vCenter.

E. Generate the passwords that  you will use for the appliance Root and Admin passwords.

F. Get the SSL Thumbprint for the certificate on your Connection Server or load balancer that is in front of the connection servers.

6. Fill out the template file.  The file has comments for documentation, so it should be pretty easy to fill out.  There are a couple of things that I’ve noticed when deploying the access point using this method.  You need to have a valid port group for all three networks, even if you are only using the OneNic deployment option. 

7. Save your INI file as <APName>.ini in the same directory as the deployment scripts.

8. Open PowerShell and change to the directory where the deployment scripts are stored.

9. Run the deployment script.  The syntax is .\APDeploy.ps1 –inifile <apname>.ini

10. Enter the appliance root password twice.

11.  Enter the admin password twice.  This password is optional, however, if one is not configured, the REST API and Admin interface will not be available.

12.  If RADIUS is configured in the INI file, you will be prompted for the RADIUS shared secret.

13. After the script opens the OVA and validates the manifest, it will prompt you for the password for accessing vCenter.  Enter it here.

14. If an access point with the same name is already deployed, it will be powered off and deleted.

15. The appliance OVA will be deployed.  When the deployment is complete, the appliance will be powered on and get an IP address from DHCP.

16. The appliance configuration defined in the INI file will be injected into the appliance.  It may take a few minutes for configuration to be completed.


Testing the Access Point

Once the appliance has finished it’s deployment and self-configuration, it needs to be tested to ensure that it is operating properly. The best way that I’ve found for doing this is to use a mobile device, such as a smartphone or cellular-enabled tablet, to access the environment using the Horizon mobile app.  If everything is working properly, you should be prompted to sign in, and desktop pool connections should be successful.

If you are not able to sign in, or you can sign in but not connect to a desktop pool, the first thing to check is your firewall rules.  Validate that TCP and UDP ports 443 and 4172 are open between the Internet and your Access Point.  You may also want to check your network routes in your configuration file.  If your desktops live in a different subnet than your access points and/or your connection servers, you may need to statically define your routes.  An example of a route configuration may look like the following:

routes1 =,

If you need to make a routing change, the best way to handle it is to update the ini file and then redeploy the appliance.

My Windows 10 Template Build Process

I’ve been spending a lot of time working with Windows 10 in the lab lately, and one of the big struggles I’ve faced was building a solid template that I could reuse.  The reason I’ve had trouble with this is due to changes that Microsoft made in Windows 10 that essentially break the process that worked with previous versions of Windows.  The biggest changes include Modern UI applications and changes to how default applications are handled.

Modern UI apps are problematic for many reasons.  First, some of the original core Windows applications have been replaced by Modern UI applications, so while it is possible to remove them, you lose significant functionality that may not be replaced by 3rd Party applications.  In order to keep these applications up-to-date, the Windows Store needs to be available on the desktop.  That also means that the Store can’t be disabled unless you want to run outdated Modern UI applications.  Second, Modern UI apps tend to break Sysprep if any user profiles exist on the system outside of the built-in Administrator. 

Default applications are another tricky area.  In previous versions of Windows, a web browser or document viewer could set itself, or prompt the user to set it, as the default application for certain file types or URLs.  So if you installed Adobe Reader, it could set itself up as the default application for PDF programs.  This does not necessarily appear to be the case in Windows 10 – some applications that manage common file types have a system default that applies to all users.  This is mainly true for URLs and PDF files, and they default to Microsoft Edge.  While I can change this on a per-user basis, I may want to enforce certain corporate application standards within my image.

I’ve been spending a lot of time building Windows 10 desktop templates in my lab, and I’ve been looking at a lot of Windows 10 build guides.  All of the ones I’ve seen treat a Windows 10 build like a Windows 7 build with some minor changes, but none of them address the issues that I’ve experienced in my lab.

To get around issues with Modern UI applications, managing and/or cleaning up user accounts on the system before sysprepping my template, and dealing with application defaults, I decided to put together a different method for building my Windows 10 VDI image to address the issues I’ve faced and to reduce the number of manual steps that I have to take when creating and/or updating the template.  The main thing that I do differently is the use of Sysprep Audit Mode.  Audit mode allows an administrator to bypass the OOBE and log into the desktop as a local administrator with network access to customize the desktop environment, and the system remains in Audit Mode until Sysprep is run again.  While in Audit Mode, I cannot join the computer to the domain.  However, this is not a deal breaker as I can access my file shares without being joined to the domain.

When building this template, I don’t do a defrag or run the VMware OS Optimization tool as this template is the grandparent VM.  I will deploy my production parent VMs from this template and optimize them before deploying my instant clone or full clone pools.  I also don’t feel that defrag is needed with disposable VMs running on modern storage solutions.

My steps for building a Windows 10 virtual desktop template are:

1. Create the VM in vCenter.  Select the VMXNet3 network card as the network device and configure the VM to boot directly into the BIOS.  Also be sure to attach the Windows 10 ISO to the virtual machine.

2. Power the VM on.

3. Open the Console or use the remote console to access the VM.

4. Disable the Floppy drive and the Serial, Parallel, and Floppy Controllers in the BIOS.  Press F10 to save the settings and reboot.

5. Boot into the Windows Installation disk.

6. When you reach the first screen of the Windows installer, press Shift-F10 to open a command prompt.

7. Type diskpart to launch the disk partition utility.  We’ll use this to custom create our partition.  By default, the Windows installer creates a partition table that includes 100MB reserved space for Bitlocker.  Bitlocker isn’t supported in VDI, so we will manually create our partition.  The steps to do that are:

  • Type Select Disk 0
  • Type Create Partition Primary
  • Type Exit twice

8. Install Windows 10 using the default options.

9. When the system boots the Out-of-Box-Experience (Windows Welcome/Set up New Account), press Control-Shift-F3 to boot into Sysprep Audit Mode.

10. Install VMware Tools and reboot.

11.  Install the Horizon agent and reboot.  Note: You may need to connect to a network file share to access installers.  When doing so, sign in as Domain\User when prompted.  Do not join the system to the domain while in Audit Mode.

12. Install any applications and/or updates that you want to have in the template.  Reboot as often as required as the servers will boot into Audit Mode.

13.  Remove any Modern UI Apps that you don’t want to provision as part of the template.  I remove all except for Photos (haven’t found a good free alternative), Calculator (Windows 10 Calculator is actually pretty good), and Store (might need it depending on my use case/to keep the other two updated).  You actually need to deprovision it twice – once for the administrator account and once at the system level to remove the AppX Package.  The steps for this are:

  • Open PowerShell as an Administrator.
  • Run the following command to deprovision AppX Packages for all users: Get-AppXPackage  -allusers| Where {($ –notlike “*Photos*”) –and ($ –notlike “*Calculator*”) –and ($ –notlike “*Store*”)} | Remove-AppXPackage
  • Run the following command to uninstall unneeded AppX Packages: Get-AppXProvisionedPackage –online | Where {($ –notlike “*Photos*”) –and ($ –notlike “*Calculator*”) –and ($ –notlike “*Store*”)} | Remove-AppXProvisionedPackage –online

14.  Configure the application defaults for your administrator account.  This can be done in Settings –> System –> Default Apps.

15. Now we’re going to replace the default application associations.  Windows stores these in an XML file, and these associations are installed for each new user that logs into the system.  This file is called DefaultOEMAssociations.xml, and it is located in C:\Windows\System32.  The steps for this are:

  • Back up the C:\Windows\System32\DefaultOEMAssociations.xml file.
  • Open PowerShell as an Administrator
  • Run the following command to export your Administrator account default app associations:dism /online /Export-DefaultAppAssociations:”%userprofile%\Desktop\NewDefaultAppAssociations.xml”
  • Run the following command to import your new default app associations: dism /online /Import-DefaultAppAssociations:”%userprofile%\Desktop\NewDefaultAppAssociations.xml”

16. Reboot the system.

17. After the system reboots, the sysprep window will pop up.  Select “Out-of-Box Experience,” “Generalize,” and Shut Down.  Click OK to run sysprep.

18. After the VM shuts down, convert it to a template and deploy a test VM.  The VM should boot to the Out-of-Box-Experience.  You can also use a customization spec when deploying templates from the VM, and while it will boot to the Out-of-Box-Experience, the customization will still run.

So these are the basic steps that I do when building my Windows 10 template for VMware.  If you have any questions, please get my on Twitter at @seanpmassey.