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.
| Component | Details |
|---|---|
| PAM module | pam_radius_auth (FreeRADIUS pam_radius) |
| Linux distributions | RHEL / CentOS / Rocky Linux / AlmaLinux (yum/dnf), Debian / Ubuntu (apt) |
| Mideye Server | 5.x / 6.x |
Prerequisites
Section titled “Prerequisites”- 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)
Shared setup (SSH + sudo)
Section titled “Shared setup (SSH + sudo)”Install the PAM RADIUS module
Section titled “Install the PAM RADIUS module”RHEL / CentOS / Rocky Linux / AlmaLinux
dnf -y install epel-releasednf -y install pam_radiusDebian / Ubuntu
apt-get install libpam-radius-authFor more information on the PAM RADIUS module, refer to the FreeRADIUS pam_radius GitHub repository and the USAGE documentation.
Configure the RADIUS connection
Section titled “Configure the RADIUS connection”The configuration file location depends on the distribution:
| Distribution | Config 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| Setting | Value |
|---|---|
| Server address | IP address of the Mideye Server |
| Shared secret | Must match the RADIUS client configuration in Mideye Server |
| Timeout | 35 seconds, required for MFA flows |
For full configuration options, see the pam_radius_auth.conf sample.
Save the changes.
SSH configuration
Section titled “SSH configuration”Configure PAM for SSH
Section titled “Configure PAM for SSH”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:
#%PAM-1.0auth required pam_sepermit.soauth sufficient pam_radius_auth.so conf=/etc/pam_radius.conf client_id=LinuxPAM retry=1auth substack password-authauth include postloginDebian / Ubuntu
Add the line at the top of /etc/pam.d/sshd, before @include common-auth:
auth sufficient pam_radius_auth.so conf=/etc/pam_radius_auth.conf client_id=LinuxPAM retry=1# Standard Un*x authentication.@include common-authFor 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
KbdInteractiveAuthentication yesOpenSSH 8.x and earlier
ChallengeResponseAuthentication yesTo check your OpenSSH version:
ssh -VIf 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.
Restart the SSH service
Section titled “Restart the SSH service”RHEL / CentOS / Rocky Linux / AlmaLinux
systemctl restart sshdDebian / Ubuntu
systemctl restart sshUser account setup
Section titled “User account setup”Add Linux users
Section titled “Add Linux users”User accounts must exist on the Linux server. Create a local account:
sudo useradd -m <username>-m creates the home directory. The account has no local password, all authentication goes through RADIUS.
Domain-joined Linux
Section titled “Domain-joined Linux”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)
auth sufficient pam_radius_auth.so conf=/etc/pam_radius_auth.conf client_id=LinuxPAM retry=1auth required pam_deny.so@include common-authRHEL / CentOS / Rocky Linux / AlmaLinux (/etc/pam.d/sshd)
#%PAM-1.0auth required pam_sepermit.soauth sufficient pam_radius_auth.so conf=/etc/pam_radius.conf client_id=LinuxPAM retry=1auth required pam_deny.soauth substack password-authauth include postloginSkip useradd for domain users. Instead, verify the user is resolvable on the Linux server:
id <username>If the user is not found, SSSD is likely not running or the user does not exist in Active Directory:
systemctl status sssdSudo setup
Section titled “Sudo setup”Sudo configuration
Section titled “Sudo configuration”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:
#%PAM-1.0auth sufficient pam_radius_auth.so conf=/etc/pam_radius.conf client_id=LinuxPAM retry=1auth include system-authaccount include system-authpassword include system-authsession include system-authOn 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:
#%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=0session 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-noninteractiveFor 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:
echo "Defaults timestamp_timeout=0" > /etc/sudoers.d/mfa-no-cachechmod 440 /etc/sudoers.d/mfa-no-cacheNo service restart is required, PAM changes take effect immediately.
To test:
sudo -ksudo whoamiExpected result: Mideye prompts for password + MFA, and on success the command runs as root.
Break-glass exemption
Section titled “Break-glass exemption”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:
echo "breakglass" > /etc/sudo-mfa-exemptchmod 644 /etc/sudo-mfa-exemptDebian / Ubuntu
In /etc/pam.d/sudo, add the exemption line before the RADIUS line:
auth [success=2 default=ignore] pam_listfile.so item=user sense=allow file=/etc/sudo-mfa-exempt onerr=failauth sufficient pam_radius_auth.so conf=/etc/pam_radius_auth.conf client_id=LinuxPAM retry=1auth required pam_deny.so@include common-authIf 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:
#%PAM-1.0auth [success=2 default=ignore] pam_listfile.so item=user sense=allow file=/etc/sudo-mfa-exempt onerr=failauth sufficient pam_radius_auth.so conf=/etc/pam_radius.conf client_id=LinuxPAM retry=1auth required pam_deny.soauth include system-authaccount include system-authpassword include system-authsession include system-authIf 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 andpam_deny.solines, then continues to local Linux password authentication (common-authorsystem-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.
Troubleshooting
Section titled “Troubleshooting”| Symptom | Check |
|---|---|
| SSH times out before OTP entry | Verify 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 immediately | Verify 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 Server | Verify UDP port 1812 is open between the Linux server and Mideye Server |
| OTP prompt does not appear | Verify 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.log | The username has no local Unix account on this machine. Create one with sudo useradd -m <username> before testing. |
sudo works without an MFA prompt | Verify 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 found | Verify the Linux user exists (id <username>) and the username matches the Mideye user repository |
client_id mismatch | Verify 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 fails | Check 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 |
Related links
Section titled “Related links”Mideye documentation
Section titled “Mideye documentation”- RADIUS Clients, add the Linux server as a RADIUS client in Mideye Server
- RADIUS Integrations, authentication flows and supported auth types
- Authentication Types, all supported Mideye authentication methods
- RADIUS Timeout, how the timeout affects authentication
- Support Center, contact Mideye support for integration assistance
External documentation
Section titled “External documentation”- FreeRADIUS pam_radius GitHub repository, source code and documentation
- pam_radius USAGE documentation, all module parameters
- pam_radius_auth.conf sample, configuration file reference