Connect to Open VPN during Gitlab Pipeline
Gitlab CI/CD offers the possibility to create a pipeline, which runs when something changes in the repository. A pipeline consists of one or more stages that run in order and in these stages, for example, it is possible to build the project, run the tests, create the artifacts, etc. For more information about Gitlab CI/CD, I suggest you look over the documentation.
These out-of-the-box solutions really simplify the work to be done to have a CI up and running. For example, this is the configuration file (a file called .gitlab-ci.yml
placed at the repository’s root) needed for running all the tests of a Kotlin project.
image: openjdk:11-jdk
cache:
key: ${CI_PROJECT_ID}
paths:
- .gradle/
before_script:
- export GRADLE_USER_HOME=$(pwd)/.gradle
- chmod +x ./gradlew
stages:
- test
test:
stage: test
script:
- ./gradlew test --info --stacktrace
But, let’s assume that the project is using some libraries that are published on a private Maven repository behind a VPN. The pipeline will fail because it can’t download the dependencies.
To connect to a VPN, it is necessary to do some tweaks before starting the stages of the pipeline. And it is possible to do it by writing the commands inside the before_script:
phase.
For this example, I will use OpenVPN but the script can be adapted for whatever type of VPN.
Before writing any code, it is necessary to write some secret variables (the menu is available under Settings > CI/CD > Variables - here for more info). Three variables are necessary:
- CLIENT_OVPN -> the content of the .ovpn file
- VPN_USER -> the VPN user
- VPN_PWD -> the VPN password
First of all, some dependencies are needed
before_script:
...
## VPN
- echo "Setup Open VPN"
- which openvpn || (apt-get update -y -qq && apt-get install -y -qq openvpn && apt-get install -y -qq iputils-ping)
Then the secrets need to be loaded:
before_script:
...
- cat <<< $CLIENT_OVPN > /etc/openvpn/client.ovpn
- cat <<< $VPN_USER > /etc/openvpn/cred.txt
- cat <<< $VPN_PWD >> /etc/openvpn/cred.txt # append at the bottom
Now, the connection can be performed:
before_script:
...
- openvpn --config /etc/openvpn/client.ovpn --auth-user-pass /etc/openvpn/cred.txt --daemon
To check that everything is ok I make a 30 seconds sleep (yes, it’s brutal but it works) and then I ping the server:
before_script:
...
- sleep 30s
- ping -c 1 <your-ip>
And that’s it! Now the pipeline can download all the dependencies, even the ones under VPN.
For reference, here’s the complete .gitlab-ci.yml
file:
image: openjdk:11-jdk
cache:
key: ${CI_PROJECT_ID}
paths:
- .gradle/
before_script:
- export GRADLE_USER_HOME=$(pwd)/.gradle
- chmod +x ./gradlew
## VPN
- echo "Setup Open VPN"
- which openvpn || (apt-get update -y -qq && apt-get install -y -qq openvpn && apt-get install -y -qq iputils-ping)
- cat <<< $CLIENT_OVPN > /etc/openvpn/client.ovpn
- cat <<< $VPN_USER > /etc/openvpn/cred.txt
- cat <<< $VPN_PWD >> /etc/openvpn/cred.txt
- openvpn --config /etc/openvpn/client.ovpn --auth-user-pass /etc/openvpn/cred.txt --daemon
- sleep 30s
- ping -c 1 <your-ip>
stages:
- test
test:
stage: test
script:
- ./gradlew test --info --stacktrace