OpenVPN OTP Authentication

Yes sure i will have a look thanks for your work :smiley:

Hey Erik,

after some hours I got it to work. I configured the OpenVPN-Server to use TOTP in connection with username/password autentication using pam_unix.so

I first configured the OpenVPN-Server to use authentication via username/password using this how-to: https://wiki.ipfire.org/configuration/services/openvpn/extensions/plugins/auth-pam

After that was working i started to integrate OTP authentication.

I created a folder where the secret files of the users should be stored and created a user for creating the software tokens:

addgroup gauth
useradd -g gauth gauth
mkdir /var/ipfire/ovpn/google-authenticator
chown gauth:gauth /var/ipfire/ovpn/google-authenticator
chmod 0700 /var/ipfire/ovpn/google-authenticator

I customized the /etc/pam.d/openvpn :

#Google Authenticator
auth    requisite       /usr/lib/security/pam_google_authenticator.so secret=/var/ipfire/ovpn/google-authenticator/${USER} user=gauth forward_pass debug

#Username/Password authentication
auth    required        pam_unix.so use_first_pass
account required        pam_unix.so

This is what my server.conf.local looks like:
plugin /usr/lib/openvpn/plugins/openvpn-plugin-auth-pam.so /etc/pam.d/openvpn

Here are my entrys in client.conf.local:

#Username - Password Authentication
auth-user-pass

#Do not cache auth info
auth-nocache

For creating new users more convenient I use the following shellscript:
#!/bin/bash

#variables

#MFA Label
MFA_LABEL='Testcorp OpenVPN-Server'

#MFA User
MFA_USER=gauth

#Directory for Secretfiles
MFA_DIR=/var/ipfire/ovpn/google-authenticator


##########################################################################
echo -en "Please enter new username:"
read user_id

if [ "$user_id" = "" ]; then
	echo "ERROR: No username specified"
	exit 1
fi

echo "Creating account ${user_id}"
useradd -s /bin/false "$user_id"

echo "Please enter password for new user"
passwd "$user_id"

echo "Creating MFA token"
su -c "google-authenticator -t -C -d -r3 -R30 -f -l \"${MFA_LABEL}\" -s $MFA_DIR/${user_id}" - $MFA_USER | tee $MFA_DIR/otp-config/$user_id

For logging in using the OpenVPN client i created roadwarrior connection for each user over the WUI
and did the import on the client machine. The credentials you have to type in when connecting are the following:

username : USER_ID
password: password+otp-token (for example: password934741)

Hope I didn’t miss something. I hope the packages could find a way into the pakfire repo :slight_smile:

Greetings

Steffen

1 Like

Great work Steffen! Will give it a try may in the evening.
Have had the user/group/dir and permissions block also in the install.sh of google-authenticator. Am thinking about to reintegrate it or should we keep it simple ?
Do you think we can bring other additionals to the package ?
May the PAM config might be nice ?
Should we rework the script a little to integrate it also into the package ?

Best,

Erik

Hey Erik,

I think it would be useful to integrate it into the install script to keep it simple for the user. I would also integrate the pam profile and the outputfolders /var/ipfire/ovpn/google-authenticator (for the secret files) and /var/ipfire/ovpn/google-authenticator/otp-config (for the setup and recovery information for each token) and the needed permissions.

Greetings

Steffen

Hi Steffen,
did test it and what should i say, i works :slightly_smiling_face:

