- Enable Two Factor Authentication in your PVE system
- Enabling TFA for SSH access
- Enforcing TFA TOTP for accessing the Proxmox VE web console
- Enforcing TFA TOTP as a default requirement for the
pamrealm - Incompatibility of PVE web console login with TFA enforced local shell access
- Relevant system paths
- References
- Navigation
One of the first things you should do to harden your standalone Proxmox VE node is to enable the Two Factor Authentication (TFA, also known as 2FA) for all your users, and specially for the root user.
You must be aware that the Proxmox VE platform provides its own TFA system for login into its web console, but it does not apply for local shell or remote ssh access. On the other hand, this section explains how to enable a TFA token system valid for both ssh and web access, although not for direct local shell login.
Open a shell console as root (the only user you should have available yet) and execute the apt commands below:
$ apt update
$ apt install -y libpam-google-authenticatorThis installs the google-authenticator program, enabling you to generate TFA tokens for the users of your PVE server's underlying Debian system.
At this point, be aware that the Google Authenticator program offers two ways of being executed: one is fully interactive and the other is meant to be used in shell scripting.
The interactive process is a step-by-step execution that asks the user to define some parameters for generating a new TFA token. Since those steps do not cover all the possible parameters handled by the command, this interactive method should be used only for a first-contact with the command.
Important
Better use the automated execution method over this interactive one
The automated method enables you to use all the options available for generating TFA tokens with the google-authenticator program, specially for shell scripting.
To start the interactive process, launch the google authenticator program like this:
$ google-authenticator -Q utf8Notice how a parameter -Q is specified in the command above:
-Q utf8
By default, the QR code generated by thegoogle-authenticatorcommand is printed with ANSI characters. This usually makes the printed QR too big for your shell screen and impossible to be copied or read by your authenticator app. Therefore, better use the Unicode UTF-8 character set. This ensures the QR is printed in a smaller and much more convenient character format.
The program will ask for your input in the following steps:
-
Do you want authentication tokens to be time-based (y/n)
Answeryhere. The time-based token is a Time-based One-Time Password, or TOTP, and is the most common and convenient token to use in TFA. -
In the following step, the
google-authenticatorprogram will show you a QR code and below it:-
Your new secret key is:
This is the secret key associated to this new TFA code. -
Enter code from app (-1 to skip):Here you can input the code generated by your TFA app to verify that you got the QR right, or just type-1to skip this check.
Regardless of you validating the TFA token or not, you get the emergency scratch codes associated to it. Make a screen capture to get that QR (or copy the whole text block if your terminal allows it) and save it together with all the codes (secret key, verification code and emergency scratch codes) in a safe storage like a password manager.
-
-
Do you want me to update your "/root/.google_authenticator" file? (y/n)
Answeryso the command writes this authentication token's configuration in a.google_authenticatorplain text file. By default, the command saves this file at the home directory of your current user (in this case,root).[!IMPORTANT] Answering
nto this question finishes the interactive procedure
If you answernhere, thegoogle-authenticatorcommand will not ask with the questions shown in the next steps and will return you to the shell prompt.[!NOTE] It is possible to use other paths and other file names
You can change the path and the file name, allowing you to generate and save different TFA tokens on different files or in different paths.This possibility will neither be shown nor used in this guide.
-
Do you want to disallow multiple uses of the same authentication token? This restricts you to one login about every 30s, but it increases your chances to notice or even prevent man-in-the-middle attacks (y/n)
Answeryto limit to one login per 30 seconds the usage of each TOTP token. -
By default, a new token is generated every 30 seconds by the mobile app. In order to compensate for possible time-skew between the client and the server, we allow an extra token before and after the current time. This allows for a time skew of up to 30 seconds between authentication server and client. If you experience problems with poor time synchronization, you can increase the window from its default size of 3 permitted codes (one previous code, the current code, the next code) to 17 permitted codes (the 8 previous codes, the current code, and the 8 next codes). This will permit for a time skew of up to 4 minutes between client and server. Do you want to do so? (y/n)
Answernhere. This option is for taking into account possible time differences between the server and the authentication app that gives you the timed codes. Nowadays, all systems are in proper sync thanks to time servers available on internet. -
If the computer that you are logging into isn't hardened against brute-force login attempts, you can enable rate-limiting for the authentication module. By default, this limits attackers to no more than 3 login attempts every 30s. Do you want to enable rate-limiting? (y/n)
Answeryto this final question. This limits the attempts to input the authentication code to 3 per each 30 seconds.
The resulting configuration is stored by default in the $HOME directory of the current user, in this case the root superuser, as a .google_authenticator file. Remove the file when you want to regenerate the TOTP token and its associated keys.
The google-authenticator program can be executed with parameters so it can be included in automated procedures. You can also list those parameters with the --help option:
$ google-authenticator -h
google-authenticator [<options>]
-h, --help Print this message
-c, --counter-based Set up counter-based (HOTP) verification
-C, --no-confirm Don't confirm code. For non-interactive setups
-t, --time-based Set up time-based (TOTP) verification
-d, --disallow-reuse Disallow reuse of previously used TOTP tokens
-D, --allow-reuse Allow reuse of previously used TOTP tokens
-f, --force Write file without first confirming with user
-l, --label=<label> Override the default label in "otpauth://" URL
-i, --issuer=<issuer> Override the default issuer in "otpauth://" URL
-q, --quiet Quiet mode
-Q, --qr-mode={NONE,ANSI,UTF8} QRCode output mode
-r, --rate-limit=N Limit logins to N per every M seconds
-R, --rate-time=M Limit logins to N per every M seconds
-u, --no-rate-limit Disable rate-limiting
-s, --secret=<file> Specify a non-standard file location
-S, --step-size=S Set interval between token refreshes
-w, --window-size=W Set window of concurrently valid codes
-W, --minimal-window Disable window of concurrently valid codes
-e, --emergency-codes=N Number of emergency codes to generateWarning
If you have already executed the google-authenticator command in the interactive mode, you will have a configured TOTP token
This TOTP token's setup will be stored in a .google_authenticator file within your user's home directory.
The file .google_authenticator will be overwritten when you execute the google-authenticator command again for the same user and location!.
After discovering all the options available in the google-authenticator command, you can build a command line to replicate and enhance the TOTP token configuration made in the previously explained interactive method:
Important
The following command line is just an example, DO NOT execute it as is
Among its many options, there are two, -l and -i , you must always edit to fit your requirements.
$ google-authenticator -t -d -f -r 3 -R 30 -w 3 -Q utf8 -i pve.homelab.cloud -l root@pamNext are explained the options set in the example command line above:
-
-t -d -f -r 3 -R 30 -w 3
These options configure the TOTP token almost like it was set in the interactive procedure. Check their purpose in thegoogle-authenticatorcommand's help (-h) ormancontent. -
-Q utf8
By default, the QR code shown by thegoogle-authenticatorcommand is printed withANSIcharacters. This can make the printed QR too big for your shell window and impossible to be copied or read by your authenticator app. Therefore, it is better to use Unicode's UTF-8 character set, which prints the QR in a smaller but equally valid format. -
-i pve.homelab.cloud
The issuer is the name of the entity that issued the authentication token. In your authenticator app, it helps you identify to which system corresponds each TOTP code. In this guide it would be the main sole Proxmox VE node itself, so this value is filled by default with whatever hostname it has, likepve. Better put a more descriptive string here for clarity, like yourpvenode's FQDN. -
-l root@pam
The label is another identifying value shown by authenticator apps for each TOTP code. By default, thegoogle-authenticatorcommand fills this label with the username of your current user, plus your system's hostname. Instead of using the hostname, use the user's authentication realm,pamin this case, so this label also looks as how the Proxmox VE web console presents the username.
When you have set up your command to your preferences, execute it to get an output like the following:
Warning: pasting the following URL into your browser exposes the OTP secret to Google:
https://www.google.com/chart?chs=200x200&chld=M|0&cht=qr&chl=otpauth://totp/root@pam%3Fsecret%3DHPDSSXPJ5BFJIXIIZD7EYTMJVM%26issuer%3Dpve.homelab.cloud
█▀▀▀▀▀█ ▄ ▄ ▄▀▀▄█▀▀ ██ ▄▀█▄ █▀▀▀▀▀█
█ ███ █ ▄█▀█▄▀█ ███ ▄▄▄ ▄█▄ █ ███ █
█ ▀▀▀ █ ▄ ▀█▀▄▄ ██▄█▄▄▄▀▄▄███ █ ▀▀▀ █
▀▀▀▀▀▀▀ ▀▄▀ █▄█▄█▄▀ ▀▄▀ █ █ ▀ ▀▀▀▀▀▀▀
▀▄ ▀ █▀ █ ▄ █▀█ ▄ ▄█▀ ▄▀█▀▀▀ ▀ ▄▄ ▄
▄▀▀██▀▀█▄▀ ▀▀█▄▀▀██▄▄█ ▀▄ ▄██▄ █ ▀▀
▄▄ █▄▀▄██ █▀▄ ▄▀▄▄ ▄▀▄ ▀ ▀█▄█ ▄█▀▀
██▀█ ▄▀█ █▀▄▄█▀ ▀▄█▄ █ █▄█▄▄▀▀ ▄█ ▀ ▀
▀ ▄▄▀█▀ ▄▄ █▀▄ ▄▄▀ ▀█▀█▄ ▄▄█▀▀█▄█▄▄
▄▄▄ ▀ █▄██▄▀▀▀▀██ ██▀▄▄▀▄ ▀▀▄█ ▀█▀█
▄▀ ▀▄▄▀▀▄▀ ▄▄▀▀██▀▄█▄▀▄ ███ ▄ ██▀▄▀▄
█▄ ▄██▀█▀ ▄█▀▄▄█ █ ▄ ▄▀▄▄▀▀█▀▀ ▀█
▀▀▀▀██▀▀▄ █▀█ ▀▄█▀ ███▄ ▀▄▄ █▀▀ █ ▄▄
▀▄▀▀▀█▀▀▄▄█▀▀ █▄██▀▄██▀▀▀▄▀ ▀▄▀ ▀▀▄█
▀▀ ▀▀ ▀ ▄█▀ ██ ▀▄▄▀▄▀▀▄██▄▀█▀▀▀█▀ ▀
█▀▀▀▀▀█ ▄ █▀▄ ▀ ██▄ ██ ▄▀ ▄▀█ ▀ █▀███
█ ███ █ ▄ ██ ▀█▀█▄▄ ▄█ ▀▄█▀ █▀▀███▄ ▀
█ ▀▀▀ █ █ ▀▀█▄█ ▀█ ▄█ ▄███▀▄▄▄█ ▀▀▀
▀▀▀▀▀▀▀ ▀▀▀ ▀ ▀ ▀ ▀ ▀ ▀ ▀▀▀▀▀▀ ▀▀▀
Your new secret key is: HPDSSXPJ5BFJIXIIZD7EYTMJVM
Enter code from app (-1 to skip):The command requests you to verify the key. Scan the QR code with your authentication app and then input the authentication code as the answer to the question (or just press -1 if you want to skip this validation).
Enter code from app (-1 to skip): 384525
Code confirmed
Your emergency scratch codes are:
68904426
75567886
58397698
41263689
78071899With the code verified, make a snapshot of the QR (or just copy the QR text block itself in a plain UTF-8 text file). Save the QR, its issuer and label, and all the related codes in a safe place, like in a password manager.
By default, the authentication token generated by the google-authenticator command is saved, together with its configuration, in a plain text file called .google_authenticator. This file is generated by the command itself and saved in the home directory of your current user, but with only a read-only permission (400 mode) exclusive for your user. Its content varies depending on how the token has been configured, but it looks something like this:
HPDSSXPJ5BFJIXIIZD7EYTMJVM
" RATE_LIMIT 3 30
" WINDOW_SIZE 3
" DISALLOW_REUSE
" TOTP_AUTH
68904426
75567886
58397698
41263689
78071899
-
HPDSSXPJ5BFJIXIIZD7EYTMJVM
This is your TOTP token's secret code, the one you have to input in your authentication app to get the corresponding TOTP codes. -
All the lines starting with
"are configuration values for the TOTP token
You could change these manually but, since how to do it is not properly documented, it is not recommended. -
68904426
This number and all the ones listed below it are scratch recovery codes. If you lose access to your TFA authentication app, you can use any of these recovery codes as TOTP codes.[!WARNING] Scratch recovery codes are one-use only
When used once, a scratch recovery code cannot be used again (hence, it has to be scratched from the list of available recovery codes).
With the TOTP token configured for your root user (the only user you have at this point yet), you can adjust your system's ssh configuration so it enforces the use of the TOTP token when accessing the system remotely.
-
First, go to the
pamconfiguration directory and make a backup of the ssh daemon's configuration file:$ cd /etc/pam.d $ cp sshd sshd.orig -
Append to the
sshdfile the following lines to make the ssh daemon aware of thegoogle-authenticatormethod of authentication:# Enforcing TFA with Google Authenticator tokens auth required pam_google_authenticator.so -
Go to the ssh configuration directory and make a backup of the original
sshd_configfile:$ cd /etc/ssh/ $ cp sshd_config sshd_config.orig -
Edit the
sshd_configfile as follows:-
Find the parameter
KbdInteractiveAuthenticationand change it toyes.# Change to yes to enable challenge-response passwords (beware issues with # some PAM modules and threads) KbdInteractiveAuthentication yes
-
Append the following line to the file.
AuthenticationMethods keyboard-interactive
This parameter tells ssh which authentication methods are required. In this case, it will ask for a password and the verification code.
[!WARNING] The keyboard interactive method already asks for all the required authentication inputs
Withkeyboard-interactive, the authentication procedure asks for all the inputs it requires to validate the login. In this case, the user password and the verification (TOTP) code. Therefore, do not add thepasswordmethod before thekeyboard-interactiveone or the login procedure will not work properly (thepasswordmethod will require the TOTP code, NOT the user password).
-
-
With all the previous changes done, restart the
sshddaemon to apply the changes:$ systemctl restart sshd.service
-
Using a ssh client, like PuTTY or Bitvise, check that the server asks you for your user password and your verification code (your TOTP code). Through PuTTY, the ssh login for the
rootuser will look like the following:login as: root Keyboard-interactive authentication prompts from server: Password: Verification code: End of keyboard-interactive prompts from server
You have enabled TFA authentication when connecting through SSH to your server for all users. This is better than just using the user password to log in through ssh, but we can improve on this by using ssh key pairs instead of passwords. This guide shows you how in a later chapter that covers how to harden the sshd configuration.
The Proxmox VE web console offers the option of enabling TFA for its users.
Important
This TFA configuration is only about the Proxmox VE web console login
Proxmox VE's TFA configuration has nothing to do with the local or remote SSH shell terminal access.
To increase the security of your Proxmox VE setup, enable the Two-Factor Authentication (TFA) of the main root user on the Proxmox VE's web console. Also, you will reuse the TOTP token already generated with the google-authenticator command:
-
Go to the
TFAoption available in theroot@pammenu: -
The web console loads the page for the
Datacenter > Permissionslevel feature calledTwo Factor: -
Unfold the
Two Factorpage'sAddmenu and pick theTOTPoption: -
The
TOTPoption raises theAdd a TOTP login factorwindow. Setup in it the TOTP-based TFA procedure for yourrootuser: -
Fill the fields of the TOTP window using the details of your previously
google-authenticatorgenerated TOTP token:-
User
Identifies the user affected by this TOTP method. This field corresponds with thelabelyou specified in thegoogle-authenticatormethod (-loption). -
Description
Just a string describing this TOTP login factor. There is no correspondence with any of the parameters specified in thegoogle-authenticatormethod. -
Secret
This is where the secret key must be set. This field corresponds with the secret key thegoogle-authenticatorcommand returns as the generated TOTP. -
Issuer Name
The name identifying the issuer of this TOTP. This field is equivalent to the issuer value specified to thegoogle-authenticatorcommand (-ioption).
[!WARNING] The autogenerated QR in this TOTP window will not be the same as the one you got previously with the
google-authenticatorcommand
If you scan it, it may generate a new entry in your authenticator app, but it will generate the same codes as the TOTP token you generated first. -
-
To enable the
Addbutton, you must validate the TOTP token. Enter theVerify Codegiven by your TOTP app, then clickAdd. Your new TOTP login factor will appear listed in theTwo Factorpage:
After all these steps, you obtain the TFA TOTP mode enabled in the root account for the web console with the same TOTP token you enabled for the remote ssh access.
Important
This TFA is valid for the web console only
This procedure only enables the TFA method for login through Proxmox VE's web console, not for accessing through a shell terminal.
To ensure that all pam users use TFA when accessing the Proxmox VE web console, you can configure that realm to have TFA enforced by default. Select the Datacenter level, open the Permissions options set and click on Realms.
The Realms page lists the authentication realms currently available in your Proxmox VE installation. In a clean Proxmox VE installation like the one used in this guide, you only have two realms: pam and pve. The main root user of your Proxmox VE system is in the pam realm.
-
Choose the
pamrealm and pressEditin the button menu above: -
After pressing the
Editbutton, you will get into theEdit: Linux PAMwindow: -
Unfold the
Require TFAlist, currently set asnone, to see all the available options: -
Choose the
OATH/TOTPoption. Notice how in the window appear two new fields related to TOTP,Time StepandSecret Length: -
Leave the TOTP parameters with their default values, they are good as they are. Accept the change to the
pamrealm by pressingOK, and you get back to the authentication realms list:See in the TFA column how the
pamrealm shows the stringoath. TFA is enforced in that realm with a OATH/TOTP token system. From now on, any user in that realm will be required to authenticate with a TOTP code, together with their username and password, to access the Proxmox VE web console.
At the beginning of this chapter, it is explicitly stated that it will not be enabled the TFA token system for the local shell login. This is due to a incompatibility existing between the Proxmox VE web console login and the modification required in the underlying Debian system's pam configuration.
Since this issue is not documented anywhere, this chapter illustrates the problem here in a few steps:
-
Open a remote ssh terminal and log in as
root(again, the only available user at this point). Thencdto the/etc/pam.ddirectory:$ cd /etc/pam.d -
The file to edit is
common-auth, so first let's make a backup of it:$ cp common-auth common-auth.orig
-
Append the following line to the
common-authfile:auth required pam_google_authenticator.so
[!WARNING] Do not close the remote session
Also, leave thecommon-authfile open but be sure to save the change above. -
Now try to log in the Proxmox VE web console and see how the login takes longer than usual:
-
After a few seconds, the login will raise a failure error:
Notice that you will not even reach the TFA form to input your TOTP code. Proxmox VE just raises this error window and does not allow you to go further than that.
-
Go back to your remote terminal session. Remove the line you added to the
common-authfile and save the change, or just restore the backup. -
Try to log into the web console again. It should work as usual now.
This conflict is not really that surprising. Proxmox VE web console needs some privileged access to its underlying Debian system, and adding the TFA restriction in the pam configuration for local authorization may mess up with it.
This is probably just a problem of limiting the TFA restriction to the users and groups that should have it enforced. Still, this problem is not explicitly documented anywhere and messing with the system's PAM configuration is risky. Therefore better leave it as it is, although being aware that the local access to the physical Proxmox VE server does not have TFA enabled.
Important
This problem not only happens in the 9.0 releases of Proxmox Virtual Environment
This problem happens in previous versions too.
/etc/pam.d/etc/ssh/root
/etc/pam.d/common-auth/etc/pam.d/common-auth.orig/etc/pam.d/sshd/etc/pam.d/sshd.orig/etc/ssh/sshd_config/etc/ssh/sshd_config.orig/root/.google_authenticator
-
DigitalOcean. How To Set Up Multi-Factor Authentication for ssh on Ubuntu 20.04
-
DigitalOcean. How To Set Up Multi-Factor Authentication for ssh on Ubuntu 16.04
-
TechRepublic. How to set up two-factor authentication in Linux
-
TechRadar. How to add two-factor authentication to Linux with Google Authenticator
- GitHub. Linux PAM (Pluggable Authentication Modules for Linux) project
- Debian Reference. 4.5. PAM and NSS
- TecMint. How to Configure and Use PAM in Linux
- Desde Linux. Autenticación PAM – Redes PYMES (in Spanish)
<< Previous (G006. Host configuration 04) | +Table Of Contents+ | Next (G008. Host hardening 02) >>













