Skip to content

Configure Mideye MFA for Linux SSH & sudo via PAM RADIUS

This guide covers how to configure Linux SSH authentication to use Mideye Server for multi-factor authentication via the PAM RADIUS module (pam_radius_auth). In this setup, Mideye handles both password validation and MFA via a single RADIUS request, the user's password is forwarded to Mideye, which validates it against AD/LDAP/local database and triggers the configured MFA factor. Configurations where the password is validated separately (e.g. locally via pam_unix or SSSD) before RADIUS are not covered here.

ComponentDetails
PAM modulepam_radius_auth (FreeRADIUS pam_radius)
Linux distributionsRHEL / CentOS / Rocky Linux / AlmaLinux (yum/dnf), Debian / Ubuntu (apt)
Mideye Server5.x / 6.x
  • A running Mideye Server with RADIUS enabled (default UDP port 1812)
  • The Linux server must be added as a RADIUS client in Mideye Server
  • Root or sudo access on the Linux server
  • Network connectivity from the Linux server to Mideye Server on UDP port 1812
  • User accounts must exist in both the Linux server and the Mideye user repository (Active Directory, LDAP, or local database)

RHEL / CentOS / Rocky Linux / AlmaLinux

Terminal window
dnf -y install epel-release
dnf -y install pam_radius

Debian / Ubuntu

Terminal window
apt-get install libpam-radius-auth

For more information on the PAM RADIUS module, refer to the FreeRADIUS pam_radius GitHub repository and the USAGE documentation.

The configuration file location depends on the distribution:

DistributionConfig file
RHEL / CentOS / Rocky Linux / AlmaLinux/etc/pam_radius.conf
Debian / Ubuntu/etc/pam_radius_auth.conf

Edit the file for your distribution and replace the example values with your actual Mideye Server IP address and shared secret:

# server[:port] shared_secret timeout (s)
192.0.2.10 your-shared-secret 35
SettingValue
Server addressIP address of the Mideye Server
Shared secretMust match the RADIUS client configuration in Mideye Server
Timeout35 seconds, required for MFA flows

For full configuration options, see the pam_radius_auth.conf sample.

Save the changes.

Edit /etc/pam.d/sshd and add the RADIUS authentication line at the top of the auth section. The client_id parameter sets the NAS-Identifier sent to Mideye Server, it must match the NAS-ID configured in the Mideye RADIUS client.

The exact placement and surrounding lines differ by distribution.

RHEL / CentOS / Rocky Linux / AlmaLinux

Add the line after pam_sepermit.so:

Terminal window
#%PAM-1.0
auth required pam_sepermit.so
auth sufficient pam_radius_auth.so conf=/etc/pam_radius.conf client_id=LinuxPAM retry=1
auth substack password-auth
auth include postlogin

Debian / Ubuntu

Add the line at the top of /etc/pam.d/sshd, before @include common-auth:

Terminal window
auth sufficient pam_radius_auth.so conf=/etc/pam_radius_auth.conf client_id=LinuxPAM retry=1
# Standard Un*x authentication.
@include common-auth

For more on client_id and other parameters, see the pam_radius USAGE documentation.

Save the changes.

Enable keyboard-interactive authentication in SSH

Section titled “Enable keyboard-interactive authentication in SSH”

Edit /etc/ssh/sshd_config. The correct setting depends on your OpenSSH version:

OpenSSH 9.0 and later

Terminal window
KbdInteractiveAuthentication yes

OpenSSH 8.x and earlier

Terminal window
ChallengeResponseAuthentication yes

To check your OpenSSH version:

Terminal window
ssh -V

If the line exists with no, change it to yes. If it is commented out, uncomment and set it to yes.

Also verify that UsePAM yes is present and uncommented, this is required for the PAM stack to be invoked on login.

Save the changes.

RHEL / CentOS / Rocky Linux / AlmaLinux

Terminal window
systemctl restart sshd

Debian / Ubuntu

Terminal window
systemctl restart ssh

User accounts must exist on the Linux server. Create a local account:

Terminal window
sudo useradd -m <username>

-m creates the home directory. The account has no local password, all authentication goes through RADIUS.

If the Linux server is already joined to Active Directory (via realmd + SSSD), the shared setup and SSH configuration are identical. The difference is user provisioning: domain users are provided by SSSD and do not need local accounts.

If you require strict MFA-only access for non-break-glass users, add pam_deny.so immediately after the RADIUS line in the relevant PAM stacks (sshd, and for sudo also sudo/sudo-i).

Debian / Ubuntu (/etc/pam.d/sshd)

Terminal window
auth sufficient pam_radius_auth.so conf=/etc/pam_radius_auth.conf client_id=LinuxPAM retry=1
auth required pam_deny.so
@include common-auth

RHEL / CentOS / Rocky Linux / AlmaLinux (/etc/pam.d/sshd)

Terminal window
#%PAM-1.0
auth required pam_sepermit.so
auth sufficient pam_radius_auth.so conf=/etc/pam_radius.conf client_id=LinuxPAM retry=1
auth required pam_deny.so
auth substack password-auth
auth include postlogin

Skip useradd for domain users. Instead, verify the user is resolvable on the Linux server:

Terminal window
id <username>

If the user is not found, SSSD is likely not running or the user does not exist in Active Directory:

Terminal window
systemctl status sssd

To require Mideye MFA when users run sudo commands, add the RADIUS auth line to the sudo PAM stack. This uses the same architecture as SSH in this guide: password and MFA are both validated by Mideye in one RADIUS request.

RHEL / CentOS / Rocky Linux / AlmaLinux