Mar 11 14:53:00 ipfire openvpn[5654]: PAM _pam_init_handlers: no default config other
Mar 11 14:53:00 ipfire google-auth-openvpn(pam_google_authenticator)[5654]: debug: start of google_authenticator for "ummeegge"
Mar 11 14:53:00 ipfire google-auth-openvpn(pam_google_authenticator)[5654]: debug: Secret file permissions are 0400. Allowed permissions are 0600
Mar 11 14:53:00 ipfire google-auth-openvpn(pam_google_authenticator)[5654]: debug: "/var/ipfire/ovpn/accounting/google-authenticator/ummeegge" read
Mar 11 14:53:00 ipfire google-auth-openvpn(pam_google_authenticator)[5654]: debug: shared secret in "/var/ipfire/ovpn/accounting/google-authenticator/ummeegge" processed
Mar 11 14:53:00 ipfire google-auth-openvpn(pam_google_authenticator)[5654]: debug: google_authenticator for host "(null)"
Mar 11 14:53:00 ipfire google-auth-openvpn(pam_google_authenticator)[5654]: debug: no scratch code used from "/var/ipfire/ovpn/accounting/google-authenticator/ummeegge"
Mar 11 14:53:00 ipfire google-auth-openvpn(pam_google_authenticator)[5654]: Accepted google_authenticator for ummeegge
Mar 11 14:53:00 ipfire google-auth-openvpn(pam_google_authenticator)[5654]: debug: "/var/ipfire/ovpn/accounting/google-authenticator/ummeegge" written
Mar 11 14:53:00 ipfire google-auth-openvpn(pam_google_authenticator)[5654]: debug: end of google_authenticator for "ummeegge". Result: Success
Mar 11 14:53:00 ipfire openvpnserver[5652]: 192.168.123.4:41732 PLUGIN_CALL: POST /usr/lib/openvpn/plugins/openvpn-plugin-auth-pam.so/PLUGIN_AUTH_USER_PASS_VERIFY status=0
Mar 11 14:53:00 ipfire openvpnserver[5652]: 192.168.123.4:41732 TLS: Username/Password authentication succeeded for username 'ummeegge' 
Mar 11 14:53:00 ipfire openvpnserver[5652]: 192.168.123.4:41732 Outgoing Data Channel: Cipher 'AES-256-GCM' initialized with 256 bit key
Mar 11 14:53:00 ipfire openvpnserver[5652]: 192.168.123.4:41732 Incoming Data Channel: Cipher 'AES-256-GCM' initialized with 256 bit key
Mar 11 14:53:00 ipfire openvpnserver[5652]: 192.168.123.4:41732 Control Channel: TLSv1.3, cipher TLSv1.3 TLS_CHACHA20_POLY1305_SHA256, 2048 bit RSA
Mar 11 14:53:00 ipfire openvpnserver[5652]: 192.168.123.4:41732 [otptest] Peer Connection Initiated with [AF_INET]192.168.123.4:41732
Mar 11 14:53:00 ipfire openvpnserver[5652]: otptest/192.168.123.4:41732 OPTIONS IMPORT: reading client specific options from: /var/ipfire/ovpn/ccd/otptest
Mar 11 14:53:00 ipfire openvpnserver[5652]: otptest/192.168.123.4:41732 MULTI_sva: pool returned IPv4=10.63.16.14, IPv6=(Not enabled)
Mar 11 14:53:00 ipfire openvpnserver[5652]: otptest/192.168.123.4:41732 MULTI: Learn: 10.63.16.14 -> otptest/192.168.123.4:41732
Mar 11 14:53:00 ipfire openvpnserver[5652]: otptest/192.168.123.4:41732 MULTI: primary virtual IP for otptest/192.168.123.4:41732: 10.63.16.14
Mar 11 14:53:01 ipfire openvpnserver[5652]: otptest/192.168.123.4:41732 PUSH: Received control message: 'PUSH_REQUEST'
Mar 11 14:53:01 ipfire openvpnserver[5652]: otptest/192.168.123.4:41732 SENT CONTROL [otptest]: 'PUSH_REPLY,route 10.63.16.1,topology net30,ping 10,ping-restart 60,redirect-gateway,route 192.168.234.0 255.255.255.0,dhcp-option DNS 192.168.123.222,dhcp-option DNS 8.8.4.4,ifconfig 10.63.16.14 10.63.16.13,peer-id 0' (status=1)

. Needed to modify the script a little in this line ‘$MFA_DIR/otp-config/$user_id’ since ‘otp-config’ is not there and are not created via google-authenticator.
Another one is, the barcode comes not up with the script via terminal…

Have extend the script a little but also the package but am stalled currently since there is a discussion if not signed packages should be provided in here in general.

Either way good work !

Best,

Erik

Hey Erik,

I’m happy that it works for you too. Yes the folder /var/ipfire/ovpn/google-authenticator and /var/ipfire/ovpn/google-authenticator/otp-config were created manually because i wanted an output directory for the secret files an the otp-config files. The directories can be created during installation. The barcode is a picture so if you redirect the output into a file the barcode is not there. But with the URL you can show the barcode.

Greetings

Steffen

Hi all,
made now an package update which includes also an extended script which can be found in here --> https://gitlab.com/ummeegge/google-authenticator-openvpn/-/blob/master/build_files/CONF/google-auth-openvpn/google-auth-adduser .
Script includes now:

  • Add new user
  • Display QR-Code or secret for already existing users
  • Delete existing user
  • List all users
  • Modify OpenVPN server and client config

