Two-Factor Authentication With Google Authenticator And APM
Introduction
Two-factor authentication (TFA) has been around for many years and the concept far pre-dates computers. The application of a keyed padlock and a combination lock to secure a single point would technically qualify as two-factor authentication: “something you have,” a key, and “something you know,” a combination. Until the past few years, two-factor authentication in its electronic form has been reserved for high security environments: government, banks, large companies, etc. The most common method for implementing a second authentication factor has been to issue every employee a disconnected time-based one-time password hard token. The term “disconnected” refers to the absence of a connection between the token and a central authentication server. A “hard token” implies that the device is purpose-built for authentication and serves no other purpose. A soft or “software” token on the other hand has other uses beyond providing an authentication mechanism. In the context of this article we will refer to mobile devices as a soft tokens. This fits our definition as the device an be used to make phone calls, check email, surf the Internet, all in addition to providing a time-based one-time password.
A time-based one-time password (TOTP) is a single use code for authenticating a user. It can be used by itself or to supplement another authentication method. It fits the definition of “something you have” as it cannot be easily duplicated and reused elsewhere. This differs from a username and password combination, which is “something you know,” but could be easily duplicated by someone else. The TOTP uses a shared secret and the current time to calculate a code, which is displayed for the user and regenerated at regular intervals. Because the token and the authentication server are disconnected from each other, the clocks of each must be perfectly in sync. This is accomplished by using Network Time Protocol (NTP) to synchronize the clocks of each device with the correct time of central time servers.
Using Google Authenticator as a soft token application makes sense from many angles. It is low cost due to the proliferation of smart phones and is available from the “app store” free of charge on all major platforms. It uses an open standard (defined by RFC 4226), which means that it is well-tested, understood, secure. Calculation as you will later see is well-documented and relatively easy to implement in your language of choice (iRules in our case). This process is explained in the next section.
This Tech Tip is a follow-up to Two-Factor Authentication With Google Authenticator And LDAP. The first article in this series highlighted two-factor authentication with Google Authenticator and LDAP on an LTM. In this follow-up, we will be covering implementation of this solution with Access Policy Manager (APM). APM allows for far more granular control of network resources via access policies. Access policies are rule sets, which are intuitively displayed in the UI as flow charts. After creation, an access policy is applied to a virtual server to provide security, authentication services, client inspection, policy enforcement, etc. This article highlights not only a two-factor authentication solution, but also the usage of iRules within APM policies. By combining the extensibility of iRules with the APM’s access policies, we are able to create virtually any functionality we might need.
Note: A 10-user fully-featured APM license is included with every LTM license. You do not need to purchase an additional module to use this feature if you have less than 10 users.
Calculating The Google Authenticator TOTP
The Google Authenticator TOTP is calculated by generating an HMAC-SHA1 token, which uses a 10-byte base32-encoded shared secret as a key and Unix time (epoch) divided into a 30 second interval as inputs. The resulting 80-byte token is converted to a 40-character hexadecimal string, the least significant (last) hex digit is then used to calculate a 0-15 offset. The offset is then used to read the next 8 hex digits from the offset. The resulting 8 hex digits are then AND’d with 0x7FFFFFFF (2,147,483,647), then the modulo of the resultant integer and 1,000,000 is calculated, which produces the correct code for that 30 seconds period.
Base32 encoding and decoding were covered in my previous Tech Tip titled Base32 Encoding And Decoding With iRules . The Tech Tip details the process for decoding a user’s base32-encoded key to binary as well as converting a binary key to base32.
The HMAC-SHA256 token calculation iRule was originally submitted by Nat to the Codeshare on DevCentral. The iRule was slightly modified to support the SHA-1 algorithm, but is otherwise taken directly from the pseudocode outlined in RFC 2104.
These two pieces of code contribute the bulk of the processing of the Google Authenticator code. The rest is done with simple bitwise and arithmetic functions.
Triggering iRules From An APM Access Policy
Our previously published Google Authenticator iRule combined the functionality of Google Authenticator token verification with LDAP authentication. It was written for a standalone LTM system without the leverage of APM’s Visual Policy Editor. The issue with combining these two authentication factors in a single iRule is that their functionality is not mutually exclusive or easily separable. We can greatly reduce the complexity of our iRule by isolating functionality for Google Authenticator token verification and moving the directory server authentication to the APM access policy.
APM iRules differ from those that we typically develop for LTM. iRules assigned to LTM virtual server are triggered by events that occur during connection or payload handling. Many of these events still apply to an LTM virtual server with an APM policy, but do not have perspective into the access policy. This is where we enter the realm of APM iRules. APM iRules are applied to a virtual server exactly like any other iRule, but are triggered by custom iRule event agent IDs within the access policy. When the access policy reaches an iRule event, it will trigger the ACCESS_POLICY_AGENT_EVENT iRule event. Within the iRule we can execute the ACCESS::policy agent_id command to return the iRule event ID that triggered the event. We can then match on this ID string prior to executing any additional code. Within the iRule we can get and set APM session variables with the ACCESS::session command, which will serve as our conduit for transferring variables to and from our access policy. A visual walkthrough of this paragraph is shown below.
iRule Trigger Process
- Create an iRule Event in the Visual Policy Editor
- Specify a Name for the object and an ID for the Custom iRule Event Agent
- Create an iRule with the ID referenced and assign it to the virtual server
1: when ACCESS_POLICY_AGENT_EVENT { 2: if { [ACCESS::policy agent_id] eq "ga_code_verify" } { 3: # get APM session variables 4: set username [ACCESS::session data get session.logon.last.username] 5: 6: ### Google Authenticator token verification (code omitted for brevity) ### 7: 8: # set APM session variables 9: ACCESS::session data set session.custom.ga_result $ga_result 10: } 11: }
- Add branch rules to the iRule Event which read the custom session variable and handle the result
Google Authenticator Two-Factor Authentication Process
Two-Factor Authentication Access Policy Overview
Rather than walking through the entire process of configuring the access policy from scratch, we’ll look at the policy (available for download at the bottom of this Tech Tip) and discuss the flow. The policy has been simplified by creating macros for the redundant portions of the authentication process: Google Authenticator token verification and the two-factor authentication processes for LDAP and Active Directory.
The “Google Auth verification” macro consists of an iRule event and 5 branch rules. The number of branch rules could be reduced to just two: success and failure. This would however limit our diagnostic capabilities should we hit a snag during our deployment, so we added logging for all of the potential failure scenarios. Remember that these logs are sent to APM reporting (Web UI: Access Policy > Reports) not /var/log/ltm. APM reporting is designed to provide per-session logging in the user interface without requiring grepping of the log files.
The LDAP and Active Directory macros contain the directory server authentication and query mechanisms. Directory server queries are used to retrieve user information from the directory server. In this case we can store our Google Authenticator key (shared secret) in a schema attribute to remove a dependency from our BIG-IP. We do however offer the ability to store the key in a data group as well.
The main portion of the access policy is far simpler and easier to read by using macros. When the user first enters our virtual server we look at the Landing URI they are requesting. A first time request will be sent to the “normal” logon page. The user will then input their credentials along with the one-time password provided by the Google Authenticator token. If the user’s credentials and one-time password match, they are allowed access. If they fail the authentication process, we increment a counter via a table in our iRule and redirect them back to an “error” logon page. The “error” logon page notifies them that their credentials are invalid. The notification makes no reference as to which of the two factors they failed. If the user exceeds the allowed number of failures for a specified period of time, their session will be terminated and they will be unable to login for a short period of time. An authenticated user would be allowed access to secured resources for the duration of their session.
Deploying Google Authenticator Token Verification
This solution requires three components (one optional) for deployment:
- Sample access policy
- Google Authenticator token verification iRule
- Google Authenticator token generation iRule (optional)
The process for deploying this solution has been divided into four sections:
Configuring a AAA server
- Login to the Web UI of your APM
- From the side panel select Access Policy > AAA Servers > Active Directory, then the + next to the text to create a new AD server
- Within the AD creation form you’ll need to provide a Name, Domain Controller, Domain Name, Admin Username, and Admin Password
- When you have completed the form click Finished
Copy the iRule to BIG-IP and configure options
- Download a copy of the Google Authenticator Token Verification iRule for APM from the DevCentral CodeShare (hint: this is much easier if you “edit” the wiki page to display the source without the line numbers and formatting)
- Navigate to Local Traffic > iRules > iRule List and click the + symbol
- Name the iRule '”google_auth_verify_apm,” then copy and paste the iRule from the CodeShare into the Definition field
- At the top of the iRule there are a few options that need to be defined:
- lockout_attempts - number of attempts a user is allowed to make prior to being locked out temporarily (default: 3 attempts)
- lockout_period - duration of lockout period (default: 30 seconds)
- ga_code_form_field - name of HTML form field used in the APM logon page, this field is define in the "Logon Page" access policy object (default: ga_code_attempt)
- ga_key_storage - key storage method for users' Google Authenticator shared keys, valid options include: datagroup, ldap, or ad (default: datagroup)
- ga_key_ldap_attr - name of LDAP schema attribute containing users' key
- ga_key_ad_attr - name of Active Directory schema attribute containing users' key
- ga_key_dg - data group containing user := key mappings
- Click Finished when you’ve configured the iRule options to your liking
Import sample access policy
- From the Web UI, select Access Policy > Access Profiles > Access Profiles List
- In the upper right corner, click Import
- Download the sample policy for Two-Factor Authentication With Google Authenticator And APM and extract the .conf from ZIP archive
- Fill in the New Profile Name with a name of your choosing, then select Choose File, navigate to the extracted sample policy and Open
- Click Import to complete the import policy
- The sample policy’s AAA servers will likely not work in your environment, from the Access Policy List, click Edit next to the imported policy
- When the Visual Policy Editor opens, expand the macro (LDAP or Active Directory auth) that describe your environment
- Click the AD Auth object, select the AD server from the drop-down that was defined earlier in the AAA Servers step, then click Save
- Repeat this process for the AD Query object
Assign sample policy and iRule to a virtual server
- From the Web UI, select Local Traffic > Virtual Servers > Virtual Server List, then the create button (+)
- In the New Virtual Server form, fill in the Name, Destination address, Service Port (should be HTTPS/443), next select an HTTP profile and an SSL Profile (Client).
- Next you’ll add a SNAT Profile if needed, an Access Profile, and finally the token verification iRule
- Depending on your deployment you may want to add a pool or other network connectivity resources
- Finally click Finished
At this point you should have a function virtual server that is serving your access policy. You’ll now need to add some tokens for your users. This process is another section on its own and is listed below.
Generating Software Tokens For Users
In addition to the Google Authenticator Token Verification iRule for APM we also wrote a Google Authenticator Soft Token Generator iRule that will generate soft tokens for your users. The iRule can be added directly to an HTTP virtual server without a a pool and accessed directly to create tokens. There are a few available fields in the generator: account, pre-defined secret, and a QR code option. The “account” field defines how to label the soft token within the user’s mobile device and can be useful if the user has multiple soft token on the same device (I have 3 and need to label them to keep them straight). A 10-byte string can be used as a pre-defined secret for conversion to a base32-encoded key. We will advise you against using a pre-defined key because a key known to the user is something they know (as opposed to something they have) and could be potentially regenerate out-of-band thereby nullifying the benefits of two-factor authentication. Lastly, there is an option to generate a QR code by sending an HTTPS request to Google and returning the QR code as an image. While this is convenient, this could be seen as insecure since it may wind up in Google’s logs somewhere. You’ll have to decide if that is a risk you’re willing to take for the convenience it provides.
Once the token has been generated, it will need to be added to a data group on the BIG-IP:
- Navigate to Local Traffic > iRules > Data Group Lists
- Select Create from the upper right-hand corner if the data group does not yet exist. If it exists, just select it from the list.
- Name the data group “google_auth_keys” (data group name can be changed in the beginning section of the iRule)
- The type of data group will be String
- Type the “username” into the String field and paste the “Google Authenticator key” into the Value field
- Click Add and the username/key pair should appear in the list as such: user := ONSWG4TFOQYTEMZU
- Click Finished when all your username/key pairs have been added.
Your user can scan the QR code or type it into their device manually. After they scan the QR code, the account name should appear along with the TOTP for the account. The image below is how the soft token appears in the Google Authenticator iPhone application:
Once again, do not let the user leave with a copy of the plain text key. Knowing their key value will negate the value of having the token in the first place. Once the key has been added to the BIG-IP, the user’s device, and they’ve tested their access, destroy any reference to the key outside the BIG-IPs data group.If you’re worried about having the keys in plain text on the BIG-IP, they can be encrypted with AES or stored off-box in LDAP and only queried via secure connection. This is beyond the scope of this article, but doable with iRules.
Code
Google Authenticator Token Verification iRule for APM – Documentation and code for the iRule used in this Tech Tip
Google Authenticator Soft Token Generator iRule – iRule for generating soft tokens for users
Sample Access Policy: Two-Factor Authentication With Google Authenticator And APM – APM access policy
Reference Materials
RFC 4226 - HOTP: An HMAC-Based One-Time Password Algorithm
RFC 2104 - HMAC: Keyed-Hashing for Message Authentication
RFC 4648 - The Base16, Base32, and Base64 Data Encodings
SOL3122: Configuring the BIG-IP system to use an NTP server using the Configuration utility – Information on configuring time servers
Configuration Guide for BIG-IP Access Policy Manager – The “big book” on APM configurations
Configuring Authentication Using AAA Servers – Official F5 documentation for configuring AAA servers for APM
Troubleshooting AAA Configurations – Extra help if you hit a snag configuring your AAA server
- LeonardoF5_1747Nimbostratus
Hi Sohaib Atta, can you resolve the issue ? I have the same isuee...Thank you.
I just noticed that if the user mapping is removed from the data-group then the macro always directs the session to branch2 (No google auth key found). however if the user mapping is present in the data-group the session always directs to fallback branch. Any ideas what might be the issue?
I am using this for a web based service. The VPE configured is a follows:
Macro configuration is:
While testing it seems to be directed to the fallback branch in the macro ultimately resulting in a deny I am using the Google Authenticator Soft Token Generator code with another VS for linking with google authenticator app. The key generated that particular VS is added to the data group. What am I missing ?
- David_adasha_30Nimbostratus
Hi,
Great article!!! thank you.
Does any one know how to import the sample access policy ? it is does not work for me.
- bulldoza99_2458Nimbostratus
Has anyone done this on v13.0 ? running into some issues where the irule seems to be failing on the policy.
I get Rule to evaluate = ""
and then it goes into failback I can see session.logon.last.ga_code_attempt is in there and valid but not sure how to debug the last bit
- am_gliAltostratus
I've got this running on 12.1. For me the code worked as is, except that I think that some of the naming in this guide seems to be messed up a bit (irule/datagroup).
After I changed the names properly, it works great.
- Hey All, Sample access policy is importable on the BIG-IP 11.3. No error by doing that. From there you can upgrade the BIG-IP to higher versions, or manually replicate the configuration on another BIG-IP such as 11.6 or 12. I am currently doing this on the 12.0 and it is working out fine.
- Been using this code for awhile now and one of the things i noticed is some of the time on people's device are off by a few seconds that can mess with the token on their end. Is it possible to modify this code so that its checks what they enter, fail it and then run the code again but this time run the code with "time-30 seconds" so that it basically approves the token that is valid right now and the token that was valid before.
- Bill_Chipman_10NimbostratusThe iRule is now working as expected (I added some log statements to catch the userid/code entered/code calculated/return value. However, the branch rules aren't working. I get an error "Rule evaluation failed with error: invalid command name "expr { 0 == 0}".
- wonsoo_41223Historic F5 AccountWhen I setup Google OTP on the google OTP app, and it generates 32 char length key instead of 16. the iRule need to change this code's value from 16 to 32 if { [string length $ga_key] == 32 } {