Search for blog posts, documentation, or pages

Documentation

Duo Unix - Two-Factor Authentication for SSH

Duo can be easily added to any Unix system to protect remote (SSH) or local logins. It has been tested on Linux (RedHat, Fedora, CentOS, Debian, Ubuntu, Gentoo, Amazon Linux), BSD (FreeBSD, NetBSD, OpenBSD, MacOS X), Solaris, HP-UX, and AIX.

Walkthrough Video

Overview

Duo can be enabled on any Unix system with the addition of a simple login_duo utility or pam_duo PAM module. The code is open-source and available on GitHub.

First Steps

Before starting:

  1. Sign up for a Duo account.
  2. Log in to the Duo Admin Panel and navigate to Applications.
  3. Click Add an application and select UNIX Application from the list. Click Add this application to get your integration key, secret key, and API hostname. See Getting Started for help.
Connectivity Requirements

This integration communicates with Duo’s service on TCP port 443. Also, we do not recommend locking down your firewall to individual IP addresses, since these may change over time to maintain our service’s high availability.

Instructions

Set up login_duo

OpenSSL development headers and libraries are required for login_duo, so you’ll want to install those first. libpam is also a required dependency for pam_duo. When compiling on SUSE/SLES, the zlib package is also necessary.

Dependency Platform Installation
OpenSSL FreeBSD, NetBSD Installed by default
Debian, Ubuntu apt-get install libssl-dev
Red Hat, Fedora, CentOS, Amazon Linux yum install openssl-devel
SUSE/SLES zypper install libopenssl-devel
Solaris pkg install openssl
HP-UX, AIX 3rd party packages or source build
libpam FreeBSD, NetBSD, Mac OS X, Solaris, HP-UX, AIX Installed by default
Debian, Ubuntu apt-get install libpam-dev
Red Hat, Fedora, CentOS, Amazon Linux yum install pam-devel
SUSE/SLES zypper install pam-devel
zlib SUSE/SLES zypper install zlib-devel

Once the required dependencies are installed, you need to download, build, and install the latest version of duo_unix (checksum here).

$ wget https://dl.duosecurity.com/duo_unix-latest.tar.gz
$ tar zxf duo_unix-latest.tar.gz
$ cd duo_unix-1.9.15
$ ./configure --prefix=/usr && make && sudo make install

For advanced build options, see the README file in the source tarball.

Once duo_unix is installed, edit login_duo.conf (in /etc/duo or /etc/security) to add your integration key, secret key, and API hostname:

[duo]
; Duo integration key
ikey = INTEGRATION_KEY
; Duo secret key
skey = SECRET_KEY
; Duo API hostname
host = API_HOSTNAME

The login_duo binary is marked setuid in order to read the protected login_duo.conf configuration file. However, privileges are dropped immediately after, so the privilege escalation attack surface is minimal.

Test login_duo

As a regular user, test login_duo manually by running

$ /usr/sbin/login_duo

On some systems, you may instead have to run /usr/local/sbin/login_duo.

If everything is set up correctly, you’ll be given an enrollment link and prompted to enroll:

Visit the URL, enroll your phone, and then try login_duo again, this time adding a command to run after authentication is complete:

$ /usr/sbin/login_duo echo 'YOU ROCK!'

You should see something like this:

If you are having trouble with these steps, or if you aren’t getting a Duo login prompt, try running login_duo with the -d flag to enable debug output.

Enable login_duo

To protect remote access via SSH, use login_duo.

To enable two-factor authentication for any SSH login method (password, pubkey, etc.) for any user, edit your sshd_config (usually in /etc or /etc/ssh) to add the following line:

ForceCommand /usr/sbin/login_duo

This ForceCommand directive instructs sshd to run login_duo (to perform two-factor authentication) before any other requested commands. However, according to the sshd documentation: “The command is invoked by using the user’s login shell with the -c option.” This means that shell rc files (e.g. .bashrc, .cshrc, etc.) execute before login_duo; if users can edit these files, they may be able to disable Duo authentication for their own accounts. Mitigate this by deploying pam_duo instead of login_duo.

We strongly recommend that you disable PermitTunnel and AllowTcpForwarding in your sshd_config when using login_duo to protect SSH logins. Since OpenSSH sets up port forwarding and tunneling before Duo’s two-factor challenge, an attacker may be able to access internal services via port forwarding before completing secondary authentication. Adding the following lines to your sshd_config will prevent this scenario:

