diff --git a/README.md b/README.md index 2099c33..daacb34 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,7 @@ Conveniently, `kylemanna/openvpn` comes with a script called `ovpn_getclient`, which dumps an inline OpenVPN client configuration file. This single file can then be given to a client for access to the VPN. +To enable Two Factor Authentication for clients (a.k.a. OTP) see [this document](/docs/otp.md). ## OpenVPN Details diff --git a/docs/otp.md b/docs/otp.md new file mode 100644 index 0000000..22d6353 --- /dev/null +++ b/docs/otp.md @@ -0,0 +1,72 @@ +# Using two factor authentication for users + +Instead of relying on complex passwords for client certificates (that usually get written somewhere) this image +provides support for two factor authentication with OTP devices. + +The most common app that provides OTP generation is Google Authenticator ([iOS](https://itunes.apple.com/it/app/google-authenticator/id388497605?mt=8) and +[Android](https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2&hl=it)) you can download it +and use this image to generate user configuration. + +## Usage + +In order to enable two factor authentication the following steps are required. + +* Generate server configuration with `-2` option + + docker run --volumes-from $OVPN_DATA --rm fabn/openvpn ovpn_genconfig -u udp://vpn.example.com -2 + +* Generate your client certificate (possibly without a password since you're using OTP) + + docker run --volumes-from $OVPN_DATA --rm -it fabn/openvpn easyrsa build-client-full nopass + +* Generate authentication configuration for your client. -t is needed to show QR code, -i is optional for interactive usage + + docker run --volumes-from $OVPN_DATA --rm -t fabn/openvpn ovpn_otp_user + +The last step will generate OTP configuration for the provided user with the following options + +``` +google-authenticator --time-based --disallow-reuse --force --rate-limit=3 --rate-time=30 --window-size=3 \ + -l "${1}@${OVPN_CN}" -s /etc/openvpn/otp/${1}.google_authenticator +``` + +It will also show a shell QR code in terminal you can scan with the Google Authenticator application. It also provides +a link to a google chart url that will display a QR code for the authentication. + +**Do not share QR code (or generated url) with anyone but final user, that is your second factor for authentication + that is used to generate OTP codes** + +Here's an example QR code generated for an hypotetical user@example.com user. + +![Example QR Code](https://www.google.com/chart?chs=200x200&chld=M|0&cht=qr&chl=otpauth://totp/user@example.com%3Fsecret%3DKEYZ66YEXMXDHPH5) + +Generate client configuration for `` and import it in OpenVPN client. On connection it will prompt for user and password. + Enter your username and a 6 digit code generated by Authenticator app and you're logged in. + +## TL;DR + +Under the hood this configuration will setup an `openvpn` PAM service configuration (`/etc/pam.d/openvpn`) +that relies on the awesome [Google Authenticator PAM module](https://github.com/google/google-authenticator). +In this configuration the `auth` part of PAM flow is managed by OTP codes and the `account` part is not enforced + because you're likely dealing with virtual users and you do not want to create a system account for every VPN user. + +`ovpn_otp_user` script will store OTP credentials under `/etc/openvpn/otp/.google_authentication`. In this + way when you take a backup OTP users are included as well. + +Finally it will enable the openvpn plugin `openvpn-plugin-auth-pam.so` in server configuration and append the +`auth-user-pass` directive in client configuration. + +## Debug + +If something is not working you can verify your PAM setup with these commands + +``` +# Start a shell in container +docker run --volumes-from $OVPN_DATA --rm -it fabn/openvpn bash +# Then in container install pamtester utility +apt-get update && apt-get install -y pamtester +# To check authentication use this command that will prompt for a valid code from Authenticator APP +pamtester -v openvpn authenticate +``` + +If you configured everything correctly you should get authenticated by entering a OTP code from the app.