Deploying Wireguard for private mesh networking
Author(s) | Helena Rasche |
OverviewQuestions:Objectives:
What is wireguard?
When is it useful?
Is it right for me?
Requirements:
Setup a wireguard mesh across a few nodes
- Galaxy Server administration
- Ansible: slides slides - tutorial hands-on
- Three or more VMs (they can be tiny, 1 CPU, <1GB RAM)
Time estimation: 60 minutesSupporting Materials:Last modification: Sep 28, 2022
In this tutorial we will briefly cover what Wireguard is and how you can leverage it for your needs. This will not make you an expert on Wireguard but will give you the tools you need in order to setup a local Wireguard network.
Agenda
What is Wireguard?
Wireguard is a VPN like OpenVPN or IPSec, but instead of the hub and spoke model of those where all traffic must go through a central node, Wireguard creates a mesh network where machines can all talk individually to each other. Wireguard also uses modern encryption only, ensuring your data stays safe.
Is it right for me?
If you have machines that need to talk to each other privately, and you don’t have a better way to do it like a local network team, then yes, it’s a great solution to private, secure, fast networking. It has excellent performance despite the encryption, and is built directly into the kernel.
By using wireguard, you can let services listen only on the wireguard interface, and thus only known and trusted machines can access those services.
Setting up the infrastructure
Hands-on: Configuration files
Create a
ansible.cfg
file (next to your playbook) to configure settings like the inventory file (and save ourselves some typing!), or the Python interpreter to use:--- /dev/null +++ b/ansible.cfg @@ -0,0 +1,6 @@ +[defaults] +interpreter_python = /usr/bin/python3 +inventory = hosts +retry_files_enabled = false +[ssh_connection] +pipelining = true
As mentioned in the “Ubuntu or Debian, CentOS or RHEL?” comment above, if you are using CentOS7 do not set
interpreter_python
inansible.cfg
.Pipelining will make Ansible run faster by significantly reducing the number of new SSH connections that must be opened.
Create the
hosts
inventory file if you have not done so yet, defining an[wireguard]
group with every host you want to be part of the cluster. For each machine, also set a variablewireguard_ip
with an address from192.168.0.0/24
Input: Bashcat hosts
Output: BashYour hostname is probably different:
--- /dev/null +++ b/hosts @@ -0,0 +1,5 @@ +[wireguard] +1-wg.galaxy.training wireguard_ip=192.168.0.1 +2-wg.galaxy.training wireguard_ip=192.168.0.2 +3-wg.galaxy.training wireguard_ip=192.168.0.3 +4-wg.galaxy.training wireguard_ip=192.168.0.4
Wireguard can use any of the private network blocks, here we use 192.168.0.0/16
for familiarity, Tailscale uses 10.0.0.0/8
.
Writing the playbook
First lets set up the playbook and install Wireguard, without configuring it.
Hands-on: Installing Wireguard
Create and open
wg.yml
which will be our playbook. Add the following:--- /dev/null +++ b/wg.yml @@ -0,0 +1,16 @@ +--- +- hosts: all + become: yes + vars: + wireguard_mask_bits: 24 + wireguard_port: 51871 + tasks: + - name: update packages + apt: + update_cache: yes + cache_valid_time: 3600 + + - name: Install wireguard + apt: + name: wireguard + state: present
Run the playbook:
Input: Bashansible-playbook wg.yml
Now we can start configuring it. Wireguard relies on each node having a private/public keypair which is used for encrypting communications between the nodes. By default this uses modern elliptic cryptography which is quite simple and provably secure, wireguard only has ~4k LOC compared to 400k+ LOC for most VPN solutions. Let’s generate those keys now:
Hands-on: Generating a keypair
Edit
wg.yml
and add--- a/wg.yml +++ b/wg.yml @@ -14,3 +14,8 @@ apt: name: wireguard state: present + + - name: Generate Wireguard keypair + shell: wg genkey | tee /etc/wireguard/privatekey | wg pubkey | tee /etc/wireguard/publickey + args: + creates: /etc/wireguard/privatekey
Run the playbook:
Input: Bashansible-playbook wg.yml
Go check out what the keys look like!
Ok, that’s got wireguard setup, but it still isn’t running. As of 2018 or so, systemd added built in support for wireguard and we’ll use that to setup the network devices, and the network itself.
Hands-on: Setting up the network
Edit
wg.yml
and add the following. We want to register the contents of these keys, as they’ll be used to configure our networks later.--- a/wg.yml +++ b/wg.yml @@ -19,3 +19,13 @@ shell: wg genkey | tee /etc/wireguard/privatekey | wg pubkey | tee /etc/wireguard/publickey args: creates: /etc/wireguard/privatekey + + - name: register private key + shell: cat /etc/wireguard/privatekey + register: wireguard_private_key + changed_when: false + + - name: register public key + shell: cat /etc/wireguard/publickey + register: wireguard_public_key + changed_when: false
Again editing
wg.yml
, we’ll setup the network device:--- a/wg.yml +++ b/wg.yml @@ -29,3 +29,28 @@ shell: cat /etc/wireguard/publickey register: wireguard_public_key changed_when: false + + - name: Setup wg0 device + copy: + content: | + [NetDev] + Name=wg0 + Kind=wireguard + Description=WireGuard tunnel wg0 + [WireGuard] + ListenPort={{ wireguard_port }} + PrivateKey={{ wireguard_private_key.stdout }} + {% for peer in groups['all'] %} + {% if peer != inventory_hostname %} + [WireGuardPeer] + PublicKey={{ hostvars[peer].wireguard_public_key.stdout }} + AllowedIPs={{ hostvars[peer].wireguard_ip }}/32 + Endpoint={{ hostvars[peer].inventory_hostname }}:{{ wireguard_port }} + PersistentKeepalive=25 + {% endif %} + {% endfor %} + dest: /etc/systemd/network/99-wg0.netdev + owner: root + group: systemd-network + mode: 0640 + notify: systemd network restart
Here we do a number of things:
- We configure a NetDev, a virtual network device. Systemd supports many types but we’ll use wireguard.
- Next we setup wireguard, specifying a
ListenPort
which is used for all wireguard communication, and specifies our PrivateKey which is used by the tunnel.- For every peer (all other instances than ourselves), we setup a
WireGuardPeer
with that peer’s public key, and which IPs are allowed to connect.Again editing
wg.yml
, we’ll setup the final bit, the network service.--- a/wg.yml +++ b/wg.yml @@ -54,3 +54,16 @@ group: systemd-network mode: 0640 notify: systemd network restart + + - name: Setup wg0 network + copy: + content: | + [Match] + Name=wg0 + [Network] + Address={{ wireguard_ip }}/{{ wireguard_mask_bits }} + dest: /etc/systemd/network/99-wg0.network + owner: root + group: systemd-network + mode: 0640 + notify: systemd network restart
Here we just setup the network, declare the interface name, and the address for it.
And last let’s restart the appropriate services.
--- a/wg.yml +++ b/wg.yml @@ -67,3 +67,10 @@ group: systemd-network mode: 0640 notify: systemd network restart + + handlers: + - name: systemd network restart + service: + name: systemd-networkd + state: restarted + enabled: yes
Run the playbook:
Input: Bashansible-playbook wg.yml
Go check out the network! Try pinging each of the wireguard IPs to see if you can reach each of the machines.
Key points
Wireguard is incredibly easy to deploy, and very secure.
Frequently Asked Questions
Have questions about this tutorial? Check out the FAQ page for the Galaxy Server administration topic to see if your question is listed there. If not, please ask your question on the GTN Gitter Channel or the Galaxy Help ForumFeedback
Did you use this material as an instructor? Feel free to give us feedback on how it went.
Did you use this material as a learner or student? Click the form below to leave feedback.
Citing this Tutorial
- , 2022 Deploying Wireguard for private mesh networking (Galaxy Training Materials). https://training.galaxyproject.org/training-material/topics/admin/tutorials/wireguard/tutorial.html Online; accessed TODAY
- Batut et al., 2018 Community-Driven Data Analysis Training for Biology Cell Systems 10.1016/j.cels.2018.05.012
Congratulations on successfully completing this tutorial!@misc{admin-wireguard, author = "Helena Rasche", title = "Deploying Wireguard for private mesh networking (Galaxy Training Materials)", year = "2022", month = "09", day = "28" url = "\url{https://training.galaxyproject.org/training-material/topics/admin/tutorials/wireguard/tutorial.html}", note = "[Online; accessed TODAY]" } @article{Batut_2018, doi = {10.1016/j.cels.2018.05.012}, url = {https://doi.org/10.1016%2Fj.cels.2018.05.012}, year = 2018, month = {jun}, publisher = {Elsevier {BV}}, volume = {6}, number = {6}, pages = {752--758.e1}, author = {B{\'{e}}r{\'{e}}nice Batut and Saskia Hiltemann and Andrea Bagnacani and Dannon Baker and Vivek Bhardwaj and Clemens Blank and Anthony Bretaudeau and Loraine Brillet-Gu{\'{e}}guen and Martin {\v{C}}ech and John Chilton and Dave Clements and Olivia Doppelt-Azeroual and Anika Erxleben and Mallory Ann Freeberg and Simon Gladman and Youri Hoogstrate and Hans-Rudolf Hotz and Torsten Houwaart and Pratik Jagtap and Delphine Larivi{\`{e}}re and Gildas Le Corguill{\'{e}} and Thomas Manke and Fabien Mareuil and Fidel Ram{\'{\i}}rez and Devon Ryan and Florian Christoph Sigloch and Nicola Soranzo and Joachim Wolff and Pavankumar Videm and Markus Wolfien and Aisanjiang Wubuli and Dilmurat Yusuf and James Taylor and Rolf Backofen and Anton Nekrutenko and Björn Grüning}, title = {Community-Driven Data Analysis Training for Biology}, journal = {Cell Systems} }