lxndryng - a blog about nothing

Setting up open-source multi-factor authentication for Amazon WorkSpaces

Feb 09, 2017

AWS's Identity and Access Management (IAM) is a wonderful service that allows its users to leverage an incredibly powerful suite of fine-grained access controls to really implement the principle of least privilege to secure services hosted with AWS. It also happens to have a fairly simple multi-factor authentication (MFA) approach that uses the popular OATH TOTP (Time-based One Time Password) standard implemented across a number of virtual and hardware token generators.

Amazon's Desktop-as-a-Service WorkSpaces product, however, departs from this inherently de jure and de facto standards approach through TOTP and IAM for multi-factor authentication, rather leaving the users of the service to use a second factor of their choosing, as long as it can be handled through RADIUS: a problem which has recently caused me some issue at work. In the hope that no one should have to deal with this in the same way I did, it's probably worth going over where the issues start and how they can be addressed. It's probably just best to ignore the fact that RADIUS is a technology best left in the nineties.

WorkSpaces authentication architecture, in broad strokes

To use multi-factor authentication at all, it is necessary that the directory service that supports the WorkSpaces that one wishes to enable multi-factor authentication be a Microsoft Active Directory (AD) instance - if you were using Amazon's Simple Directory services, you're going to have to start again. In order to leverage an external AD instance, it is necessary to deploy an Amazon service called AD Connector into two subnets (for High Availability purposes, let's ignore the fact that we're only running a single domain controller - don't worry about it) within the VPC that is being used to host the WorkSpaces instances. It is the AD Connector service that provides the magic that will allow us to put an MFA solution into practice: configuration of a RADIUS server to be used as the second factor for authentication can be undertaken here.

In the context of the MFA flow for WorkSpaces, the public-facing brokering service that Amazon provides to enable connectivity over PCoIP to the Workspaces instance orchestrates the authentication flow such that initial authentication occurs with username and password against AD, with the username and provided MFA token being submitted to the RADIUS server in the event that the inital authentication is successful.

So what do we need?

If we assume that we don't have any authentication infrastructure outside of what we're putting in place for WorkSpaces, aside from the AD domain to be used as the first factor, we need:

  • A RADIUS server
  • A means to generate one-time passwords
  • Management infrastructure for the one-time passwords

Things of note

If your organisation's MFA approach is premised upon TOTP, you're going to be doing something non-compliant with that approach for WorkSpaces: Amazon (at time of writing) explicity - in a footnote in an FAQ - warns its users that TOTP is not supported. The only standardised OTP process that remains, then, is HOTP - an algorithm that relies upon a counter, so will probably cause you operational issues with users who may generate tokens without using them.

It is also necessary (for fairly common-sense reasons) that your user store called out to from RADIUS has the exact same usernames as those present in your Active Directory, and case sensitivity can be an issue here.

An open-source product selection for RADIUS and OTP generation

Much as my first inclination will be to prefer open source solutions, the first port of call for the RADIUS service to support WorkSpaces was Microsoft's Network Policy and Access Services: a quick answer was preferable to a philosophically satifying one. It turns out, however, that there is no OTP verification service available for integration with NPS that didn't cost money. Given the speed needed to get an MFA solution bottomed out, working through a corporate commercial process didn't seem that appealing.

The aptly named FreeRADIUS seemed a sensible choice for the RADIUS server, given its flexibility and support for a number of means of authorisation - in case no OTP mechanism would readily become available. After a little bit of digging, I found a PHP script/class called multiotp that seemed to offer the functionality that I required (HOTP), as well as being able to integrate with user lists from an AD server.

A VPC design for MFA-supporting WorkSpaces

Amazon VPC for MFA

MultiOTP configuration

While multiotp does offer a MySQL backend (which could be made readily resilient using AWS's Relational Database Service, this has been omitted here for the sake of simplicity: the flat file backend should be sufficient as long as we are sensible about syncing it between the two RADIUS servers. In order to set up a user, we can issue the command:

multiotp -create -no-prefix-pin [username] hotp [hexademical-encoded-seed] 1111

OpenSSL's rand command can be used with its -hex switch to generate a random hex string encoded to provide a suitable seed.

Following this, we can generate a QR code for the user to use to register WorkSpaces as an application in their software token generator:

multitop -qrcode [username] [file_path_for_png.png]

multiotp caveats

multiotp maintains its own user database incorporating some OTP-specific AD user synchronisation makes some unfortunate assumptions about the types of OTP you'll want to use: it will import all users with the assumption that they will be using TOTP, rather than the required HOTP here, with the CLI not currently presenting configuration options to change the algorithm associated with a user once set or to change the default algorithm used for AD-synced users.

I expect I'll submit some pull requests against their GitHub project in the fullness of time, but even with the caveats made explicit above, it does seem to be the most competent means of returning a RADIUS-compatible response from an OTP generation algorithm (a number of, in fact). Until Amazon does something more sensible around MFA for WorkSpaces, something that works will suffice when the alternative is nothing.

The seed provided to multiotp needs to be a hexademical string, while software tokens (such as Google Authenticator) will often require a base32-encoded version of the string used to generate the first hex string. The easier way around this is to use the token generation algorithm in the multiotp class and just generate a QR code using the CLI to be distributed to the user.

FreeRADIUS configuration

With a user account to actually test against, we need to configure FreeRADIUS to hand-off authentication requests to multiotp. In order to do this, we create a new module for authentication in /etc/raddb/modules/ called multiotp with the content below:

exec multiotp {  
    wait = yes  
    input_pairs = request  
    output_pairs = reply  
    program = "/path/to/multiotp '%{User-Name}' '%{User-Password}' -request-nt-key -src=%{Packet-Src-IP-Address} -chap-challenge=%{CHAP-Challenge} -chap-password=%{CHAP-Password} -ms-chap-challenge=%{MS-CHAP-Challenge} -ms-chap-response=%{MS-CHAP-Response} -ms-chap2-response=%{MS-CHAP2-Response}"  
    shell_escape = yes  

In the file /etc/raddb/sites-enabled/default, the directive multiotp should be added before the first instance of pap in the file, and the first instances of chap and mschap commented out with a hash (#). Additionally, the following should be added prior to the first Auth-Type PAP in the file:

Auth-Type multiotp {  

In /etc/raddb/sites-enabled/inner-tunnel, the first instances of chap and mschap should against be commented out, and the following added prior to the first Auth-Type PAP directive:

Auth-Type multiotp {  

The authorisation policy established above then needs to be enabled in /etc/raddb/policy.conf by adding the following just before the last } in the file:

multiotp.authorize {  
    if (!control:Auth-Type) {  
        update control {  
            Auth-Type := multiotp  

In /etc/raddb/clients.conf, appropriate client information should be populated, with [RADIUS shared secret] being replaced with a secure shared secret to be used to establish the RADIUS connection between AD Connector and FreeRADIUS:

client {  
    netmask = 0  
    secret = [RADIUS shared secret]  

Start the RADIUS server in debug mode with radiusd -X and leave it running: upon setting us the RADIUS server in AD Connector, we'll be able to make sure that things are working as they should here.

AD Connector configuration

In the AWS Console, MFA can be activated through the Update Details menu for directories defined within the WorkSpaces service. Enter the IP address of your RADIUS server and the shared secret defined earlier within the Multi-factor Authentication.

WorkSpaces MFA screen

Upon clicking update, you should see an authentication request from a user of awsfakeuser with the password badpassword. After a few minutes, the RADIUS service will be registered for the WorkSpaces directory. From here, try generating an MFA code for real and signing into a WorkSpace using the WorkSpaces client.