PermitTunnel no
AllowTcpForwarding no

You can also optionally limit two-factor authentication to a subset of users by UID or group in login_duo.conf. For example:

group = wheel

If you’d like to enable Duo for only for specific accounts using SSH pubkeys, use the command option in those users’ authorized_keys instead. For example, to verify each admin authorized to log into a shared root account, your ~/.ssh/authorized_keys might look something like this:

command="/usr/sbin/login_duo -f user1" ssh-dss FRP...FD== user1@company
command="/usr/sbin/login_duo -f user2" ssh-dss YUX...IO== user2@company

Now restart the SSH service.

This also works for user-local installations (e.g. in $HOME/bin) without root access — just specify the location of login_duo.conf with the -c flag.

Configuration Options

The login_duo.conf and pam_duo.conf configuration files use the INI format. They can take the following options:

Key Required? Description
ikey Required Your integration key
skey Required Your secret key
host Required Your API hostname (i.e. api-XXXXXXXX.duosecurity.com
groups Optional

If specified, Duo authentication is required only for users whose primary group or supplementary group list matches one of the space-separated pattern lists.

failmode Optional

On service or configuration errors that prevent Duo authentication, fail “safe” (allow access) or “secure” (deny access). The default is “safe”.

pushinfo Optional

Include information such as the command to be executed in the Duo Push message. Either “yes” or “no”. The default is “no”.

http_proxy Optional

Use the specified HTTP proxy, same format as the HTTP_PROXY environment variable. (honored by wget, curl, etc.).

autopush Optional

Either “yes” or “no”. Default is “no”. If “yes”, Duo Unix will automatically send a push login request to the user’s phone, falling back on a phone call if push is unavailable. If “no”, the user will be prompted to choose an authentication method.

When configured with autopush = yes, we recommend setting prompts = 1.

motd Optional

Print the contents of /etc/motd to screen after a successful login. Either “yes” or “no”. The default is “no”.

This option is only available for login_duo.

prompts Optional

If a user fails to authenticate with a second factor, Duo Unix will prompt the user to authenticate again. This option sets the maximum number of prompts that Duo Unix will display before denying access. Must be 1, 2, or 3. Default is 3.

For example, when prompts = 1, the user will have to successfully authenticate on the first prompt, whereas if prompts = 2, if the user enters incorrect information at the initial prompt, he/she will be prompted to authenticate again.

When configured with autopush = yes, we recommend setting prompts = 1.

accept_env_factor Optional

Look for factor selection or passcode in the $DUO_PASSCODE environment variable before prompting the user for input. When $DUO_PASSCODE is non-empty, it will override autopush.

The SSH client will need SendEnv DUO_PASSCODE in its configuration, and the SSH server will similarily need AcceptEnv DUO_PASSCODE.

Default is "no".

fallback_local_ip Optional

Duo Unix reports the IP address of the authorizing user, for the purposes of authorization and whitelisting. If Duo Unix cannot detect the IP address of the client, setting fallback_local_ip = yes will cause Duo Unix to send the IP address of the server it is running on.

If you are using IP whitelisting, enabling this option could cause unauthorized logins if the local IP is listed in the whitelist.

https_timeout Optional

Set to the number of seconds to wait for HTTPS responses from Duo Security. If Duo Security takes longer than the configured number of seconds to respond to the preauth API call, the configured failmode is triggered. Other network operations such as DNS resolution, TCP connection establishment, and the SSL handshake have their own independent timeout and retry logic.

Default is 0, which disables the HTTPS timeout.

Example (fake) configuration file:

[duo]
ikey=BRTYMPKRR8TI06H8Y938
skey=V8hLztP5rb8L78C4wWkpnmSGvqTPQqqj5NoRbbYu
host=api-5c3dee43.duosecurity.com
pushinfo=yes
autopush=yes

For more information, see the man page for login_duo.

PAM Configuration

You can deploy pam_duo instead of login_duo to provide a more comprehensive coverage of PAM-enabled applications (like su, sudo, ftpd, etc.).

First, configure, build, and install the integration:

./configure --with-pam --prefix=/usr && make && sudo make install

Now modify your pam_duo.conf file to enter your keys and api-hostname. You should be able to find this file in /etc/duo/pam_duo.conf. This file takes the same configuration options as login_duo.conf, except where otherwise noted.

Next, you’ll need to modify your system’s PAM configuration to include a line like the following:

auth required pam_duo.so

Depending on your OS or architecture, the pam_duo.so module might be in /lib64/security instead of the default location /lib/security. If so, specify the full path to pam_duo.so in the PAM config file.

The location of this line and the specified control flag (eg. “required”, “requisite”, “sufficient”) varies. For most common configurations, place pam_duo directly after pam_unix (frequently found in common-auth or system-auth on Linux), set pam_unix’s control flag to “requisite”, and set pam_duo’s control flag to whatever pam_unix used to be.

If you want to use pam_duo with OpenSSH sshd, set both UsePAM and ChallengeResponseAuthentication to yes in your sshd_config. You should also set UseDNS to no so that PAM Duo is always passed the IP address of the connecting user, rather than the resolved hostname.

UsePAM yes
ChallengeResponseAuthentication yes
UseDNS no

Public Key Authentication

In addition to the configuration above, if you would like to use pam_duo with SSH public key authentication, set PubkeyAuthentication to yes, PasswordAuthentication to no, and AuthenticationMethods to publickey,keyboard-interactive in sshd_config. This feature is only available with OpenSSH 6.2+, SSH protocol 2, and Duo Unix 1.9.15 or later.

PubkeyAuthentication yes
PasswordAuthentication no
AuthenticationMethods publickey,keyboard-interactive

We recommend leaving a root shell open while making any changes to your PAM configuration, in order to prevent accidentally locking yourself out. Additionally, always make sure your PAM configuration works locally, before testing it with SSH logins.

The following are some PAM configuration examples for common Linux systems:

Ubuntu

/etc/pam.d/common-auth

Before:

auth [success=1 default=ignore]  pam_unix.so nullok_secure
auth    requisite pam_deny.so

After:

auth requisite pam_unix.so nullok_secure
auth    [success=1 default=ignore]  pam_duo.so
auth    requisite pam_deny.so

SSH Public Key Authentication

/etc/pam.d/sshd

Before:

@include common-auth

After:

auth    required pam_duo.so

CentOS

/etc/pam.d/system-auth

Before:

auth required    pam_env.so
auth    sufficient  pam_unix.so nullok try_first_pass
auth    requisite   pam_succeed_if.so uid >= 500 quiet
auth    required    pam_deny.so

After:

auth required    pam_env.so
auth    requisite   pam_unix.so nullok try_first_pass
auth    sufficient  pam_duo.so
auth    requisite   pam_succeed_if.so uid >= 500 quiet
auth    required    pam_deny.so

SSH Public Key Authentication

/etc/pam.d/sshd

Before:

auth    required    pam_sepermit.so
auth    substack    password-auth
auth    include     postlogin

After:

auth    required    pam_sepermit.so
auth    required    pam_duo.so
auth    include     postlogin

If you are running SELinux you must also update your policies to include authlogin_duo:

sudo make -C pam_duo semodule

*This allows sshd to make outgoing HTTP connections, which is required for Duo authentication to complete.

Amazon Linux

/etc/pam.d/system-auth

Before:

auth required    pam_env.so
auth    sufficient  pam_unix.so nullok try_first_pass
auth    requisite   pam_succeed_if.so uid >= 500 quiet
auth    required    pam_deny.so

After:

auth required    pam_env.so
auth    requisite   pam_unix.so nullok try_first_pass
auth    sufficient  pam_duo.so
auth    requisite   pam_succeed_if.so uid >= 500 quiet
auth    required    pam_deny.so

SSH Public Key Authentication

/etc/pam.d/sshd

Before:

auth    required    pam_sepermit.so
auth    substack    password-auth

After:

auth    required    pam_sepermit.so
auth    required    pam_duo.so

FreeBSD

/etc/pam.d/system

Before:

# auth
auth            sufficient      pam_opie.so             no_warn no_fake_prompts
auth            requisite       pam_opieaccess.so       no_warn allow_local
#auth           sufficient      pam_krb5.so             no_warn try_first_pass
#auth           sufficient      pam_ssh.so              no_warn try_first_pass
auth            required        pam_unix.so             no_warn try_first_pass nullok

After:

# auth
auth            sufficient      pam_opie.so             no_warn no_fake_prompts
auth            requisite       pam_opieaccess.so       no_warn allow_local
#auth           sufficient      pam_krb5.so             no_warn try_first_pass
#auth           sufficient      pam_ssh.so              no_warn try_first_pass
auth            requisite       pam_unix.so             no_warn try_first_pass nullok
auth            requisite       pam_duo.so

SSH Public Key Authentication

/etc/pam.d/sshd

Before:

# auth
auth            sufficient      pam_opie.so             no_warn no_fake_prompts
auth            requisite       pam_opieaccess.so       no_warn allow_local
#auth           sufficient      pam_krb5.so             no_warn try_first_pass
#auth           sufficient      pam_ssh.so              no_warn try_first_pass
auth            required        pam_unix.so             no_warn try_first_pass

After:

# auth
auth            sufficient      pam_opie.so             no_warn no_fake_prompts
auth            requisite       pam_opieaccess.so       no_warn allow_local
#auth           sufficient      pam_krb5.so             no_warn try_first_pass
#auth           sufficient      pam_ssh.so              no_warn try_first_pass
#auth           required        pam_unix.so             no_warn try_first_pass
auth            required        pam_duo.so

Gentoo

/etc/pam.d/system-auth

Before:

auth required    pam_env.so 
auth    required    pam_unix.so try_first_pass likeauth nullok

After:

auth required    pam_env.so 
auth    requisite   pam_unix.so try_first_pass likeauth nullok 
auth    required    pam_duo.so

Linux Distribution Packages

To more easily install and maintain Duo Unix deployments, we’ve built Linux packages for a variety of popular distributions. These packages are tested against the specific listed versions of their respective distributions. Please test all packages thoroughly prior to deploying them into your environment to ensure a great experience.

Red Hat Enterprise Linux

Tested against 6.4 32/64-bit and 7.0 64-bit

Create /etc/yum.repos.d/duosecurity.repo with the following contents:

[duosecurity]
name=Duo Security Repository
baseurl=http://pkg.duosecurity.com/RedHat/$releasever/$basearch
enabled=1
gpgcheck=1

Execute the following shell commands:

# rpm --import https://www.duosecurity.com/RPM-GPG-KEY-DUO
# yum install duo_unix

CentOS

Tested against 5.9 32/64-bit and 6.4 32/64-bit installed via Yum, and 7.0-1406 64-bit when built from source

Create /etc/yum.repos.d/duosecurity.repo with the following contents:

[duosecurity]
name=Duo Security Repository
baseurl=http://pkg.duosecurity.com/CentOS/$releasever/$basearch
enabled=1
gpgcheck=1

Execute the following shell commands:

# rpm --import https://www.duosecurity.com/RPM-GPG-KEY-DUO
# yum install duo_unix

Debian

Tested against 7.1 32/64-bit

Create /etc/apt/sources.list.d/duosecurity.list with the following contents:

deb http://pkg.duosecurity.com/Debian wheezy main

Execute the following shell commands:

# curl -s https://www.duosecurity.com/APT-GPG-KEY-DUO | sudo apt-key add -
# apt-get update && apt-get install duo-unix

Ubuntu

Tested against 12.04.3 32/64-bit and 14.04 32/64-bit

Create /etc/apt/sources.list.d/duosecurity.list with the following contents:

deb http://pkg.duosecurity.com/Ubuntu precise main

or

deb http://pkg.duosecurity.com/Ubuntu trusty main

Execute the following shell commands:

# curl -s https://www.duosecurity.com/APT-GPG-KEY-DUO | sudo apt-key add -
# apt-get update && apt-get install duo-unix

Puppet Module

For environments that utilize Puppet we offer a module to deploy and manage Duo Unix. This module will handle configuration of our Linux package repositories, package installation, and configuration of either login_duo or pam_duo. If you’d like to contribute to its development, please visit our Github project page.

To install the module for deployment:

# puppet module install duosecurity/duo_unix

Please be sure to view the README for details on configuration options and example usage.

Troubleshooting

Need some help? Take a look at the Duo UNIX Troubleshooting page or Frequently Asked Questions (FAQ) page or try searching our Knowledge Base. For further assistance, contact Support.

Network Diagram

  1. SSH connection initiated
  2. Primary authentication
  3. Duo Unix connection established to Duo Security over TCP port 443
  4. Secondary authentication via Duo Security’s service
  5. Duo Unix receives authentication response
  6. SSH session logged in