Multi-Factor Authentication
Contents
Introduction
Flavors
The Bastion supports two flavors of Multi-Factor Authentication (MFA, sometimes called 2FA):
Immediate MFA, mandatory on a per-account basis during the SSH authentication phase on the ingress side, done by the system even before executing the bastion code, regardless of which actions (plugin calls, remote connection, ...) are to be done by the account currently being authenticated
JIT MFA, done after the authentication phase, by the bastion code, conditionally (just-in-time), when an action that is about to be done requires it by (configurable) policy
Each of these methods and their differences are detailed below, so you can choose the one that fits your environment.
Supported additional factors
The first factor is always the SSH publickey. Two additional factors are supported:
password, in which case a password is attached to the account. This password's policy is configurable through MFAPasswordMinDays, MFAPasswordMaxDays, MFAPasswordWarnDays, MFAPasswordInactiveDays.
TOTP, aka "Time-based One-Time Password", which requires a smartphone app and generates a new pin-code every 60 seconds.
Immediate MFA
This method implements MFA directly using PAM during the initial SSH authentication phase, on the ingress side, e.g. when accounts are connecting to the bastion. This entirely resides on SSH/PAM and doesn't even depend on The Bastion code (appart from the setup side of the additional factor for each account).
Note
Use this method if you want to enable MFA for some or all accounts unconditionally, regardless of which action
they're about to conduct on The Bastion (i.e. use an --osh
command, or attempt to connect somewhere,
or just display the help). If you want to enable MFA only for some precise --osh
commands or some remote hosts,
you'll want to use JIT MFA instead.
This method requires proper configuration of both the SSH server, and PAM. The included templates of
/etc/ssh/sshd_config
and /etc/pam.d/ssh
files do support it out of the box.
Detailed explanation of the SSH server and PAM configuration
This works by modifying the AuthenticationMethods
in sshd_config
to add keyboard-interactive:pam
,
which instructs the SSH server to rely on PAM for part of the authentication phase. Then, the PAM file defines
several authentications methods, which include several factors that can be configured per-account.
Note
You can skip this subsection if you're not interested in how this works exactly, but mainly want to know how
to setup MFA. If you're using the included sshd_config
and pam.d/ssh
templates unmodified,
which you are if you've followed the installation section, this will just work out of the box so you may skip
over the details and jump to How to use Immediate MFA.
sshd_config snippet
Let's take the last few lines of the ssh_config
file and explain them step by step. These are where the
MFA logic is implemented. We've left the comments that can be found in the template, for clarity.
# If 2FA has been configured for root, we force pubkey+PAM for it. If this is the case
# on your system, uncomment the next two lines (see
# https://ovh.github.io/the-bastion/installation/advanced.html#fa-root-authentication)
#Match User root
# AuthenticationMethods publickey,keyboard-interactive:pam
As explained in the comments within the file, this section (commented by default) refers to the MFA that can be
configured on the root
account to protect The Bastion's own system. This is out of the scope of this documenation
section, as we're focusing on the users MFA here, so refer to the 2FA root authentication
section if that's what you want to achieve.
# Unconditionally skip PAM auth for members of the bastion-nopam group
Match Group bastion-nopam
AuthenticationMethods publickey
The snipper above tells the SSH server to NOT rely on PAM (hence disable MFA) for accounts that are part of the
bastion-nopam
group. This is an internal group that is used for accounts whose MFA setup has been set to
bypass PAM authentication, with the following command:
bssh --osh accountModify --account robot-sync --pam-auth-bypass yes
╭──ac777d06bec9───────────────────────────────────────────the-bastion-3.12.00───
│ ▶ modify the configuration of an account
├───────────────────────────────────────────────────────────────────────────────
│ Bypassing sshd PAM auth usage for this account...
│ ... done, this account will no longer use PAM for authentication
╰────────────────────────────────────────────────────────────</accountModify>───
This way, the account robot-sync
will fall into the above configuration section Match
case and end up
only using classic publickey
authentication, hence no MFA. As MFA is only meaningful for humans, use this setting
for accounts that are used by any automated process you might have that interact with the bastion (for example using
its JSON API).
# if in one of the mfa groups AND the osh-pubkey-auth-optional group, use publickey+pam OR pam
Match Group mfa-totp-configd,mfa-password-configd Group osh-pubkey-auth-optional
AuthenticationMethods publickey,keyboard-interactive:pam keyboard-interactive:pam
The snippet above tells SSH that for accounts having an authentication factor configured, namely either a TOTP or
a password, and having the "public key is optional" flag, set by --osh accountModify --pubkey-auth-optional
,
implies that those accounts can either authenticate through public key and an additional factor (through PAM),
or through PAM only. In essence these accounts may use only a password, or a TOTP, or both, without having a
public key in addition to the other factors. Hence, this is not MFA per-se, but is an additional functionaly available
should you need this in your environment. You may remove (or comment) the two lines above if you're confident you'll
never require the pubkey-auth-optional feature.
# if in one of the mfa groups, use publickey AND pam
Match Group mfa-totp-configd,mfa-password-configd
AuthenticationMethods publickey,keyboard-interactive:pam
The snippet above is the core of the mandatory MFA configuration of the SSH server: it instructs the SSH server to authenticate accounts that have at least one MFA factor configured with their public key first, then hand over the authentication phase to PAM to check the additional factors.
# by default, always ask the publickey (no PAM)
Match All
AuthenticationMethods publickey
Finally, the snippet above is for the general case, i.e. accounts not having MFA configured, in which case they're authenticated using their public key only.
PAM ssh snippet
The template is heavily commented<https://github.com/ovh/the-bastion/blob/master/etc/pam.d/sshd.debian12>, line by line, please have a look at it if you want to know more.
How to use Immediate MFA
If you want to setup immediate MFA, you'll need to setup the SSH server and PAM configurations correctly, as explained above. If you installed the provided templates for both (which is the default), you're good to go.
You may want either to enable MFA for all the accounts existing on your bastion, or only a subset of these users, read on the proper section below for each case.
Requiring all users to setup their MFA
To ensure no user can use their account without configuring their MFA first, you have to set the accountMFAPolicy
option of bastion.conf
to either any-required
, totp-required
or password-required
. Detailed
information about this configuration setting is available
here.
When this setting is configured to any of the 3 above values, no interaction will be allowed on the bastion (such as using plugins or connecting to a remote asset) as long as the user didn't set up their MFA:
bssh --osh selfListAccesses
│
│ ⛔ Sorry johndoe, but you need to setup the Multi-Factor Authentication before using this bastion, please use either the `--osh selfMFASetupPassword' or the `--osh selfMFASetupTOTP' option, at your discretion, to do so
The only allowed --osh
commands allowed in such a case are help
, info
and the two ones referenced in the
above error message, precisely to be able to setup the MFA on the account.
In this mode, if you want to exclude a few accounts from requiring MFA (if you have accounts that are used by
automation or any other M2M workflow), you can do so using accountModify --pam-auth-bypass yes
.
Requiring only a subset of users to setup their MFA
If instead of forcing all users to require MFA, you want to require a precise subset of users to have MFA, you should
leave the accountMFAPolicy
to enabled
, and set the requirement flag on a per-account basis. This can be
done using accountModify --mfa-password-required yes
and/or accountModify --mfa-totp-required yes
. If you
set both flags on the same account, the bastion will require both factors to be set and provided on authentication,
in addition to publickey authentication. In this case, 3 authentication factors would be required. This is why we
call it MFA instead of 2FA: the number of additional factors you want is configurable.
JIT MFA
This method implements MFA checking right before an action is allowed, depending on the bastion policy, instead of requiring it at the ingress authentication stage.
Note
Use this method if you want to enable MFA on a per-action basis. In this case, The Bastion will decide whether
providing additional authentication factors is required right before a specific action is requested (such as
connection to a given remote asset, or execution of a subset of --osh
commands).
You may also want to use this method if for some reason you can't setup the sshd_config
file
as required by the Immediate MFA method
Note that the different ways detailed below can be cumulated: you might want to enable MFA for a few plugins, along with enabling it for sensitive remote hosts present in specific bastion groups, in addition to a few sensitive accounts that would require it no matter what.
Proper setup of sshd_config
To use JIT MFA, your first have to disable Immediate MFA, as is the default if you're using the provided
configuration template for your SSH server (which you are if you followed the default installation steps).
You'll need to comment out two lines within the /etc/ssh/sshd_config
file, these are located near the
end of the file:
# if in one of the mfa groups, use publickey AND pam
#Match Group mfa-totp-configd,mfa-password-configd
# AuthenticationMethods publickey,keyboard-interactive:pam
You'll need to reload the SSH daemon for this to be taken into account. The next subsections explain how to setup policies depending on the actions you want to protect through JIT MFA.
On a per-plugin basis
First ensure you've followed the Proper setup of sshd_config.
To force MFA for a plugin, you may add the mfa_required
option to its configuration. This configuration parameter
allows 4 values:
any, in which case MFA is required with any supported factor (currently either password or TOTP)
password, in which case a password is required in addition to publickey authentication
totp, in which case a TOTP is required in addition to publickey authentication
none, in which case no MFA is required (which is the default if the
mfa_required
setting is omitted)
To enable MFA for the adminSudo
plugin, for example, you may add:
{
"mfa_required": "any"
}
to the /etc/bastion/plugin.adminSudo.conf
file. Please ensure that this file is readable by the
bastion-users
system group (as all /etc/bastion/plugin.*.conf
files should be), so that the code running
under the bastion users permissions can read it.
When configured like this, usage of the adminSudo plugin, in our example, will trigger the validation of additional
authentication factors.
Note that for this to work, you must have the /etc/pam.d/ssh
file set up correctly,
as we're using PAM for this. The provided template is advised, and you're already using it if you followed the
default installation steps.
If you are not sure you're using the provided template, you may compare your current /etc/pam.d/ssh
file
with the proper template for your distro, which can be found in /opt/bastion/etc/pam.d/sshd.*
.
As you see, the MFA phase will be fired up for this plugin, but not for the info
plugin for example:
bssh --osh adminSudo
As this is required to run this plugin, entering MFA phase for johndoe.
Your account has Multi-Factor Authentication enabled, an additional authentication factor is required (password).
Your password expires on 2023/10/31, in 89 days
Password: ^C
bssh --osh info
╭──ac777d06bec9───────────────────────────────────────────the-bastion-3.12.00───
│ ▶ information
├───────────────────────────────────────────────────────────────────────────────
│ You are johndoe
[...]
On a per-group basis
First ensure you've followed the Proper setup of sshd_config.
If you want to ensure that MFA is required to connect to a remote host through a bastion group,
you should tag this group to require MFA. To do this, use the groupModify
command:
guybrush@bastion1(master)> groupModify --group securegroup --mfa-required any
╭──ac777d06bec9───────────────────────────────────────────the-bastion-3.12.00───
│ ▶ modify the configuration of a group
├───────────────────────────────────────────────────────────────────────────────
│ Modifying mfa-required policy of group...
│ ... done, policy is now: any
╰──────────────────────────────────────────────────────────────</groupModify>───
guybrush@bastion1(master)> groupInfo --group securegroup
╭──ac777d06bec9───────────────────────────────────────────the-bastion-3.12.00───
│ ▶ group info
├───────────────────────────────────────────────────────────────────────────────
│ Group securegroup's Owners are: guybrush
[...]
│ ❗ MFA Required: when connecting to servers of this group, users will be asked for an additional authentication factor
[...]
guybrush@bastion1(master)> ssh root@127.1.2.3
│ Welcome to bastion1, guybrush, your last login was 00:00:27 ago (Wed 2023-08-02 15:36:03 UTC) from 172.17.0.1(172.17.0.1)
[...]
will try the following accesses you have:
- group-member of securegroup with ED25519-256 key SHA256:94yETEnnWUy9yTG1dgAdXgunq6zzJPjlddFXjUH0Czw [2023/03/03] (MFA REQUIRED: ANY)
As this is required for this host, entering MFA phase for guybrush.
Your account has Multi-Factor Authentication enabled, an additional authentication factor is required (password).
Your password expires on 2023/10/31, in 89 days
Password:
As you see, after setting the flag on the group, attempting to access an asset that is part of the group (see
groupListServers
) will require MFA.
Note
If an account has access to an asset via several groups, MFA will be required if at least one group requires it.
Hence, a good way to ensure that all connections to an asset will require MFA would be to list the
SSH keys on the remote server, match those to groups on the bastion, and ensure they all have --mfa-required
enabled.
On a per-account basis
You may also use this method to enable MFA on a per-account basis (as is possible with the Immediate MFA method).
To do this, you should follow the same steps than are outlined in the Requiring only a subset of users to setup their MFA subsection of the Immediate MFA setup.
The only difference will be in your sshd_config
file, as for JIT MFA your should ensure you've followed the Proper setup of sshd_config.
In the case of Immediate MFA, the uncommented sshd_config
file block asks the SSH server to hand over authentication to PAM, hereby
requiring MFA at the authentication phase. For the JIT MFA on a per-account basis, this configuration is disabled, but the bastion code, after the
authentication phase is over, verifies whether the account requires to provide additional authentication factors, and triggers a PAM call if this
is the case.
Bypassing MFA for automated workflows
If you have accounts that are used for automation, you'll want to exclude them from requiring MFA.
To do this, use --osh accountModify --mfa-password-required bypass --mfa-totp-required bypass
. Accounts
with this setting will no longer require to enter additional credentials even when the policy of JIT MFA would
require them to.
Additional information
MFA and interactive mode
When using the interactive mode, and JIT MFA, attempting to conduct an action that requires MFA will trigger the MFA authentication phase, as expected.
However, when multiple MFA-required operations are to be done back to back, as is often the case when interactive mode is used, the MFA authentication phase will be triggered for each and every action, which can be cumbersome.
As long as interactiveModeProactiveMFAenabled is true, users can use the mfa command in interactive mode, to trigger the MFA authentication phase proactively, and enter an elevated session that will not require to enter MFA again. This elevated session will expire after interactiveModeProactiveMFAexpiration seconds (15 minutes by default). Users can exit the elevated session manually by typing nomfa.
Here is how it looks like:
bssh -i
Welcome to bastion1 interactive mode, type `help' for available commands.
You can use <tab> and <tab><tab> for autocompletion.
You'll be disconnected after 60 seconds of inactivity.
Loading... 90 commands and 0 autocompletion rules loaded.
guybrush@bastion1(master)> mfa
As proactive MFA validation has been requested, entering MFA phase.
Your account has Multi-Factor Authentication enabled, an additional authentication factor is required (password).
Your password expires on 2023/10/31, in 88 days
Password:
pamtester: successfully authenticated
Proactive MFA enabled, any command requiring MFA from now on will not ask you again.
This mode will expire in 00:15:00 (Thu 2023-08-03 12:35:08 UTC)
To exit this mode manually, type 'nomfa'.
guybrush@bastion1(master)[MFA-OK]> groupAddServer
╭──ac777d06bec9───────────────────────────────────────────the-bastion-3.12.00───
│ ▶ adding a server to a group
├───────────────────────────────────────────────────────────────────────────────
[...]
guybrush@bastion1(master)[MFA-OK]> nomfa
Your proactive MFA validation has been forgotten.
guybrush@bastion1(master)>
As you seen, once mfa
has been entered and the MFA validated, the prompt changes to [MFA-OK]
implying that
any command usually requiring MFA will not ask for it again (such as groupAddServer
in the above example, as
we've configured it to). We then explicitely exit the MFA elevated session by entering nomfa
.
MFA and --osh batch
The batch plugin is useful to enter several --osh
commands in a batch way. However, if
any of those commands require MFA, it would ask us repeatedly for our MFA, which can be cumbersome.
To avoid this behavior, and if you know that some of the commands you want to use in batch more will require MFA,
you may use the --proactive-mfa
option to the bastion, which will ask for your MFA before executing the
batch plugin, and any command requiring MFA will not ask for it again:
bssh --proactive-mfa --osh batch
As proactive MFA has been requested, entering MFA phase for guybrush.
Your account has Multi-Factor Authentication enabled, an additional authentication factor is required (password).
Your password expires on 2023/11/01, in 89 days
Password:
pamtester: successfully authenticated
╭──ac777d06bec9───────────────────────────────────────────the-bastion-3.12.00───
│ ▶ batch
├───────────────────────────────────────────────────────────────────────────────
│ Feed me osh commands line by line on stdin, I'll execute them sequentially.
│ Use 'exit', 'quit' or ^D to stop.
│ --- waiting for input
[...]