CI/CD setups use a lot of automation to achieve their goals of improving development pace and quality. Automated agents are used to execute tasks such as building code changes, executing tests, and deploying increments.

Provisioning and maintaining these automated agents is often a tedious job; therefore, platforms such as Azure DevOps offer their users the possibility to use “hosted” agents that are provisioned automatically when a job needs to run and are destroyed afterwards. However, if a job needs to access other cloud resources (such as databases or virtual machines), making this access secure might be a problem.

Example scenario

This exact topic arose on one of our current projects. The project has been under development for some time and historically used self-hosted build agents running in our local infrastructure. This worked quite well. However, as part of the company-wide cloud push, the project members decided to migrate all the local development infrastructure (database servers, application hosts, build agents) to Microsoft Azure.

In order to follow best practices, it was decided that these resources would be provisioned within their own virtual network (v-LAN) and access to the network from the Internet would be entirely disabled. This means that a VPN connection to the v-LAN would need to be established by anyone wanting to access the project’s cloud resources. This includes the automated build agents used in the project’s CI/CD pipelines. Since one of the build steps is to execute a set of integration tests (this requires access to a database server in the cloud), the build agents must be able to establish the VPN connection on their own.

The issue with Azure VPN

Azure is well-equipped for the scenario outlined above. We created our v-LAN, provisioned a few virtual machines and other resources in it, established a VPN gateway in the network, and cut off all public access to the resources within the network. Next, we tested the VPN access.

There are two main modes of operation for an Azure VPN gateway: site-to-site and point-to-site. The site-to-site connection is usually established on a site level and works seamlessly for all users on that site. The point-to-site VPN connection only connects a single user. For reasons beyond the scope of this article, we could not use the site-to-site VPN connection and had to use the point-to-site connection mode.







The Azure VPN gateway allows users to download a small installer package that creates and configures the necessary P2S VPN settings automatically (on Windows). This works quite seamlessly for people who want to be able to connect to the virtual network. Unfortunately, the configuration created is such that in order to connect to the VPN, user action and administrative rights are necessary. This is not a problem for real humans but presents quite an obstacle for non-interactive environments such as build agents.




Azzure virtual network


In the example scenario above, we have a hosted build agent that lives “in the cloud”, is non-interactive, and must establish a P2S VPN connection to an Azure v-LAN. This turned out to be trickier than originally expected.

Establishing an Azure P2S VPN connection from the command line

After a lot of research and experimentation, we realised there is no officially supported way to achieve the P2S connection from the command line without a lot of fussing with network configuration. Fortunately, the Azure VPN installer mentioned above provides a way to bypass this limitation with just a few commands.

The whole “trick” lies in the Windows utility `rasdial` and some creative usage of the Azure VPN installer.

Rasdial is a Windows command line utility that can connect and disconnect VPN connections. Unfortunately, just pointing it at the Azure VPN gateway isn’t enough because rasdial doesn’t support client certificate authentication (which Azure VPN requires).

The key to side-stepping this limitation is provided in the Azure P2S VPN installer itself. This installer exe file is actually an archive that can be extracted:


Content of the installer
Figure 1 – Content of the installer executable after extraction


The archive contains several files required by the installation process. The most important file is the PBK file. This is a “Dial-Up Phonebook” file containing all the information necessary for rasdial to establish a VPN connection. It also contains information about the authentication mode – in the case of Azure VPN, it specifies which certificates are usable for authenticating to the VPN gateway. The file is named after the GUID assigned to your Azure VPN gateway.

The other important file in the archive is the routes.txt file. This file describes the routing rules necessary for the VPN connection to work properly (basically which connections should go through the VPN and which should not).

ADD MASK default METRIC default IF default
ADD MASK default METRIC default IF default

With these files, we can start creating a script that will establish a P2S connection automatically. These are the steps necessary for it to work on a build agent with no prior configuration:

1. Install a client certificate (this will be used automatically to authenticate against the VPN gateway)
2. Invoke rasdial using the PBK file from the Azure installer
3. Add the routing rules from the routes.txt file
4. The VPN tunnel is established and configured; you can access your cloud resources securely
5. Disconnect the VPN tunnel

The PowerShell script to handle all of this is rather short (the example assumes the VPN gateway GUID is 11111111-1111-1111-1111-111111111111):

$pass = ConvertTo-SecureString -string “MyPassword” -Force -AsPlainText

Import-PfxCertificate -FilePath client.pfx -CertStoreLocation Cert:\CurrentUser\My -Password $pass

