[SOLVED] Use TOTP from Web GUI for SSH connections

CZappe

Member
Jan 25, 2021
36
11
13
Santa Fe, NM, USA
www.bti-usa.com
I'm configuring TOTP multifactor authentication for our Linux servers, including Proxmox nodes, and have a question about whether the codes Proxmox uses in the Web GUI could be configured for use for SSH connections as well. Ideally, I'd like to have one method of generating TOTP codes work for both management interfaces, to avoid the confusion of having multiple entries for a single machine in our authenticator app.

The nearest I've seen to an explanation was the forum post, "How to enable TFA for SSH?" from a few years back, but it seemed to suggest just installing libpam-google-authenticator, which is what I'm doing on our other servers that are only managed over SSH. However, this wouldn't seem to generate TOTP codes that could also be used in the WebGUI. I've looked through the PVE documentation, 14.6. Two-Factor Authentication, but don't see any mention of SSH.

Does Proxmox allow TOTP codes configured from the Web GUI to be used for SSH connections? If so, what steps would be needed to use them for SSH, as well?

My test node has TOTP configured in the Web GUI at present, and is running PVE 7.2-11

Thanks!
 
This is not possible out of the box, although I think you could get it to work with a bit of manual wiring. I haven't tried this though, so I can give no guarantees. There might be some caveats I am not aware of, so take this with a grain of salt.

You can find the secrets for the TOTP stored in /etc/pve/priv/tfa.cfg, where all secrets for the respective user accounts are located. This secret could then be supplied to the libpam-google-authenticator, via manually specifying a configuration file, as described in [1] . You would probably have to copy the secret over to a new file, so it contains the identical secret, which is then in turn used for libpam-google-authenticator. You also need to make sure this file has proper locked down permissions. Then you should be able to have the same secret for your user and the Web UI.

Before you do this, you have to make absolutely sure that the other nodes in your cluster are exempt from TFA, otherwise your cluster will cease working. Nodes need to be able to SSH to each other in order for the cluster to function properly. So it would probably be wise to configure the TOTP only for the specific user accounts you wish to lock down. I would try this on a test cluster first, before any unwanted issues appear..

Be aware that there is a bit of manual labor. You have to do this for every TOTP you wish to add, edit or remove manually. But in theory this would be the way to go about this. You might be able to create a script that manually parses the tfa.cfg and creates the respective files automatically, but there is no out of the box solution for this.

[1] https://github.com/google/google-authenticator-libpam/blob/master/man/pam_google_authenticator.8.md
 
Last edited:
You can setup the same auth code for GUI and ssh. but you have to do that manually, there's no built in support for this.
I should have the setup still around somewhere
 
FWIW: PAM is misused by most plugins and multi-inputs (password + something else) is rather often broken.

IMO you're much better off by using an SSH key and either encrypting the private part of that key locally or even better using a HW dongle or smart-card like a yubikey, nitrokey or another such alternatives.
 
Thanks for the initial pointers here!

I went ahead and installed libpam-google-authenticator and initialized it as I've done on our other Debian-based servers. This generated a configuration file, /root/.google_authenticator with permissions '0400'

I then copied in the secret from /etc/pve/priv/tfa.cfg, as well as the 10 recovery codes I'd recorded separately (as the codes in tfa.cfg seem to be hashed (though this may have been a mistake on my part)

Code:
# TOTP Secret from /etc/pve/priv/tfa.cfg
GO4...xxx
# Secret generated by google-authenticator
# GQY...xxx

" RATE_LIMIT 3 30 1669141015
" DISALLOW_REUSE
" TOTP_AUTH

# Recovery Codes from Proxmox (unhashed)
f9de-xxxx-xxxx-xxxx
194b-xxxx-xxxx-xxxx
ac6e-xxxx-xxxx-xxxx
a810-xxxx-xxxx-xxxx
379b-xxxx-xxxx-xxxx
9cc6-xxxx-xxxx-xxxx
9927-xxxx-xxxx-xxxx
5ad3-xxxx-xxxx-xxxx
26ce-xxxx-xxxx-xxxx
eb70-xxxx-xxxx-xxxx

