DEV Community

loading...
Cover image for Connect to VPN inside a pipeline (CI/CD)

Connect to VPN inside a pipeline (CI/CD)

WoutBuelens
401 - unauthorized, you curious bastard!
・3 min read

For numerous reasons, some servers are protected with a VPN, but it shouldn't hold you back from using a CI/CD. In this guide (aka my first one), I'll describe how to connect to your VPN inside your pipeline. Let's get started!

File Structure

It is always suggested to put your pipeline files inside one folder, to keep things clean. This is a file structure for CircleCI using Forticlient VPN.

├── .circleci
      └── config.yml  
      └── forti-vpn.sh
      └── forticlient-sslvpn_4.4.2333-1_amd64.deb 
Enter fullscreen mode Exit fullscreen mode

I suggest you put most of your files needed, inside the .circleci folder, as this can keep the structure clean and put all your pipeline files hidden away from your code.
The 'root' of your repo inside the machine is:

/home/$CIRCLE_PROJECT_REPONAME/

I'll dive into the two Forticlient files later in this post.

VPN Setup

It's actually easier than you might think. The build tool (CircleCI, Jenkins, Azure, Github Workflow,..) actually just utilizes by default docker images (read more). Usually, the build automation tool has some agents (Linux containers) already running. But since we need some special TUN/TAP drivers, we'll need to spin up a Linux VM ourselves.

Don't worry, you don't need anything special for it, just 1 line of code at the top of your config.yml.

version: 2.1
jobs:
    build:
        machine:
            image: ubuntu-1604:201903-01
Enter fullscreen mode Exit fullscreen mode

The machine line tells the tool to spin up a specific Linux machine, because in the standard ones, the TUN/TAP driver are disabled by default.

VPN Clients

FortiClient

Environment variables

Add your FortiClient host (with port), username and password as environment variables in the UI of CircleCI

  • FORTI_HOST hostname:port
  • FORTI_USER forticlient username
  • FORTI_PASSWORD forticlient password

Install FortiClient

At the time of writing, I wasn't able to install forticlient inside a cmd with a curl command or otherwise, so I'm just passing the installation file inside the .circleci folder. You can download the file from here. On Azure, the following cmd did work:

sudo wget https://hadler.me/files/forticlient-sslvpn_4.4.2333-1_amd64.deb
Enter fullscreen mode Exit fullscreen mode

Now we have the installer, but we still need to create a step which installs the tool inside our Linux.

- run:
name: Install FortiClient
command: |
    mkdir -p /home/$CIRCLE_PROJECT_REPONAME/vpn/tmp
    cd /home/$CIRCLE_PROJECT_REPONAME/vpn
    sudo apt-get update
    echo "Install Expect"
    sudo apt-get install expect
    echo "Install PPP"
    sudo apt-get install ppp expect
    echo "Install FortiClient"

    sudo cp  ~/.circleci/forticlient-sslvpn_4.4.2333-1_amd64.deb .
    sudo dpkg -x forticlient-sslvpn_4.4.2333-1_amd64.deb /home/$CIRCLE_PROJECT_REPONAME/vpn

    sudo truncate -s 0 opt/forticlient-sslvpn/64bit/helper/License.txt
    sudo ./opt/forticlient-sslvpn/64bit/helper/setup >/dev/null < <(echo y)
Enter fullscreen mode Exit fullscreen mode

*you don't need to change anything in this script, the $CIRCLE_PROJECT_REPONAME is a circleci env var, that automatically grabs your repo name.

Connect to the VPN

You only need to provide your credentials as environment variables. Create this file and paste in the following script (or you can get this file)

Then, add a step to connect to the VPN using the script.

    sudo wget https://gist.githubusercontent.com/buelenw/0887937a8cffaca9c9ec84c8b4c47a06/raw/a8575708e860b33f5f51ae834ee64558d1a57d14/forti-vpn.sh
    sudo sed -i s/"<FORTI_HOST>"/$FORTI_HOST/ forti-vpn.sh
    sudo sed -i s/"<FORTI_USERNAME>"/$FORTI_USER/ forti-vpn.sh
    sudo sed -i s/"<FORTI_PASSWORD>"/$FORTI_PASSWORD/ forti-vpn.sh
    sudo chown root:root forti-vpn.sh
    sudo chmod 600 forti-vpn.sh
    sudo chmod +x forti-vpn.sh
    nohup sudo ./forti-vpn.sh &     
    sleep 10

    HOST=$SERVER
    ip=${HOST%%:*}
    ping -c 1 $ip ;  echo $?
Enter fullscreen mode Exit fullscreen mode

*the sed command will place your credentials into the login script

the sleep is needed for to VPN connection to establish
After the sleep there's a check which pings the SERVER and returns 1 if the server is unreachable. This will automatically stop the CircleCI workflow.

Make sure to kill the VPN connection at the end of your job

sudo pkill forti
Enter fullscreen mode Exit fullscreen mode

This guide is working with Forti-client, but I'm pretty sure it's the same solution for all other VPN-clients (like Cisco-anyconnect and OpenVPN. It has been tested on both CircleCi & Azure DevOps.

References

https://discuss.circleci.com/t/vpn-connection-from-build-machine/4033
https://confluence.jaytaala.com/display/TKB/Continuous+and+automated+VPN+connection+with+FortiClient+%28CLI+only%29+using+bash+and+expect+scripting
https://serverfault.com/questions/412220/fortinet-ssl-vpn-client-setup-without-gui-on-linux-centos/484988#484988?newreg=9f12134c83234e27bb2ec21784900b36
https://gist.github.com/PieterScheffers/20583b65ef171cf94db16e6c659498f3

Discussion (0)