6 minute read Published: Author: Colan Schwartz
WireGuard , Ansible , Terraform , Cloud Architecture , IaaS , Automation , Security , Ubuntu , OpenStack , Cryptography

Why use a VPN?

Within cloud computing, there are various types of sites and services not meant for public consumption (e.g. analytics software, databases, log servers, etc.). For security reasons, it’s best to keep these accesssible only via the private network, which is behind the firewall.

To provide access to these resources, a virtual private network (VPN) should be used, with network access granted only to trusted individuals within the organization.

Why use WireGuard specifically?

Traditionally, OpenVPN, IPsec and other solutions were the go-to options within the open-source software space. However, these are often complex to set up and have relatively massive code bases making them difficult to maintain.

For example, OpenVPN requires that a certificate authority (CA) be set-up. This is a complex piece of software, which shouldn’t be necessary for running a VPN. WireGuard simply requires the exchange of public keys in order to set up a secure connection, much like SSH and PGP.

There’s been a lot of interest in WireGuard lately, notably because:

However, in the Why Not WireGuard article, some opposition was raised. Let’s tackle some of the points raised there.

It does not allow using a dynamic IP address on the server side of the tunnel

Fine, but we’re doing the opposite. The clients can have dynamic IP addresses, but the server never will. So it’s irrelevant for this use case.

It’s not easy to use yet

That’s precisely the purpose of this article: To introduce an easy way to set it up and maintain it with Ansible.

It lacks cipher agility and upgrading many clients is difficult

Lacking cipher agility is actually a good thing. A better approach is to use versioned protocols. And it’s actually no more difficult to upgrade WireGuard clients than anything else. Both of these non-issues are discussed very nicely in the article Against Cipher Agility in Cryptography Protocols.

Trouble integrating it into Linux

As it was recently added to the Linux kernel, this is no longer an issue.

It lacks performance

While performance can always be improved, this doesn’t appear to be a critical issue for the application. For most use cases, it’s perfectly usable.


None of the above “issues” are actually a problem here.

Why use Ansible for configuration?

Ansible allows for automated deployment of configuration, which removes the need for manually installing, configuring and maintaining applications. It provides tonnes of modules, including those for files, storage, system, networking and even cloud provisioning (although I would generally recommend Terraform for this purpose).

Its units of work are called “tasks” that are run sequentially (procedural) in “roles” and “playbooks” to perform operations such as installing server software, its configuration, and handling various other types of system administration. Ansible strives for simplicity, resulting in playbooks that are essentially self-documenting. It can safely be run multiple times (as it strives to be idempotent), running tasks only when necessary, leaving already-configured items as-is.

A new Ansible role

While there were several WireGuard roles available for installing and maintaining the application, they either:

  • didn’t cater to the cloud gateway VPN use case,
  • lacked documentation, and/or
  • intentionally omitted critical elements (e.g. packet forwarding to internal hosts) for implementation by the user.

As such, I’ve written a comprehensive one.

It’s packaged as a collection as this is the newer distribution format that doesn’t concern itself with the location of source control repositories. Traditionally, it was necessary for roles to be hosted on GitHub for them to be published on Galaxy, the site for sharing Ansible contributions. As I prefer GitLab for hosting code repositories, this seemed more natural. The project is therefore hosted on GitLab.com.

The collection contains the single WireGuard role, and can be installed with ansible-galaxy (Ansible 2.9+). For older versions of Ansible, simply clone the Git repository and create a symbolic link to roles/wireguard_cloud_gateway within it.

Documentation can be found in the role’s README.

Key features

Support for clients and servers

Some of the other roles I researched didn’t provide much support for configuring the client side of the VPN, meaning the devices which connect to the cloud gateway server to access private network resources.

My role, on the other hand, can be run in either client or server mode: the same role can be used for configuring both. Running it in server mode configures the server (on the gateway VM), and running it in client mode configures the client devices (who connect to the server to gain access to the private network).

Support for configured security groups

For cloud security akin to traditional firewalls, security groups are essential for protecting virtual-machine (VM) compute instances. While these can be configured manually, ideally such configuration would be infrastructure as code (IaC) implemented via a tool such as Terraform, stored in a version control system (VCS) such as Git.

In a typical VPN-server set-up, the incoming (“ingress”) rules for such a “VPN” security group would block access to all ports except the one upon which the VPN communicates. This configuration should be applied to the VM that will be running WireGuard. However, if this is the case, using Ansible to install it won’t work because Ansible uses SSH to connect to the VM, and the SSH port is blocked.

In order to allow for such a secure set-up, a security group ID (e.g. “public_ssh”) can be provided to the role as a variable, which will be used to temporarily allow SSH access. Once the installation is complete, this temporary access will be revoked.

Support for multiple networks

For those of us that rely on VPN technology, it’s often necessary to connect to multiple VPNs at the same time, or at least prevent network resource IDs from overlapping. For example, you want to avoid having two VMs on different networks from having the same IP address.

WireGuard supports this by allowing multiple interfaces. By default, wg0 is used as the first one, but wg1, wg2, etc. can all coexist. If each remote network can exist on a different subnet, there’s no conflict from the client perspective. For example:

  • wg0 can be used to access network A, with subnet
  • wg1 can be used to access network B, with subnet

To set this up in your Ansible playbook when calling the role, set the service_interface variable. By default, it’s wg0. Also, be sure to set the client_accessible_ips properly; this defines the subnet. For details, see the default variables file.


The role was originally written for specific systems, notably OpenStack networks and Ubuntu VMs. However, we’d like to see the role support as many systems as possible (e.g. the IaaS platforms Amazon Web Services (AWS), Microsoft’s Azure, Google Cloud Platform (GCP), Digital Ocean, etc. and non-Debian-based operating systems (OSes) such as CentOS, Red Hat, etc.).

If you work with these systems, we’re more than happy to accept your supporting code via merge requests. Otherwise, if you’re able to provide funding, we can add support for these systems on your behalf.

To get in touch with us for that, or for any other reason, please use our contact form. We provide consulting in several areas, such as:

  • Enterprise cloud architecture
  • Cloud computing infrastructures as a service (IaaS)
  • Infrastructure automation with Terraform
  • Automating full-stack configuration with Ansible
  • OpenStack, Amazon Web Services (AWS), Google Cloud Platform (GCP) & Microsoft Azure consulting
  • Virtual private networking (VPNs) with OpenVPN and WireGuard

The article Protecting your cloud networks with WireGuard VPN and Ansible first appeared on the Consensus Enterprises blog.

We've disabled blog comments to prevent spam, but if you have questions or comments about this post, get in touch!