# Recovery Codes generated by google-authenticator
# 42xxxxxx
# 14xxxxxx
# 77xxxxxx
# 60xxxxxx
# 68xxxxxx

I then made the usual changes [1] to /etc/pam.d/sshd and /etc/ssh/sshd_config, restarted the sshd service and tried opening a new SSH connection to my test Proxmox node. It accepts the password but then fails the TOTP challenge with an "Access denied" message:

Code:
Using username "root".
Keyboard-interactive authentication prompts from server:
| Password:
| Verification code:
End of keyboard-interactive prompts from server
Access denied

So it looks like I've maybe got the pieces that I need to connect to use the same TOTP codes between the Web GUI and SSH connections, but I'm still missing something.

[1] https://ubuntu.com/tutorials/configure-ssh-2fa#2-installing-and-configuring-required-packages
 
FWIW: PAM is misused by most plugins and multi-inputs (password + something else) is rather often broken.

IMO you're much better off by using an SSH key and either encrypting the private part of that key locally or even better using a HW dongle or smart-card like a yubikey, nitrokey or another such alternatives.
Agreed. Password + 2FA is the first step in our process while we secure public keys for our administrators. The goal is to move to passwordless authentication with 2FA.
 
Thanks for the initial pointers here!

I went ahead and installed libpam-google-authenticator and initialized it as I've done on our other Debian-based servers. This generated a configuration file, /root/.google_authenticator with permissions '0400'

I then copied in the secret from /etc/pve/priv/tfa.cfg, as well as the 10 recovery codes I'd recorded separately (as the codes in tfa.cfg seem to be hashed (though this may have been a mistake on my part)

Code:
# TOTP Secret from /etc/pve/priv/tfa.cfg
GO4...xxx
# Secret generated by google-authenticator
# GQY...xxx

" RATE_LIMIT 3 30 1669141015
" DISALLOW_REUSE
" TOTP_AUTH

# Recovery Codes from Proxmox (unhashed)
f9de-xxxx-xxxx-xxxx
194b-xxxx-xxxx-xxxx
ac6e-xxxx-xxxx-xxxx
a810-xxxx-xxxx-xxxx
379b-xxxx-xxxx-xxxx
9cc6-xxxx-xxxx-xxxx
9927-xxxx-xxxx-xxxx
5ad3-xxxx-xxxx-xxxx
26ce-xxxx-xxxx-xxxx
eb70-xxxx-xxxx-xxxx

# Recovery Codes generated by google-authenticator
# 42xxxxxx
# 14xxxxxx
# 77xxxxxx
# 60xxxxxx
# 68xxxxxx

I then made the usual changes [1] to /etc/pam.d/sshd and /etc/ssh/sshd_config, restarted the sshd service and tried opening a new SSH connection to my test Proxmox node. It accepts the password but then fails the TOTP challenge with an "Access denied" message:

Code:
Using username "root".
Keyboard-interactive authentication prompts from server:
| Password:
| Verification code:
End of keyboard-interactive prompts from server
Access denied

So it looks like I've maybe got the pieces that I need to connect to use the same TOTP codes between the Web GUI and SSH connections, but I'm still missing something.

[1] https://ubuntu.com/tutorials/configure-ssh-2fa#2-installing-and-configuring-required-packages

Interesting, I just tried it on a fresh Ubuntu VM and it seems to work for me this way. Do you have the comments in your file as well? I do not, I think it is important that the first line consists of the secret. I am also not sure if comments are even supported. I also did not add the Proxmox recovery codes, though. What does systemctl status sshd say?
 
That was it! :D

I was writing a reply here and lost my draft, but removing the comments in tfa.cfg got the same secret key working for both WebGUI and SSH connections.

I'm settling with the fact that the recovery codes are going to be different between the two interfaces since they normally will not come into daily use and my IT team will not have to worry about which to use where. If someone knows a way to use the recovery codes generated by the WebGUI over on SSH connections, that would be the bees knees...for now, it's working well enough for us.

Thanks!
 
  • Like
Reactions: shanreich