<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: WoutBuelens</title>
    <description>The latest articles on DEV Community by WoutBuelens (@woutb).</description>
    <link>https://dev.to/woutb</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F327392%2Fad3ed9cc-c247-47d4-8e99-6b44866fb145.jpg</url>
      <title>DEV Community: WoutBuelens</title>
      <link>https://dev.to/woutb</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/woutb"/>
    <language>en</language>
    <item>
      <title>Connect to VPN inside a pipeline (CI/CD)</title>
      <dc:creator>WoutBuelens</dc:creator>
      <pubDate>Tue, 03 Nov 2020 18:21:35 +0000</pubDate>
      <link>https://dev.to/woutb/connect-to-vpn-inside-a-pipeline-ci-cd-53d8</link>
      <guid>https://dev.to/woutb/connect-to-vpn-inside-a-pipeline-ci-cd-53d8</guid>
      <description>&lt;p&gt;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!&lt;/p&gt;

&lt;h1&gt;
  
  
  File Structure
&lt;/h1&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── .circleci
      └── config.yml  
      └── forti-vpn.sh
      └── forticlient-sslvpn_4.4.2333-1_amd64.deb 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;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. &lt;br&gt;
The 'root' of your repo inside the machine is: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;/home/$CIRCLE_PROJECT_REPONAME/&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I'll dive into the two Forticlient files later in this post.&lt;/p&gt;
&lt;h1&gt;
  
  
  VPN Setup
&lt;/h1&gt;

&lt;p&gt;It's actually easier than you might think. The build tool (CircleCI, Jenkins, Azure, Github Workflow,..) actually just utilizes by default docker images &lt;a href="https://circleci.com/docs/2.0/executor-types/"&gt;(read more)&lt;/a&gt;. Usually, the build automation tool has some agents (Linux containers) already running. But since we need some special &lt;a href="https://en.wikipedia.org/wiki/TUN/TAP"&gt;TUN/TAP drivers&lt;/a&gt;, we'll need to spin up a Linux VM ourselves.&lt;/p&gt;

&lt;p&gt;Don't worry, you don't need anything special for it, just 1 line of code at the top of your &lt;code&gt;config.yml&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;version: 2.1
&lt;span class="nb"&gt;jobs&lt;/span&gt;:
    build:
        machine:
            image: ubuntu-1604:201903-01
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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.&lt;/p&gt;

&lt;h1&gt;
  
  
  VPN Clients
&lt;/h1&gt;

&lt;h2&gt;
  
  
  FortiClient
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Environment variables
&lt;/h3&gt;

&lt;p&gt;Add your FortiClient host (with port), username and password as environment variables in the UI of CircleCI&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;FORTI_HOST &lt;em&gt;hostname:port&lt;/em&gt; &lt;/li&gt;
&lt;li&gt;FORTI_USER &lt;em&gt;forticlient username&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;FORTI_PASSWORD &lt;em&gt;forticlient password&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Install FortiClient
&lt;/h3&gt;

&lt;p&gt;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 &lt;code&gt;.circleci&lt;/code&gt; folder. You can download the file from &lt;a href="https://hadler.me/linux/forticlient-sslvpn-deb-packages/"&gt;here&lt;/a&gt;. On Azure, the following cmd did work:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;wget https://hadler.me/files/forticlient-sslvpn_4.4.2333-1_amd64.deb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have the installer, but we still need to create a step which installs the tool inside our Linux.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;- run:
name: Install FortiClient
&lt;span class="nb"&gt;command&lt;/span&gt;: |
    &lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /home/&lt;span class="nv"&gt;$CIRCLE_PROJECT_REPONAME&lt;/span&gt;/vpn/tmp
    &lt;span class="nb"&gt;cd&lt;/span&gt; /home/&lt;span class="nv"&gt;$CIRCLE_PROJECT_REPONAME&lt;/span&gt;/vpn
    &lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Install Expect"&lt;/span&gt;
    &lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;expect
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Install PPP"&lt;/span&gt;
    &lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;ppp expect
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Install FortiClient"&lt;/span&gt;

    &lt;span class="nb"&gt;sudo cp&lt;/span&gt;  ~/.circleci/forticlient-sslvpn_4.4.2333-1_amd64.deb &lt;span class="nb"&gt;.&lt;/span&gt;
    &lt;span class="nb"&gt;sudo &lt;/span&gt;dpkg &lt;span class="nt"&gt;-x&lt;/span&gt; forticlient-sslvpn_4.4.2333-1_amd64.deb /home/&lt;span class="nv"&gt;$CIRCLE_PROJECT_REPONAME&lt;/span&gt;/vpn

    &lt;span class="nb"&gt;sudo truncate&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; 0 opt/forticlient-sslvpn/64bit/helper/License.txt
    &lt;span class="nb"&gt;sudo&lt;/span&gt; ./opt/forticlient-sslvpn/64bit/helper/setup &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null &amp;lt; &amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;echo &lt;/span&gt;y&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;*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.&lt;/p&gt;

