The OpenSSH server has limits on what user authentication you can use

October 6, 2021

We've recently deployed multi-factor authentication for SSH access to some especially sensitive machines, which has caused me to become much more familiar with how OpenSSH's sshd and MFA interact with each other and the limits on that. Unfortunately these limits mean that some combinations of authentication methods are not really available (or not available at all). For example, in many situations you can't require people to use their Unix password and then either a public key or MFA authentication.

The simple way to describe the issue is that OpenSSH's public key authentication is done completely separately from PAM (on Linux systems), and OpenSSH has no way to selectively ask PAM to do various things. Roughly speaking, all interaction with PAM is a black box to the OpenSSH server that either passes or fails as the "keyboard-interactive" or "password" authentication method.

There are broadly two ways of doing MFA authentication with OpenSSH; you can do it as people log in to your server (although this gets annoying), or you can do it before hand in some way. The usual approach for the latter is to have an OpenSSH certificate authority that issues short term certificates only if you authenticate to it properly (through, for example, a web front end). Unfortunately the certificate approach is generally much more difficult to deploy, because you need a bunch of moving parts to exist on all of the clients. If you want simple deployment, you need to do all of your MFA at login time. OpenSSH itself has no built in support for MFA, so if you take the 'at login time' path you must put your MFA authentication into your PAM stack.

OpenSSH allows you to require multiple authentication methods but, as mentioned, your entire PAM stack is one authentication method. Since your MFA goes in your PAM stack, it's intrinsically coupled to whatever else the PAM stack does (which almost certainly includes asking for the Unix password). Then since SSH public key authentication isn't exposed through PAM, you can't use PAM's own (rather complicated) conditional features to require public key authentication only in some situations, or to skip only parts of the PAM stack if the user has public key authentication.

Another consequence of your MFA authentication being bolted to the rest of your PAM authentication is that it's relatively difficult to allow people using passwords to skip MFA under some circumstances (for example if they're logging in from your highly secure emergency access server). If MFA was a separate access method, you could configure this through Match blocks in your sshd_config. As it is, perhaps there's some way to do this reliably through PAM, but it's going to be harder and less obvious to configure.

In theory all of this could be dealt with if OpenSSH supported an additional authentication method, or really class of them, that I will call "pam:<service>". This would do a keyboard interactive PAM authentication using the given service name. Then you could put your MFA PAM configuration into a separate /etc/pam.d/mfa PAM service and set your SSH server to require, say, 'publickey,password' or 'password,pam:mfa' (and just 'password' from your emergency access server, or perhaps 'hostbased,password' for extra security).


Comments on this page:

There is one way to do 2FA relatively seamlessly, and that is to use the FIDO-based ed25519-sk key types, which require a U2F key to unlock each time.

By Simon Deziel at 2021-10-07 09:24:13:

To selectively require 2FA, using Match provides to be rather flexible IMHO:

PasswordAuthentication no
Match Group sudo Address 192.0.2.0/24
    AuthenticationMethods publickey
Match Group sudo
    AuthenticationMethods publickey,password
    PasswordAuthentication yes

Everyone is required to use key authentication except that sudoers need to password-auth unless they come from a trusted network.

By Seth at 2021-10-07 10:55:57:

If you have a recent-ish version of openssh, https://cern-cert.github.io/pam_2fa/ can add options by letting pam know what ssh has already done.

In our case we allow any one of three first factors: publickey, password, or AD/kerberos ticket; then Duo as second factor. sshd is setup to allow key+PAM, ticket+PAM, or just PAM. Then, using the CERN module, PAM skips the password check if sshd has already authenticated (via the key or ticket).

Using ed25519-sk is a good trick, but I guess you also need to be aware of all prior auth keys, so you cannot just storm in and break everyone's way of connecting through ssh.

Lately we've been exploring SSH based authentication by certificates provided/issues by HashiCorp's Vault. They're really short lived, and then you can basically enforce any kind of auth on the Vault's end. Although that might be more beneficial when you want to centralize log-in permissions such as when you want to allow members of the github group "something" to access "something" @ "1.2.3.4" user.

Written on 06 October 2021.
« Some early notes on using pipx for managing third-party Python programs
What Linux kernel "unknown reason" NMI messages mean »

Page tools: View Source, View Normal.
Search:
Login: Password:

Last modified: Wed Oct 6 22:39:09 2021
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.