OpenBSD: OpenSSH with Two-Factor Authentication
The OpenSSH daemon is targeted by brute-force attacks almost everyday. There are various ways to deal with the annoying attempts of unauthorised access, such as using certificates, one of which is multi-factor authentication. Here are some thoughts to set this up in the realm of OpenBSD...
Having a very complex password or long passphrase may seem to be an adequate solution to minimise the risk that a few random password guesses will be successful. Hands-on experience shows that a better solution is to replace passwords with certificates. And even better solution is to combine multiple pieces of evidence (factors), also known as multi-factor authentication (MFA).
The following how-to considers that users can successfully log in using certificates.
On the server side, the SSH daemon's configuration file (
sshd_config) needs to be updated in order to accept user's
password additionally to the already configured
$ echo "AuthenticationMethods publickey,password" >> /etc/ssh/sshd_config
And the server restarted:
$ rcctl restart sshd
OATH OTP Provider
As root, installation of
libqrencode to generate QR codes:
$ pkg_add login_oath quirks-3.124 signed on 2019-04-15T12:10:16Z login_oath-0.8p4:openpam-20141014: ok login_oath-0.8p4:oath-toolkit-2.6.2p0: ok login_oath-0.8p4: ok New and changed readme(s): /usr/local/share/doc/pkg-readmes/login_oath $ pkg_add libqrencode quirks-3.124 signed on 2019-04-15T12:10:16Z libqrencode-4.0.2: ok
As unprivileged user:
$ openssl rand -hex 20 > ~/.totp-key # generate the seed (in hexadecimal format) $ chmod 400 ~/.totp-key
Alternatively (not used in the following example), a more secure variant using
$ head -50 /dev/urandom | sha512 > ~/.totp-key # generate the seed (in hexadecimal format) $ chmod 400 ~/.totp-key
Verification can be perfomed as follows (the
-d<NUM> specifies the number of digits in OTP, the default is 6):
$ oathtool -v -d6 --totp `cat ~/.totp-key` Hex secret: <HEX-SECRET> Base32 secret: <BASE32-SECRET> Digits: 6 Window size: 0 Start counter: 0x0 (0)
Generating the QR code image for the previously generated
$ qrencode -d 90 -s 4 -o <USERNAME>@<SERVER-DOMAINNAME>.png 'otpauth://totp/<USERNAME>@<SERVER-DOMAINNAME>?secret=<BASE32-SECRET>&issuer=<SERVER-DOMAINNAME>'
The generated file needs to be delivered to the client device application using e-mail, for instance.
The OATH provider needs to be integrated with the login class capability database. After the following lines that are present in the
# Default allowed authentication styles for authentication type ftp auth-ftp-defaults:auth-ftp=passwd:
it is necessary to add the following lines:
# Default allowed authentication styles for authentication type ssh auth-ssh-defaults:auth-ssh=-totp:
and also update the appropriate class for which the TOTP is being set with the following line:
As typically, it is the
staff group, the update looks like this:
staff:\ :datasize-cur=1536M:\ :datasize-max=infinity:\ :maxproc-max=512:\ :maxproc-cur=256:\ :ignorenologin:\ :requirehome@:\ :tc=auth-ssh-defaults:\ :tc=default:
Finally, the changes need to by applied either by restarting the server or sourcing the appropriate files as follows:
$ [ -f /etc/login.conf.db ] && cap_mkdb /etc/login.conf
Once connected using an SSH client, the SSH certificate as well as the TOTP (code) will be required.
Trusting Keys Signed by a Certificate Authority
Important note: The following lines are for pure reference only. The configuration may (and most probably will not) work anymore. Reader discretion advised.
Considering the Certificate Authority (CA) was set up using the Easy-RSA, the following commands need to be performed in order to create a signed SSH certificate:
$ cd /PATH/TO/Easy-RSA/ROOT/ $ ssh-keygen -s ./ca.domain.tld/private/ca.key -I <USERNAME>@<SERVER-DOMAINNAME> -n <USERNAME> ~/.ssh/id_rsa.pub Enter passphrase: Signed user key ~/.ssh/id_rsa-cert.pub: id "<USERNAME>@<SERVER-DOMAINNAME>" serial 0 for <USERNAME> valid forever
$ ssh-keygen -lv -f ~/.ssh/id_rsa.pub
Verification of the SSH certificate can be performed as follows:
$ ssh-keygen -L -f ~/.ssh/id_rsa-cert.pub ~/.ssh/id_rsa-cert.pub: Type: email@example.com user certificate Public key: RSA-CERT SHA256:<SHA256-HASH> Signing CA: RSA SHA256:<SHA256-HASH> (using ssh-rsa) Key ID: "<USERNAME>@<SERVER-DOMAINNAME>" Serial: 0 Valid: forever Principals: <USERNAME> Critical Options: (none) Extensions: permit-X11-forwarding permit-agent-forwarding permit-port-forwarding permit-pty permit-user-rc
The local SSH configuration file needs to be updated accordingly:
$ cat << EOF > ~/.ssh/config Host <SERVER-DOMAINNAME> HostName <SERVER-DOMAINNAME> CertificateFile ~/.ssh/id_rsa-cert.pub User <USERNAME> IdentityFile ~/.ssh/id_rsa EOF
Before the CA's public key can be transported to the OpenSSH server, it needs to be converted from the X.509 to the PKCS#8 format as follows:
$ cd /PATH/TO/Easy-RSA/ROOT/ $ openssl x509 -in ./ca.domain.tld/ca.crt -noout -pubkey >pubkey.pem $ ssh-keygen -i -m PKCS8 -f pubkey.pem >ca.domain.tld.pub
On the server side, the following line should be added to the
sshd_config file in order to make sure that the server trusts the keys signed by the CA:
$ echo "AuthenticationMethods publickey,password" >> /etc/ssh/sshd_config $ echo "TrustedUserCAKeys /etc/ssh/ca.domain.tld.pub" >> /etc/ssh/sshd_config
All settings need to be verified now before the OpenSSH daemon is restarted, as the server may become unavailable when something was incorrectly configured!
$ rcctl restart sshd
Before connecting the client to the OpenSSH server,
- the server fingerprint (RSA, ECC etc.) can be printed on the server as follows:
$ ssh-keygen -l -f /etc/ssh/ssh_host_rsa_key 2048 SHA256:<SERVER-FINGERPRINT> server.domain.tld
- and the very same fingerprint should be saved into the local
known_hostsfile on the client's device:
$ vi ~/.ssh/known_hosts <SERVER-DOMAINNAME>,<SERVER-IPADDRESS> ssh-rsa <SERVER-FINGERPRINT>