&lt;h3&gt;
  
  
  Connect to the VPN
&lt;/h3&gt;

&lt;p&gt;You only need to provide your credentials as environment variables. Create this file and paste in the following &lt;a href="https://gist.github.com/WoutB/4b0706ca99fdf7b9d7def15372beb7ab#file-forti-vpn-sh"&gt;script&lt;/a&gt; (or you can get this file)&lt;/p&gt;

&lt;p&gt;Then, add a step to connect to the VPN using the script.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    &lt;span class="nb"&gt;sudo &lt;/span&gt;wget https://gist.githubusercontent.com/buelenw/0887937a8cffaca9c9ec84c8b4c47a06/raw/a8575708e860b33f5f51ae834ee64558d1a57d14/forti-vpn.sh
    &lt;span class="nb"&gt;sudo sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; s/&lt;span class="s2"&gt;"&amp;lt;FORTI_HOST&amp;gt;"&lt;/span&gt;/&lt;span class="nv"&gt;$FORTI_HOST&lt;/span&gt;/ forti-vpn.sh
    &lt;span class="nb"&gt;sudo sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; s/&lt;span class="s2"&gt;"&amp;lt;FORTI_USERNAME&amp;gt;"&lt;/span&gt;/&lt;span class="nv"&gt;$FORTI_USER&lt;/span&gt;/ forti-vpn.sh
    &lt;span class="nb"&gt;sudo sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; s/&lt;span class="s2"&gt;"&amp;lt;FORTI_PASSWORD&amp;gt;"&lt;/span&gt;/&lt;span class="nv"&gt;$FORTI_PASSWORD&lt;/span&gt;/ forti-vpn.sh
    &lt;span class="nb"&gt;sudo chown &lt;/span&gt;root:root forti-vpn.sh
    &lt;span class="nb"&gt;sudo chmod &lt;/span&gt;600 forti-vpn.sh
    &lt;span class="nb"&gt;sudo chmod&lt;/span&gt; +x forti-vpn.sh
    &lt;span class="nb"&gt;nohup sudo&lt;/span&gt; ./forti-vpn.sh &amp;amp;     
    &lt;span class="nb"&gt;sleep &lt;/span&gt;10

    &lt;span class="nv"&gt;HOST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$SERVER&lt;/span&gt;
    &lt;span class="nv"&gt;ip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;HOST&lt;/span&gt;&lt;span class="p"&gt;%%&lt;/span&gt;:&lt;span class="p"&gt;*&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
    ping &lt;span class="nt"&gt;-c&lt;/span&gt; 1 &lt;span class="nv"&gt;$ip&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$?&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;*the sed command will place your credentials into the login script&lt;/p&gt;

&lt;p&gt;&lt;em&gt;the sleep is needed for to VPN connection to establish&lt;/em&gt;&lt;br&gt;
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.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Make sure to kill the VPN connection at the end of your job&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo pkill forti
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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 &amp;amp; Azure DevOps.&lt;/p&gt;

&lt;h1&gt;
  
  
  References
&lt;/h1&gt;

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

</description>
      <category>devops</category>
      <category>pipeline</category>
      <category>cicd</category>
      <category>circleci</category>
    </item>
  </channel>
</rss>
