2

I'm trying to get ssh to work in a way where password auth can be skipped with a key, and in addition every login would be followed up with totp using google's libpam on my new debian 9 installation.

So far i've been able to get the first part working, where if i provide a key, the server asks me for the otp, but the way it is, i've had to comment out both @include common-auth and @include common-password to suppress the password prompt in /etc/pam.d/sshd.

Seems obvious then that if i do AuthenticationMethods publickey,keyboard-interactive:pam password,keyboard-interactive:pam in my sshd_config and i try logging in without a key it does not matter what password i provide since the password checking parts are commented out.

The logical way to solve this as it would seem to a novice like me, would be that i could define different pam methods or classes, and then somehow reference those in my sshd_config, but i cant seem to find any information regarding such an operation.

Is it even possible to accomplish this particular combo?

edit 1:

Tinkering further with this, it really does not make as much sense as i initially thought. If i comment out both @include common-auth and @include common-password, i can get publickey,keyboard-interactive:pam to not ask for password. If i now set AuthenticationMethods password for a specific user, that user is not able to log in at all due to every password being rejected, even if it really is the valid one. So logically then it seems sshd password auth method also uses the /etc/pam.d/sshd configs. if i dont comment those includes, keyboard-interactive:pam asks for password and verification code, but password auth method still fails for any user that has otp initialized (and would fail for all except i give google libpam the nullok option). Seems like password is just a crappy version of keyboard-interactive:pam that can only prompt for one input and thus always fails if there are more then one required inputs.

If i write my own pam.d module, is there any way to make ssh use it instead of /etc/pam.d/sshd?

edit 2:

Im starting to think that i cant do (password && otp) || (publickey && otp), because the public key is checked in a different place from the rest, and so unless i can define which pam config to use with AuthenticationMethods, or i can somehow send parameters/arguments to the pam module, knowing when to check both and when to only check otp seems impossible

Noino
  • 121
  • 3

2 Answers2

0

If you have many other layers of security and just want this one thing for a single account/key combo, you can try this dirty hack... It is a really bad idea and you shouldn't do it. A few of the obvious risks will be listed at the bottom. But if you are just tinkering in a highly isolated test network with zero risk, I guess you could try this:

Get yourself set up for (password && otp) || (publickey) as in many tutorials like this one. Then add a forced command to your publickey method which verifies OTP.

In .ssh/authorized_keys prepend your key like this:

restrict,pty,command="/usr/local/bin/promptOtpShell" ssh-rsa AAAAB3NzaC1yc2E...

Then, in /usr/local/bin/promptOtpShell:

#!/bin/bash

if [ -n "$SSH_ORIGINAL_COMMAND" ]; then
    logger -p auth.error -t ${0##*/} "error: OTP: Subsystem refused for ${LOGNAME} from ${SSH_CLIENT%% *}"
    exit 1
fi
retry=3
key=$(head -1 ~/.google_authenticator)
while [ "$retry" -gt 0 ]; do
    read -p "OTP: " -n 6 -t 120 -s otp
    echo
    if echo -e "$key\n$otp" | oathtool -b --totp -w 2 - - >/dev/null 2>&1; then
        exec -la "${SHELL##*/}" "$SHELL"
    fi
    ((retry-=1))
done
logger -p auth.error -t ${0##*/} "error: OTP: Authentication failure for ${LOGNAME} from ${SSH_CLIENT%% *}"

Be sure to apt install oathtool and don't forget to chmod 755 /usr/local/bin/promptOtpShell.

Risks:

  1. Environment variables are trusted more than is safe
  2. Port, Agent and X11 forwarding will be permitted before OTP verification if enabled (which is why we restrict in this example)
  3. If you adapt this approach for use from an /etc/sshd_config ForceCommand rather than .ssh/authorized_keys then you have to restrict all forwarding for any matching connections
  4. Someone clever could almost certainly list another handful of issues in 20 minutes or less
Kenny
  • 1
0

The parameter you are looking for in the sshd_config is AuthenticationMethods. I wrote a blog post about combinting SSH key authentication with OTP a while ago.

However, this blog post uses the OTP with a pam module against the privacyIDEA authentication system. But you should be able to easily exchange this with the google pam.

cornelinux
  • 229
  • 1
  • 7
  • I believe i've seen that blog post before. I Feel the main part is where you write your `common-auth-pi` and replace the unix password check with a privacyidea credential check. i dont know what `optional pam_cap.so` does tho, i might be mistaken. But in the end you wind up always requiring a ssh key, which is not my goal – Noino Nov 12 '18 at 05:24
  • OK, so I misunderstood you. I think it is not possible to _optionally_ require and _additional_ sshkey. – cornelinux Nov 12 '18 at 09:04