SSH Two-Factor Authentication with Duo Security


An ever increasing number of services start offering (and recommending) additional means of securing access to your accounts: Instead of just asking users to identify and authenticate themselves with a simple set of username and password, a second piece of information is requested.

Often this second piece of information is some kind of numeric code generated by a dedicated hardware token or – due to their near ubiquity – smartphone app. Only if you can provide a valid set of traditional credentials and the correct generated (and constantly changing) code are you allowed to log in.

This article describes how my colleague Lukas Pustina and I retrofitted our existing SSH servers to employ a convenient yet secure two-factor authentication by integrating the Duo Security service.


Usernames and passwords provide security, because only someone who knows the right combination can gain access to the respectively protected system. While generally viable, the main problem with this approach is that anyone who knows a valid set of credentials is admitted.

Unfortunately, credentials might easily fall into wrong hands. To thwart attacks that are based on key loggers, phishing emails, leaked password databases or other means to steal login data, modern systems do not just expect their users to know something (username, password), but also own something (the code generator).

Losing control over any one of the two factors does not pose an immediate security breach, because the second factor still ensures no one can illegally access your system. Instead, a compromised password can be reset or a lost or misplaced token invalidated and replaced, maintaining the integrity of the system under protection.


There are several protocols available to implement two-factor authentication systems. One of the more well known ones, probably due to it being used on sites like Github, Google or DropBox, is the Time-based One-Time Password Algorithm (TOTP for short). On initialization, a random secret is generated and shared between the authorization server and a token generator. Popular examples for software token generators are the free Google Authenticator or HDE OTP Generator apps, available for several mobile platforms.

In intervals of typically 30 or 60 seconds, the generator calculates a new numeric code based on the pre-shared key and the current time. The authentication server can then compare the user-provided code with the result of its own same calculation. For this two work, both token generator and server need to have their clocks be reasonably synchronized.


HDE OTP iPhone App showing TOTP tokens for several configured accounts.

A different option is the HMAC-based One-time Password algorithm (HOTP). Instead of relying on a synchronized clock, it uses a counter in conjunction with the shared secret to generate the one time codes. Moreover it not only allows the server to validate the identity of the client, but also vice-versa. By calculating not only the very next code in the sequence, the server can also pre-calculate the next few codes and send them to the client. By doing the same calculation, the client can be certain to be talking to the right server.


Most Linux/UNIX servers can only be accessed via SSH remotely. Apart from username and password tuples, SSH offers public key authentication, too, but regardless, it is still only a single factor. Fortunately, the OpenSSH daemon offers configuration options for additional factors.

One option would be to install and configure the Google Authenticator PAM Module for SSH (see Google Code).

While it improves security, it has a few drawbacks:

  • Each individual user needs to first generate a shared secret and install it into an appropriate token generator app.
  • On each log in the user needs to manually launch the app, read off the 6-8 digit code, and enter it in addition to the password.
  • To detect malicious login attempts it is necessary to monitor authorization logs for failed login attempts.

Duo Security

Duo Security offers a way around these drawbacks. Duo Security utilizes smartphones as the 2nd factor, but instead of relying on the user to read and type in a code, it uses push notifications to actively page registered users’ devices. Upon receiving the notification, the Duo Security app launches and users only have to acknowledge (or deny) the login attempt – see below.

In case the user is out of reach of a mobile network and cannot receive push notifications, short messages or even phone calls, there is a fallback TOTP code generator included in the app. Moreover, you can print out a list of emergency codes that can be used, e. g., when the phone’s battery is empty.

Duo App Fallback TOTP codes

Duo iPhone app showing a fallback TOTP code.


For Duo Security to work, a helper utility needs to be installed on the servers. You can either install duo_unix from your distributions standard repositories (which might be behind the most recent version), from Duo Security’s own repository, or by downloading the source and compiling it yourself.

Once installed, you log in to the Duo Security website and create a new Integration for your server. This creates an integration key, a shared secret and provides an API URL which you copy and paste into your /etc/duo/login_duo.conf configuration file:

ikey = <your-integration-key>
skey = <your-secret-key>
host = <api-host>

This is the minimum configuration necessary for duo_unix itself. You can try it out by entering the following command:

$ /usr/sbin/login_duo
Please enroll at

This will connect to the configured API host and check if your current user account has already been enrolled. If not, you are given a unique URL and information about how to enroll. Visiting this URL on your phone with the Duo Security app installed  connects this phone to the user account. Of course, this process can also be performed by an administrator directly on the website, both for individual and bulk enrollments.

Once the user account is set up, running the command again will yield a different result:
$ /usr/sbin/login_duo

Duo two-factor login for <username>
Enter a passcode or select one of the following options:
1. Duo Push to <phone-number>
2. Phone call to <phone-number>
3. SMS passcodes to <phone number> (next code starts with <n>)
Passcode or option (1-3): 1
Pushed a login request to your phone...
Success. Logging you in...

Choosing 1 will almost immediately deliver a push notification to you phone. From this notification you can automatically launch the app and confirm or reject the login:

Duo Push Notification

Push Notification, informing me about an attempted login (left).

Duo App Accept/Reject Screen

Details about attempted login, waiting for my approval (right)

SSH Daemon Integration

Once this is working, you want to run login_duo as a part of your SSH login. There are several ways to do this, depending on your current SSH setup. If you are using plain SSH username and password authentication, you can use the Duo Unix PAM integration. However, if you are relying on public key based authentication (like we do), this is not an option, because most SSH servers will skip the whole PAM process if a valid key is provided.

Patches for OpenSSH that allow several authentication factors at the same time as key files are part of some distributions already, but on our Ubuntu 13.10 this is not an option yet.

The method of choice there is to configure OpenSSH to run the login_duo command once the user’s key has been accepted. To do so, add this to /etc/ssh/sshd_config:

ForceCommand /usr/sbin/login_duo

This will ensure the login_duo command is run for each user.

Duo Security recommends to disable Port Forwarding and Tunneling, because due to the nature of the protocol, the command runs after the connection has already been established. Following this recommendation requires adding these two directives to sshd_config:

PermitTunnel no
AllowTcpForwarding no

Additional Configuration

On our severs we have configured a few optional settings in login_duo.conf:

pushinfo = yes
autopush = yes
failmode = secure
group = adm

From top to bottom these mean:

  • Include additional information in the push message to be displayed in the app.
  • Always try push notifications first, instead of letting the user pick. After a timeout, you may select one of the other options.
  • Duo Security login must be performed to allow access.
  • Only request Duo Security login for members of the adm group.

In conjunction with the group setting, our sshd_config includes an AllowGroups adm directive to only allow SSH logins for members of this group. This combination of parameters is designed to protect remote logins as well as possible, while not locking out users on the system console.


Instead of setting up time-based one time passwords on our servers using, e g., Google Authenticator, we decided to set up Duo Security to mitigate typical attack patterns.

The system is low cost (up to 10 users are free) and widely used by numerous well-known companies, e. g. Facebook, Twitter, and Accenture. The web dashboard provides convenient user management and login auditing. In addition, having the mobile app connect out-of-band via the mobile network provides a high level of convenience, because there is no need to manually enter any codes.

Feel free to contact us if you have questions and comments.



  • Mike Schwartz

    What about using a voice phone call for those of us with basic phones and no text messaging plan? Google and Microsoft both use this option.

    • Daniel Schneller

      27. June 2014 von Daniel Schneller

      Good point. If you look closely, the response that is shown when attempting to log in presents three options, one of them being push notifications. The other two are SMS and phone call. In contrast to the push notifications, which are free, texting or calling your phone will cost you additional money, but it certainly is possible.