rasdial "11111111-1111-1111-1111-111111111111" /PHONEBOOK:"./ 11111111-1111-1111-1111-111111111111.pbk"

New-NetRoute -DestinationPrefix "" -InterfaceAlias 11111111-1111-1111-1111-111111111111

New-NetRoute -DestinationPrefix "" -InterfaceAlias 11111111-1111-1111-1111-111111111111

To disconnect the VPN tunnel, simply call rasdial with the DISCONNECT parameter:

rasdial "11111111-1111-1111-1111-111111111111" /DISCONNECT

This sample script uses a client certificate stored in a password-protected PFX file, but other sources could be used (such as Azure KeyVault). It’s also worth pointing out that the route registration does not directly use the routes.txt file. Instead, we decided to simply rewrite the registration using PowerShell commands. Your routes might be different.

Another important point is that this script contains a lot of secrets. When using this in productive setup, these should come from secure sources (such as KeyVault, secure build pipeline variables, etc.).

And that’s it. With this script, we can now connect any build agent (or any unattended machine) to our Azure virtual network in an automated manner using a P2S VPN connection. The agent/machine can then access protected cloud resources securely and without having to expose them to the public Internet.


In this article, I explained a problem with accessing Azure virtual networks using point-to-site VPN connections without user interaction. I then described a way to solve this problem using rasdial and the VPN configuration installer produced by Azure. In the end, I created a self-contained PowerShell script that can establish an Azure P2S VPN connection in build agents and other unattended setups.


News from ERNI

In our newsroom, you find all our articles, blogs and series entries in one place.

  • 06.12.2023.

    Streamlining software development: The journey from multiple to unified requirements management tools

    Productivity in software development is slowed down by managing specifications across various requirements management (RM) tools. Although moving to a single, updated RM tool involves an upfront investment, the long-term benefits are considerable. These include increased process efficiency, enhanced collaboration, superior traceability, improved software specification quality, cost reductions, scalability and better integration with other RM tools, among others.

  • 22.11.2023.

    Recognising trends: An insight into regression analysis

    Data plays a very important role in every area of a company. When it comes to data, a distinction is made primarily between operational data and dispositive data. Operational data play an important role, especially in day-to-day business. However, they are not nearly as relevant as dispositive data. This is because these data are collected over a longer period of time and provide an initial insight into the history or the past.

  • 08.11.2023.

    Why do we need digital transformation for medical devices?

    For hospitals, it is not up for discussion as to whether they want to digitalise. The increasing age of the population in western countries and the progressive shortage of medical professionals mean that without digitalisation, the healthcare system will not be able to provide the quality that patients want in the future.

  • 25.10.2023.

    Mastering the challenges of mobile app testing: Strategies for efficient quality assurance

    Discover the unique challenges faced in testing mobile applications and learn how to overcome them effectively. From selecting suitable devices and operating systems to leveraging cloud-based test platforms, test automation and emulators, this article provides seven essential strategies for optimising your mobile app testing process.

  • 11.10.2023.

    Incorporating classical requirements engineering methods in agile software development for a laboratory automation system

    Traditional agile methodologies can sometimes struggle to accommodate the complexity and regulatory requirements of laboratory automation systems, leading to misalignment with stakeholder needs, scope creep, and potential delays. The lack of comprehensive requirements documentation can result in ambiguous expectations and hinder effective communication among cross-functional teams.

  • 27.09.2023.

    Unveiling the power of data: Part III – Navigating challenges and harnessing insights in data-driven projects

    Transforming an idea into a successful machine learning (ML)-based product involves navigating various challenges. In this final part of our series, we delve into two crucial aspects: ensuring 24/7 operation of the product and prioritising user experience (UX).

  • 13.09.2023.

    Exploring Language Models: An overview of LLMs and their practical implementation

    Generative AI models have recently amazed with unprecedented outputs, such as hyper-realistic images, diverse music, coherent texts, and synthetic videos, sparking excitement. Despite this progress, addressing ethical and societal concerns is crucial for responsible and beneficial utilization, guarding against issues like misinformation and manipulation in this AI-powered creative era.

  • 01.09.2023.

    Peter Zuber becomes the new Managing Director of ERNI Switzerland

    ERNI is setting an agenda for growth and innovation with the appointment of Peter Zuber as Managing Director of the Swiss business unit. With his previous experience and expertise, he will further expand the positioning of ERNI Switzerland, as a leading consulting firm for software development and digital innovation.