Edit /etc/pam.d/sudo and add the line before auth include system-auth:

Terminal window
#%PAM-1.0
auth sufficient pam_radius_auth.so conf=/etc/pam_radius.conf client_id=LinuxPAM retry=1
auth include system-auth
account include system-auth
password include system-auth
session include system-auth

On RHEL-family systems, /etc/pam.d/sudo-i usually includes sudo, so this single edit typically covers both sudo <command> and sudo -i.

Debian / Ubuntu

Edit /etc/pam.d/sudo and add the line before @include common-auth:

Terminal window
#%PAM-1.0
# Set up user limits from /etc/security/limits.conf.
session required pam_limits.so
session required pam_env.so readenv=1 user_readenv=0
session required pam_env.so readenv=1 envfile=/etc/default/locale user_readenv=0
auth sufficient pam_radius_auth.so conf=/etc/pam_radius_auth.conf client_id=LinuxPAM retry=1
@include common-auth
@include common-account
@include common-session-noninteractive

For sudo -i on Debian/Ubuntu, edit /etc/pam.d/sudo-i separately and add the same auth sufficient pam_radius_auth.so ... line before @include common-auth.

If you require strict MFA-only behavior for domain-joined sudo, add auth required pam_deny.so immediately after the RADIUS line in sudo (and sudo-i where used) so failed/unavailable RADIUS does not fall through to password-only modules.

To require authentication on every sudo command, disable sudo credential caching:

Terminal window
echo "Defaults timestamp_timeout=0" > /etc/sudoers.d/mfa-no-cache
chmod 440 /etc/sudoers.d/mfa-no-cache

No service restart is required, PAM changes take effect immediately.

To test:

Terminal window
sudo -k
sudo whoami

Expected result: Mideye prompts for password + MFA, and on success the command runs as root.

If you need emergency local access, exempt specific users from RADIUS and let them authenticate with local Linux passwords instead.

Create an allow-list file:

Terminal window
echo "breakglass" > /etc/sudo-mfa-exempt
chmod 644 /etc/sudo-mfa-exempt

Debian / Ubuntu

In /etc/pam.d/sudo, add the exemption line before the RADIUS line:

Terminal window
auth [success=2 default=ignore] pam_listfile.so item=user sense=allow file=/etc/sudo-mfa-exempt onerr=fail
auth sufficient pam_radius_auth.so conf=/etc/pam_radius_auth.conf client_id=LinuxPAM retry=1
auth required pam_deny.so
@include common-auth

If you use sudo -i on Debian/Ubuntu, add the same pam_listfile.so + RADIUS lines in /etc/pam.d/sudo-i.

RHEL / CentOS / Rocky Linux / AlmaLinux

In /etc/pam.d/sudo, add the exemption line before the RADIUS line:

Terminal window
#%PAM-1.0
auth [success=2 default=ignore] pam_listfile.so item=user sense=allow file=/etc/sudo-mfa-exempt onerr=fail
auth sufficient pam_radius_auth.so conf=/etc/pam_radius.conf client_id=LinuxPAM retry=1
auth required pam_deny.so
auth include system-auth
account include system-auth
password include system-auth
session include system-auth

If you do not use fail-closed (pam_deny.so), set the pam_listfile.so control back to success=1.

How it works:

  • User in /etc/sudo-mfa-exempt: skips both the RADIUS and pam_deny.so lines, then continues to local Linux password authentication (common-auth or system-auth).
  • User not in /etc/sudo-mfa-exempt: continues to RADIUS and must complete Mideye password + MFA.
  • onerr=fail: if the file is missing or unreadable, the exemption check fails closed.
SymptomCheck
SSH times out before OTP entryVerify timeout in the RADIUS config file (/etc/pam_radius.conf on RHEL, /etc/pam_radius_auth.conf on Debian/Ubuntu) is set to at least 35 seconds
Authentication fails immediatelyVerify shared secret matches between the RADIUS config file and Mideye Server RADIUS client. Check for hidden characters with cat -A /etc/pam_radius_auth.conf
No RADIUS logs in Mideye ServerVerify UDP port 1812 is open between the Linux server and Mideye Server
OTP prompt does not appearVerify KbdInteractiveAuthentication yes (OpenSSH 9+) or ChallengeResponseAuthentication yes (OpenSSH 8.x) is set in /etc/ssh/sshd_config. Also verify UsePAM yes is set. Restart the SSH service after any changes.
Invalid user or illegal user in auth.logThe username has no local Unix account on this machine. Create one with sudo useradd -m <username> before testing.
sudo works without an MFA promptVerify the auth sufficient pam_radius_auth.so ... line is in /etc/pam.d/sudo (not only in /etc/pam.d/sshd). If MFA worked recently without prompting, clear sudo cache with sudo -k or set Defaults timestamp_timeout=0.
sudo -i fails but sudo <command> works (Debian/Ubuntu)Verify /etc/pam.d/sudo-i is updated with the same RADIUS auth line used in /etc/pam.d/sudo.
User not foundVerify the Linux user exists (id <username>) and the username matches the Mideye user repository
client_id mismatchVerify the NAS-ID in /etc/pam.d/sshd matches the NAS-ID in the Mideye RADIUS client configuration
RADIUS accepted in Mideye logs but login still failsCheck that pam_radius_auth.so is set to sufficient in /etc/pam.d/sshd, not requisite. With requisite, RADIUS success continues the PAM chain where pam_unix fails on a locked account and denies the login.
Domain user not found (id returns nothing)Verify SSSD is running (systemctl status sssd) and the user exists in Active Directory