Script can surely be extended and can surely even be made better but for the first this is how it goes.

  • The PAM profile is also included in the package.
  • A new directory under /var/ipfire/ovpn/accounting/google-authenticator will be created which is the home for all new OTP-OpenVPN users.

Packages are now here --> https://people.ipfire.org/~ummeegge/google-authenticator-openvpn/ located.

All build files can be found in here --> https://gitlab.com/ummeegge/google-authenticator-openvpn for those of you who want to build in their environment. Since the uninstall.sh scripts do not use Pakfire but uninstalls the files too, it is currently not on IPFire Git.

Best,

Erik

2 Likes

I find it a very, very interesting functionality. Have you thought about creating an addon and implementing it in the list of installable addons?

It would be a very good feature.

Hi Roberto,
thanks for you positive feedback. Am currently thinking about how it could looks like.
If a OTP functionality comes to IPFire, more then one application like OpenVPN can participate from this (SSH e.g. what else ?) which brings this topic then to a new level (can hear the whispering of a new CGI in the leaves :grimacing: ) but in this current state here i wanted to find a proper way with OpenVPN, may we can also participate of this work here even it would come as a generalized Addon (no script, no PAM config).

I ask myself also:

There are several questions from my side, do someone else have some too ?

Best,

Erik

I’d like to see two factor authorization (2FA) with Authy. Is that possible?

Or FIDO2 ?

Hi all,

can´t find the sources to build it. Am right that you will always need a third party ?

Are there some links for building it from source and an OpenVPN implementation ?

Best,

Erik

EDIT: Interesting ones from my side:
https://www.saltwaterc.eu/setting-up-totp-for-openvpn-with-oath-toolkit.html

I think Authy authenticator and google Authenticator work the same way. Here is info about the google Authenticator:

disclaimer: keep in mind I know nothing about these type of authenticators.

I picked the Authy system because I am not a big fan of google…

This may help:

Hi Jon,
and thanks for the links may i oversee something but i do miss the sources.

Have build oathtool-kit (with Fedora Glib patch) which needed xmlsec1 as DEP --> https://people.ipfire.org/~ummeegge/oathtool/ and made a fast test like explained in here --> https://johannes.truschnigg.info/blog/2015-10-26 .

What was needed:

  • pam_listfile.so was needed. It is build in IPFire but it is commented in ROOTFILE so it is not presant in the main system.
  • Created a secret with oathtool with the following command
    oathtool -v --totp $(openssl rand -hex 15)
    in HEX and Base32 format. Both can be checked via commandline:
Hex secret: ec2eb5fed5a47ae460f492c6ed190d
Base32 secret: 5QXLL7WVUR5OIYHUSLDO2GIN

both should deliver the same PWD which can be checked for HEX via:
oathtool --totp ec2eb5fed5a47ae460f492c6ed190d
for Base32:
oathtool --totp -b 5QXLL7WVUR5OIYHUSLDO2GIN
both should display the same.

  • New directory /var/ipfire/ovpn/accounting/oath .
  • In there are two files, the first is ‘users_oath’ with the follwing content:
#PROTO		USER	-	SECRET				COUNTER	LASTOTP	TS
HOTP/T30	paterpan	-	024d3bd325ad769815ceb59ce4d8bf

and the second users_whitelist with the username(s):

paterpan
  • The PAM config was created under /etc/pam.d/openvpn-otp-oath with the following content:
# Check if the given username is in the list of allowed names
auth requisite pam_listfile.so file=/var/ipfire/ovpn/accounting/oath/users_whitelist item=user sense=allow onerr=fail
# Check for users' time-based One-Time Password from their OATH token device/app
auth requisite /usr/lib/security/pam_oath.so usersfile=/var/ipfire/ovpn/accounting/oath/users_oath window=10 digits=6

# Permit whitelisted usernames - if this is missing, getpwnam() will fail for non-system users
account sufficient pam_listfile.so file=/var/ipfire/ovpn/accounting/oath/users_whitelist item=user sense=allow onerr=fai
  • OpenVPN server.conf has been extended via “Additional config” with the following entry:
# Oathtool + PAM
plugin /usr/lib/openvpn/plugins/openvpn-plugin-auth-pam.so "openvpn-otp-oath"

and client.ovpn like before with:

#Username - Password Authentication
auth-user-pass

#Do not cache auth info
auth-nocache

Connection worked:

