I'm trying to implement two-factor authentication for OpenSSH. The environment is Centos 7 (kernel: 3.10.0-229.1.2.el7.x86_64) with OpenSSH_6.6.1p1, OpenSSL 1.0.1e-fips 11 Feb 2013. We have Active Directory (LDAP) + Kerberos deployed. The specification is as follows:
- A user with an existing, valid Kerberos ticket must be asked only for the second factor
- A user without an existing, valid Kerberos ticket must be asked for both his password and a second factor
- Local users (no LDAP acc.) should be able to authenticate with their local passwords
- The second factor must not be offered before the first one
- Besides Kerberos, public key authentication should be also accepted as first factor if available
- The feature should be able to be limited to a set of users - others just get let in with their passwords
For performing the second factor's authentication process, there is 3rd party a PAM module available that knows nothing about Kerberos. So here is what I did:
Put these lines into /etc/ssh/sshd_config:
# To enable PAM - this will make sshd use PAM with configuration /etc/pam.d/sshd
UsePam yes
ChallengeResponseAuthentication yes
# To enable Kerberos and public key authentication - it will let sshd use existing Kerberos tickets
GSSAPIAuthentication yes
# Enable public key authentication
PubkeyAuthentication yes
# Password validation should be done via the KDC
PasswordAuthentication yes
KerberosAuthentication yes
KerberosOrLocalPasswd yes
# Kerberos / Public Key + PAM
AuthenticationMethods gssapi-with-mic,keyboard-interactive:pam publickey,keyboard-interactive:pam password,keyboard-interactive:pam
# (only supported for OpenSSH 6.2 or higher)
The auth section of the PAM configuration for sshd (/etc/pam.d/sshd)
auth [success=ignore default=1] pam_localuser.so
auth substack password-auth
auth [success=1 default=ignore] pam_localuser.so
auth required pam_2fa.so [...some arguments...]
auth include postlogin
The module pam_2fa.so is responsible for prompting for and validating the second factor.
Now for Kerberos, this does almost everything I wanted to achieve. However, for local accounts, it results in two subsequent password prompts. This is my main problem here. This is because in this case the path "password,keyboard-interactive:pam" is used,as expected. (I need this auth. path so someone with a Kerberos account but without a valid ticket can get a ticket by entering the password then the OTP.) If I remove the password-auth substack completely from the PAM config, then Kerberos accounts remain working and local accounts remain not working. To me, it seems like the KerberosOrLocalPasswd yes statement gets ignored, because UsePAM yes is also present. However, sshd really keeps using KDC for password validation, because otherwise it would not work for LDAP accounts either.
So again, to further clarify what I wish to implement here is the pseudocode that described the desired authentication logic:
if gssapi_auth_ok(principal) or pubkey_auth_ok(pubkey):
return second_factor_auth(user, read_otp())
else:
if is_local_account(user):
if local_passwd_auth(user, read_password()):
return second_factor_auth(user, read_otp())
else:
return AUTH_ERR
else:
if krb5_auth(principal, read_password()):
return second_factor_auth(user, read_otp())
return AUTH_ERR
So my scenario I think is not too complex or ambitious in any way, but I still could not find a clear way to implement it despite I spent days researching and experimenting. Could you please help me find a solution?
Thank you very much in advance!