Skip to content

Automating VPN connection when using multifactor authentication with Tunnelblick on MacOS

Sometimes you need to connect to VPN server where connection has been set up using multi factor
authentication, meaning you can’t save your password in a traditionally convenient(read lazy) way. On top of that
it is even more annoying when you need to reach your phone just to get the bloody time based token.

Today I am going to show how to automate this process if you are using Tunnelblick and standard
TOTP MFA like Google Authenticator for example.

So let’s look at how we can do that. First off all you need to locate you config file:

➜  ~ ls /Users/$USER/Library/Application\ Support/Tunnelblick/Configurations
configtest.tblk
➜  ~ 

As you can see I have configuration called ‘configtest’, now if you go inside you should find your config:

➜  ~ cat /Users/$USER/Library/Application\ Support/Tunnelblick/Configurations/configtest.tblk/Contents/Resources/config.ovpn | head -25
client
dev tun
auth-user-pass
persist-key
persist-tun
remote-cert-tls server
blabla
blabalaa
...
<connection>
remote your-vpn-server.com 2000 tcp
float
nobind
</connection>

<ca>
-----BEGIN CERTIFICATE-----

➜  ~ 

Once you found you config, you need to replace string ‘auth-user-pass’ with ‘auth-user-pass your_auth_file”, for example as below:

➜  ~ cat /Users/$USER/Library/Application\ Support/Tunnelblick/Configurations/configtest.tblk/Contents/Resources/config.ovpn | head -5 
client
dev tun
auth-user-pass /Users/your_user_name/auth.txt
persist-key
persist-tun

Now your password will be taken from file ‘/Users/your_user_name/auth.txt’. But because it dynamically
created we will need to update that file programmatically.

But before updating file let’s look at how we can generate one-time password with oathtool.
On MacOS you can install it with brew:

brew install oath-toolkit

Now you can use it with you secret:

➜  ~ oathtool --totp -b -d 6 ABCAB23455765
892455

Here are ABCAB23455765 is your Base32 secret string,
-d 6 means generate 6 digit long token,
-totp means use Time-based One-Time Password and
-b means use base32 secret key

Alternatively you can use Linux version from Docker container on Mac:

~ docker run --name oathtool_container -it ubuntu sh
# apt-get update && apt-get install -y oathtool

and then execute the tool by running:

~ docker exec oathtool_container sh -c "oathtool --totp -b -d 6 ABCAB23455765"
778834

Either way, you can now generate your token, so le’t update the file now:

#!/bin/bash

echo -e "your_vpn_user_name_here\n`oathtool \
  --totp -b -d 6 ABCAB23455765`" > /Users/your_user_name/auth.txt

or docker version:

#!/bin/bash

echo -e "your_vpn_user_name_here\n`docker exec -it oathtool_container sh -c "oathtool \
  --totp -b -d 6 ABCAB23455765"`" > /Users/your_user_name/auth.txt

As you can see, the auth file should have 2 lines, where 1st line is for username and 2nd is for password.

We are almost there, one last thing is to automate tunnelblick connections and we will use osascript for that:

#!/bin/bash

echo -e "your_vpn_user_name_here\n`oathtool \
  --totp -b -d 6 ABCAB23455765`" > /Users/your_user_name/auth.txt

osascript -e "tell application \"/Applications/Tunnelblick.app\"" -e\
  "connect \"configtest\"" -e "end tell"

Please note ‘configtest’ is the connections name, so pick up the right one from Tunnelblick.

If you think saving the secret in the file won’t be secure enough (and you will be right!), you can go further and use vault for example.
You can also keep the file encrypted, and decrypt with passw when it is asked, then delete when connected:

echo 'enter dec pass:'
read -s pass_to_decrypt
echo -e $(openssl enc -aes-256-cbc -d -in ~/$path_2_enc_file.enc -k $pass_to_decrypt)" > /Users/your_user_name/auth.txt
sleep 5
rm /Users/your_user_name/auth.txt

That is it, all you need now is just to call this script from your favourite cmd line tool and forget about your mobile or whatever tool you have been
using to generate the MFA token.

Best way would be adding it to your .zshrc/.bashrc file:

export PATH=$PATH:/path_to_your_vpn_connection_script

You can chill now!

One Comment

  1. Tom Tom

    This is interesting to me. However, as a windows user, I am looking for something similar in a windows world. Fortunately there is an answer. The idea is the same, but I use Devolutions RDM solution for a connection manager. Some connections, by default support this, but not all. Using the technique above, I think I can do similar to automate it (using their powershell cmdlets on Windows). Thanks!

    Note: They do offer a Mac version as well, and their free offering is very full featured as well, so may be a viable alternative for those reading this who may be interested. And no, I have no connection to the company, other than as a user and advocate (aka fanboi, if you must – but this is about the only software I would accept that title to).

Comments are closed.