Mar 16 14:45:19 ipfire-server openvpnserver[28948]: 192.168.123.4:49345 peer info: IV_TCPNL=1
Mar 16 14:45:19 ipfire-server openvpn[28949]: PAM _pam_init_handlers: no default config other
Mar 16 14:45:19 ipfire-server openvpnserver[28948]: 192.168.123.4:49345 PLUGIN_CALL: POST /usr/lib/openvpn/plugins/openvpn-plugin-auth-pam.so/PLUGIN_AUTH_USER_PASS_VERIFY status=0
Mar 16 14:45:19 ipfire-server openvpnserver[28948]: 192.168.123.4:49345 TLS: Username/Password authentication succeeded for username 'paterpan' 
Mar 16 14:45:19 ipfire-server openvpnserver[28948]: 192.168.123.4:49345 Outgoing Data Channel: Cipher 'AES-256-GCM' initialized with 256 bit key
Mar 16 14:45:19 ipfire-server openvpnserver[28948]: 192.168.123.4:49345 Incoming Data Channel: Cipher 'AES-256-GCM' initialized with 256 bit key
Mar 16 14:45:19 ipfire-server openvpnserver[28948]: 192.168.123.4:49345 Control Channel: TLSv1.3, cipher TLSv1.3 TLS_CHACHA20_POLY1305_SHA256, 2048 bit RSA
Mar 16 14:45:19 ipfire-server openvpnserver[28948]: 192.168.123.4:49345 [oathtest] Peer Connection Initiated with [AF_INET]192.168.123.4:49345
Mar 16 14:45:19 ipfire-server openvpnserver[28948]: oathtest/192.168.123.4:49345 OPTIONS IMPORT: reading client specific options from: /var/ipfire/ovpn/ccd/oathtest
Mar 16 14:45:19 ipfire-server openvpnserver[28948]: oathtest/192.168.123.4:49345 MULTI_sva: pool returned IPv4=10.63.16.18, IPv6=(Not enabled)
Mar 16 14:45:19 ipfire-server openvpnserver[28948]: oathtest/192.168.123.4:49345 MULTI: Learn: 10.63.16.18 -> oathtest/192.168.123.4:49345
Mar 16 14:45:19 ipfire-server openvpnserver[28948]: oathtest/192.168.123.4:49345 MULTI: primary virtual IP for oathtest/192.168.123.4:49345: 10.63.16.18
Mar 16 14:45:20 ipfire-server openvpnserver[28948]: oathtest/192.168.123.4:49345 PUSH: Received control message: 'PUSH_REQUEST'
Mar 16 14:45:20 ipfire-server openvpnserver[28948]: oathtest/192.168.123.4:49345 SENT CONTROL [oathtest]: 'PUSH_REPLY,route 10.63.16.1,topology net30,ping 10,ping-restart 60,redirect-gateway,route 192.168.234.0 255.255.255.0,dhcp-option DNS 192.168.123.1,dhcp-option DNS 192.168.234.1,ifconfig 10.63.16.18 10.63.16.17,peer-id 0' (status=1)

The difference:

  • Another PAM modul was needed.
  • This config includes currently no system users under passwd.
  • Only OTP for authentication needed with this config, no user password.

OTP can be checked via

watch oathtool --totp -b 5QXLL7WVUR5OIYHUSLDO2GIN

whereby every 30sec´s the OTP is changing.

To generate the QR-Code you would need libqrencode and e.g. the following command should it display:

qrencode -t ANSIUTF8 5QXLL7WVUR5OIYHUSLDO2GIN

Some more testings here.

Best,

Erik

3 Likes

Very impressive! I am so glad you understand this. It is miles over my head! :exploding_head:

Since we are all together we will get this miles over head much much closer to another :innocent: or in other words WWG1WGA :upside_down_face: .

Great that you are be here !

Best,

Erik

1 Like

Hi Erik,
Thanks for this part! Just tried to run it but as metioned missing the pam_listfile.so file.
Where would i get that is even possible?
Running ipfire 1.4.5.
Thanks,
Stephan.

Hi Stephan,
have uploaded it for you, you can find it in here --> https://people.ipfire.org/~ummeegge/oathtool/ . Home of ‘pam_listfile.so’ is under /lib/security/ . If you find some new configurations, it might be nice if you post them here…

Best,

Erik

1 Like

Hi Erik,
Thanks a lot, works like a charm.
Will let you (all) know when finding something interesting :+1:
Stephan