So I’ve been reading up on configuring a CentOS 7 machine for 2 factor authentication for SSH, using pam_oath and the FreeOTP phone app, plus local usernames/password for the two factors. I’ve read various online articles, and all seem to follow the basic instructions listed in the following articles:
https://wiki.archlinux.org/index.php/Pam_oath
https://jonarcher.info/2015/07/hardening-ssh-with-otp-for-2-factor-authentication/
https://www.brianlane.com/post/setup-oath-ssh-login-on-fedora/
Before I do this on my main CentOS machine, I spun up a VirtualBox VM for testing, and did a minimum CentOS 7 install. I followed the instructions, and I get prompted for “One-time password (OATH)” credentials, but I noticed that I can input any alphanumeric string that’s 6 characters or less for the OATH password, and it will then prompt me for my local username/password. And as long as I enter the local password correctly, I’m granted shell access.
Here are the steps I followed after the initial minimal CentOS 7 install (CentOS Linux release 7.7.1908 (Core)):
- Install packages
yum update && yum upgrade
yum install epel-release
yum install pam_oath oathtool gen-oath-safe
- edit /etc/pam.d/sshd, and added the following line as the first non-commented line:
auth sufficient pam_oath.so usersfile=/etc/liboath/users.oath window=10 digits=6
So first few lines of the /etc/pam.d/sshd look like this before:
#%PAM-1.0
auth required pam_sepermit.so
auth substack password-auth
auth include postlogin
# Used with polkit to reauthorize users in remote sessions
And after:
#%PAM-1.0
auth sufficient pam_oath.so usersfile=/etc/liboath/users.oath window=10 digits=6
auth required pam_sepermit.so
auth substack password-auth
auth include postlogin
- generate keys for my local account:
gen-oath-safe jdoe hotp
-
Add key to FreeOTP app on phone via QR code
-
Add the hex code to /etc/liboath/users.oath:
HOTP jdoe – REDACTED
- edit the /etc/ssh/sshd_config file and make sure the following settings are in place:
UsePAM yes
ChallengeResponseAuthentication yes
PasswordAuthentication yes
- set SELinux permissions on /etc/liboath:
semanage fcontext -a -t systemd_passwd_var_run_t '/etc/liboath(/.*)?'
restorecon -rv /etc/liboath/
- Restart SSH:
systemctl restart sshd
So when I SSH into this host, and enter any string 6 characters or less, I’m let through to login with the local password:
login as: jdoe
Keyboard-interactive authentication prompts from server:
One-time password (OATH) for `jdoe':
Password:
End of keyboard-interactive prompts from server
Last login: Sun Mar 22 18:03:08 2020 from REDACTED
[jdoe@pkcentos7 ~]
If I enter a string 7 characters or more for the OATH password, the following occurs:
login as: jdoe
Keyboard-interactive authentication prompts from server:
One-time password (OATH) for `jdoe':
End of keyboard-interactive prompts from server
Access denied
Keyboard-interactive authentication prompts from server:
One-time password (OATH) for `jdoe':
End of keyboard-interactive prompts from server
Access denied
Keyboard-interactive authentication prompts from server:
One-time password (OATH) for `jdoe':
I’ve looked through various other articles returned from Google searches, and I don’t clearly see a step or setting I’m missing.
Any help on this would be greatly appreciated. Thanks in advance, and if any additional information is needed, please let me know.
Paul
2
Answers
Thanks for the reply! From looking at your sshd_config file, I assume that you're using a public key as part of the 2FA on your system. So I tweaked what you have above to work on my test system:
1) /etc/pam.d/sshd
2) /etc/sshd/sshd_config
Here's what the output from the SSH login process after this change, where I:
1) purposely entered one-time password wrong
2) entered correct one-time, but wrong account password
3) correct one-time password, then correct account password
Change pam module control from
sufficient
to[success=done new_authtok_reqd=done default=die]
My pam line looks like:
sshd_config: