From 4e5adac6911c3f925e68d83e7bfb1c402f044490 Mon Sep 17 00:00:00 2001 From: Robert Wimmer <2039811+githubixx@users.noreply.github.com> Date: Thu, 5 May 2022 00:03:25 +0200 Subject: [PATCH] Change restart handling / add very basic unit test (#156) * move register if config/private key handling out of wg subcommands block * allow user to specify WireGuard interface restart behavior * update README * numeric values in meta/main.yml should be strings * update Copyright * fix indentation in tasks/setup-debian.yml * update Copyright * update Copyright * truthy values should be lowercase * add namespace key again to meta/main.yml * add molecule/kvm/verify.yml with a very basic unit test --- .gitignore | 2 +- README.md | 87 ++++++++++++++++++++++++- defaults/main.yml | 37 ++++++++++- handlers/main.yml | 6 +- meta/main.yml | 24 +++---- molecule/kvm-single-server/molecule.yml | 2 +- molecule/kvm/converge.yml | 2 +- molecule/kvm/molecule.yml | 5 +- molecule/kvm/prepare.yml | 2 +- molecule/kvm/verify.yml | 33 ++++++++++ tasks/main.yml | 50 ++++++++++---- tasks/setup-almalinux-8.yml | 2 +- tasks/setup-archlinux.yml | 2 +- tasks/setup-debian-pve-host-variant.yml | 2 +- tasks/setup-debian-vanilla.yml | 2 +- tasks/setup-debian.yml | 6 +- tasks/setup-opensuse leap.yml | 3 +- tasks/setup-rocky-8.yml | 2 +- tasks/setup-ubuntu.yml | 2 +- templates/etc/wireguard/wg.conf.j2 | 2 +- 20 files changed, 227 insertions(+), 46 deletions(-) create mode 100644 molecule/kvm/verify.yml diff --git a/.gitignore b/.gitignore index f46d7ac..df7a7f7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -# Copyright (C) 2018-2020 Robert Wimmer +# Copyright (C) 2018-2022 Robert Wimmer # SPDX-License-Identifier: GPL-3.0-or-later molecule/kvm/.vagrant diff --git a/README.md b/README.md index b33cd97..d1080d8 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ In general WireGuard is a network tunnel (VPN) for IPv4 and IPv6 that uses UDP. Linux ----- -This role is mainly tested with Ubuntu 20.04 (Focal Fossa) and Archlinux. Ubuntu 18.04 (Bionic Beaver), Debian 10 (Buster), Debian 11 (Bullseye), Fedora 34 (or later), CentOS 7, AlmaLinux, Rocky Linux and openSUSE Leap 15.3 should also work and are tested via the provided "Molecule" tests (see further down below). It should also work with `Raspbian Buster` but for this one there is no test available. MacOS (see below) should also work partitially but is only best effort. +This role is mainly tested with Ubuntu 20.04 (Focal Fossa) and Archlinux. Ubuntu 18.04 (Bionic Beaver), Debian 10 (Buster), Debian 11 (Bullseye), Fedora 34 (or later), CentOS 7, AlmaLinux, Rocky Linux and openSUSE Leap 15.3 should also work and are tested via the provided [Molecule tests](https://github.com/githubixx/ansible-role-wireguard#testing) (see further down below). It should also work with `Raspbian Buster` but for this one there is no test available. MacOS (see below) should also work partitially but is only best effort. MacOS ----- @@ -78,6 +78,91 @@ wireguard_conf_mode: 0600 # The default state of the wireguard service wireguard_service_enabled: "yes" wireguard_service_state: "started" + +# By default "wg syncconf" is used to apply WireGuard interface settings if +# they've changed. Older WireGuard tools doesn't provide this option. In that +# case as a fallback the WireGuard interface will be restarted. This causes a +# short interruption of network connections. +# +# So even if "false" is the default, the role figures out if the "syncconf" +# option of the "wg" utility is available and if not falls back to "true" +# (which means interface will be restarted as this is the only possible option +# in this case). +# +# Possible options: +# - false (default) +# - true +# +# Both options have their pros and cons. The default "false" option (do not +# restart interface) +# - does not need to restart the WireGuard interface to apply changes +# - does not cause a short VPN connection interruption when changes are applied +# - might cause network routes are not properly reloaded +# +# Setting the option value to "true" will +# - restart the WireGuard interface as the name suggests in case of changes +# - cause a short VPN connection interruption when changes are applied +# - make sure that network routes are properly reloaded +# +# So it depends a little bit on your setup which option works best. If you +# don't have an overly complicated routing that changes very often or at all +# using "false" here is most properly good enough for you. E.g. if you just +# want to connect a few servers via VPN and it normally stays this way. +# +# If you have a more dynamic routing setup then setting this to "true" might be +# the safest way to go. Also if you want to avoid the possibility creating some +# hard to detect side effects this option should be considered. +wireguard_interface_restart: false + +# Normally the role automatically creates a private key the very first time +# if there isn't already a WireGuard configuration. But this option allows +# to provide your own WireGuard private key if really needed. As this is of +# course a very sensitive value you might consider a tool like Ansible Vault +# to store it encrypted. +# wireguard_private_key: +``` + +There are also a few Linux distribution specific settings: + +```yaml +####################################### +# Settings only relevant for Ubuntu +####################################### + +# Set to "false" if package cache should not be updated +wireguard_ubuntu_update_cache: "true" + +# Set package cache valid time +wireguard_ubuntu_cache_valid_time: "3600" + +####################################### +# Settings only relevant for CentOS 7 +####################################### + +# Set wireguard_centos7_installation_method to "kernel-plus" +# to use the kernel-plus kernel, which includes a built-in, +# signed WireGuard module. +# UTILIZING KERNEL-PLUS WILL PERFORM A SYSTEM REBOOT DURING SETUP!! +# +# The default of "standard" will use the standard kernel and +# the ELRepo module for WireGuard. +wireguard_centos7_installation_method: "standard" + +# The default seconds to wait for machine to reboot and respond +wireguard_centos7_kernel_plus_reboot_timeout: "600" + +######################################### +# Settings only relevant for RockyLinux 8 +######################################### + +# Set wireguard_rockylinux8_installation_method to "dkms" +# to build WireGuard module from source, with wireguard-dkms. +# This is required if you use a custom kernel and/or your arch +# is not x86_64. +# +# The default of "standard" will install the kernel module +# with kmod-wireguard from ELRepo. +wireguard_rockylinux8_installation_method: "standard" ``` The following variable is mandatory and needs to be configured for every host in `host_vars/` e.g.: diff --git a/defaults/main.yml b/defaults/main.yml index 7c31b84..826aff7 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -1,5 +1,5 @@ --- -# Copyright (C) 2018-2020 Robert Wimmer +# Copyright (C) 2018-2022 Robert Wimmer # SPDX-License-Identifier: GPL-3.0-or-later ####################################### @@ -28,6 +28,41 @@ wireguard_conf_mode: 0600 wireguard_service_enabled: "yes" wireguard_service_state: "started" +# By default "wg syncconf" is used to apply WireGuard interface settings if +# they've changed. Older WireGuard tools doesn't provide this option. In that +# case as a fallback the WireGuard interface will be restarted. This causes a +# short interruption of network connections. +# +# So even if "false" is the default, the role figures out if the "syncconf" +# option of the "wg" utility is available and if not falls back to "true" +# (which means interface will be restarted as this is the only possible option +# in this case). +# +# Possible options: +# - false (default) +# - true +# +# Both options have their pros and cons. The default "false" option (do not +# restart interface) +# - does not need to restart the WireGuard interface to apply changes +# - does not cause a short VPN connection interruption when changes are applied +# - might cause network routes are not properly reloaded +# +# Setting the option value to "true" will +# - restart the WireGuard interface as the name suggests in case of changes +# - cause a short VPN connection interruption when changes are applied +# - make sure that network routes are properly reloaded +# +# So it depends a little bit on your setup which option works best. If you +# don't have an overly complicated routing that changes very often or at all +# using "false" here is most properly good enough for you. E.g. if you just +# want to connect a few servers via VPN and it normally stays this way. +# +# If you have a more dynamic routing setup then setting this to "true" might be +# the safest way to go. Also if you want to avoid the possibility creating some +# hard to detect side effects this option should be considered. +wireguard_interface_restart: false + # This is sensitive: encrypt it with a tool like Ansible Vault. # If not set, a new one is generated on a blank configuration. # wireguard_private_key: diff --git a/handlers/main.yml b/handlers/main.yml index 4126c67..298d0e7 100644 --- a/handlers/main.yml +++ b/handlers/main.yml @@ -1,5 +1,5 @@ --- -# Copyright (C) 2018-2020 Robert Wimmer +# Copyright (C) 2018-2022 Robert Wimmer # SPDX-License-Identifier: GPL-3.0-or-later - name: restart wireguard @@ -10,7 +10,7 @@ - stopped - started when: - - not wg_syncconf + - wireguard__restart_interface - not ansible_os_family == 'Darwin' - wireguard_service_enabled == "yes" listen: "reconfigure wireguard" @@ -26,7 +26,7 @@ args: executable: "/bin/bash" when: - - wg_syncconf + - not wireguard__restart_interface - not ansible_os_family == 'Darwin' - wireguard_service_enabled == "yes" listen: "reconfigure wireguard" diff --git a/meta/main.yml b/meta/main.yml index 18b5565..373d597 100644 --- a/meta/main.yml +++ b/meta/main.yml @@ -1,34 +1,34 @@ -# Copyright (C) 2018-2020 Robert Wimmer +# Copyright (C) 2018-2022 Robert Wimmer # SPDX-License-Identifier: GPL-3.0-or-later galaxy_info: author: Robert Wimmer description: Installs Wireguard incl. systemd integration license: GPL-3.0-or-later - min_ansible_version: 2.9 - role_name: ansible_role_wireguard + min_ansible_version: "2.9" namespace: githubixx + role_name: ansible_role_wireguard platforms: - name: ArchLinux - name: Ubuntu versions: - - bionic - - focal + - "bionic" + - "focal" - name: Debian versions: - - buster - - bullseye + - "buster" + - "bullseye" - name: EL versions: - - 7 - - 8 + - "7" + - "8" - name: Fedora versions: - - 34 - - 35 + - "34" + - "35" - name: opensuse versions: - - 15.3 + - "15.3" galaxy_tags: - networking - security diff --git a/molecule/kvm-single-server/molecule.yml b/molecule/kvm-single-server/molecule.yml index 7ab53ff..4916d72 100644 --- a/molecule/kvm-single-server/molecule.yml +++ b/molecule/kvm-single-server/molecule.yml @@ -79,4 +79,4 @@ scenario: verifier: name: ansible - enabled: False + enabled: false diff --git a/molecule/kvm/converge.yml b/molecule/kvm/converge.yml index b05d755..0c9a877 100644 --- a/molecule/kvm/converge.yml +++ b/molecule/kvm/converge.yml @@ -1,5 +1,5 @@ --- -# Copyright (C) 2020 Robert Wimmer +# Copyright (C) 2020-2022 Robert Wimmer # SPDX-License-Identifier: GPL-3.0-or-later - hosts: all diff --git a/molecule/kvm/molecule.yml b/molecule/kvm/molecule.yml index bb62bd1..3cd47c2 100644 --- a/molecule/kvm/molecule.yml +++ b/molecule/kvm/molecule.yml @@ -1,5 +1,5 @@ --- -# Copyright (C) 2020 Robert Wimmer +# Copyright (C) 2020-2022 Robert Wimmer # Copyright (C) 2020 Pierre Ozoux # SPDX-License-Identifier: GPL-3.0-or-later @@ -179,11 +179,13 @@ provisioner: wireguard_port: 51820 wireguard_persistent_keepalive: "30" wireguard_endpoint: "192.168.10.40" + wireguard_interface_restart: true test-wg-centos7: wireguard_address: "10.10.10.50/24" wireguard_port: 51820 wireguard_persistent_keepalive: "30" wireguard_endpoint: "192.168.10.50" + wireguard_interface_restart: true test-wg-arch: wireguard_address: "10.10.10.60/24" wireguard_port: 51820 @@ -237,4 +239,3 @@ scenario: verifier: name: ansible - enabled: False diff --git a/molecule/kvm/prepare.yml b/molecule/kvm/prepare.yml index 33bd649..76e3483 100644 --- a/molecule/kvm/prepare.yml +++ b/molecule/kvm/prepare.yml @@ -1,5 +1,5 @@ --- -# Copyright (C) 2021 Robert Wimmer +# Copyright (C) 2021-2022 Robert Wimmer # SPDX-License-Identifier: GPL-3.0-or-later - hosts: opensuse diff --git a/molecule/kvm/verify.yml b/molecule/kvm/verify.yml new file mode 100644 index 0000000..4551ce3 --- /dev/null +++ b/molecule/kvm/verify.yml @@ -0,0 +1,33 @@ +--- +# Copyright (C) 2022 Robert Wimmer +# SPDX-License-Identifier: GPL-3.0-or-later + +- name: Verify setup + hosts: all + vars: + hosts_count: "{{ groups['vpn'] | length }}" + tasks: + - name: Count WireGuard interfaces + ansible.builtin.shell: | + set -o errexit + set -o pipefail + set -o nounset + wg | grep "peer: " | wc -l + exit 0 + args: + executable: "/bin/bash" + register: wireguard__interfaces_count + changed_when: false + + - name: Print WireGuard interface count + ansible.builtin.debug: + var: wireguard__interfaces_count.stdout + + - name: Print hosts count in vpn group + ansible.builtin.debug: + var: hosts_count + + - name: There should be as much WireGuard interfaces as hosts in vpn group minus one + ansible.builtin.assert: + that: + - "hosts_count|int -1 == wireguard__interfaces_count.stdout|int" diff --git a/tasks/main.yml b/tasks/main.yml index 42aa3ee..96282ee 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -1,5 +1,5 @@ --- -# Copyright (C) 2018-2020 Robert Wimmer +# Copyright (C) 2018-2022 Robert Wimmer # SPDX-License-Identifier: GPL-3.0-or-later - name: Gather instance facts @@ -33,14 +33,18 @@ - wg-install when: not ansible_os_family == 'Darwin' -- name: Generate keys | Check wg syncconf subcommand status +- name: Set default for WireGuard interface restart behavior + ansible.builtin.set_fact: + wireguard__restart_interface: >- + {%- if wireguard_interface_restart -%} + true + {%- else -%} + false + {%- endif %} + +- name: Make sure wg syncconf option is available block: - - name: Register if config/private key already exists on target host - ansible.builtin.stat: - path: "{{ wireguard_remote_directory }}/{{ wireguard_interface }}.conf" - register: wireguard__register_config_file - - - name: Get wg subcommands + - name: Get available wg subcommands ansible.builtin.command: "wg --help" register: wireguard__register_subcommands changed_when: false @@ -48,11 +52,35 @@ - name: Check if wg syncconf subcommand is available ansible.builtin.set_fact: - wg_syncconf: "{{ 'syncconf:' in wireguard__register_subcommands.stdout }}" + wireguard__syncconf_avail: "{{ 'syncconf:' in wireguard__register_subcommands.stdout }}" - - name: Show syncconf subcommand status + - name: wg syncconf subcommand available ansible.builtin.debug: - var: wg_syncconf + var: wireguard__syncconf_avail + + - name: Fall back to interface restart if wg syncconf is not available + ansible.builtin.set_fact: + wireguard__restart_interface: true + when: + - not wireguard__syncconf_avail + when: + - not wireguard_interface_restart + tags: + - wg-config + +- name: Final decision on WireGuard interface restart method + ansible.builtin.debug: + msg: >- + {%- if wireguard__restart_interface -%} + 'restart' + {%- else -%} + 'syncconf' + {%- endif %} + +- name: Register if config/private key already exists on target host + ansible.builtin.stat: + path: "{{ wireguard_remote_directory }}/{{ wireguard_interface }}.conf" + register: wireguard__register_config_file tags: - wg-generate-keys - wg-config diff --git a/tasks/setup-almalinux-8.yml b/tasks/setup-almalinux-8.yml index 6181e59..42a3a45 100644 --- a/tasks/setup-almalinux-8.yml +++ b/tasks/setup-almalinux-8.yml @@ -1,5 +1,5 @@ --- -# Copyright (C) 2021 Robert Wimmer +# Copyright (C) 2021-2022 Robert Wimmer # SPDX-License-Identifier: GPL-3.0-or-later - name: (AlmaLinux 8) Install EPEL & ELRepo repository diff --git a/tasks/setup-archlinux.yml b/tasks/setup-archlinux.yml index c1da252..354f930 100644 --- a/tasks/setup-archlinux.yml +++ b/tasks/setup-archlinux.yml @@ -1,5 +1,5 @@ --- -# Copyright (C) 2018-2021 Robert Wimmer +# Copyright (C) 2018-2022 Robert Wimmer # SPDX-License-Identifier: GPL-3.0-or-later - name: (Archlinux) Install wireguard-tools package diff --git a/tasks/setup-debian-pve-host-variant.yml b/tasks/setup-debian-pve-host-variant.yml index 8fbdcd5..a9638de 100644 --- a/tasks/setup-debian-pve-host-variant.yml +++ b/tasks/setup-debian-pve-host-variant.yml @@ -1,5 +1,5 @@ --- -# Copyright (C) 2018-2020 Robert Wimmer +# Copyright (C) 2018-2022 Robert Wimmer # Copyright (C) 2019-2020 Ties de Kock # Copyright (C) 2021 Steve Fan # SPDX-License-Identifier: GPL-3.0-or-later diff --git a/tasks/setup-debian-vanilla.yml b/tasks/setup-debian-vanilla.yml index 098e76b..68c53ca 100644 --- a/tasks/setup-debian-vanilla.yml +++ b/tasks/setup-debian-vanilla.yml @@ -1,5 +1,5 @@ --- -# Copyright (C) 2018-2021 Robert Wimmer +# Copyright (C) 2018-2022 Robert Wimmer # Copyright (C) 2019-2020 Ties de Kock # SPDX-License-Identifier: GPL-3.0-or-later diff --git a/tasks/setup-debian.yml b/tasks/setup-debian.yml index 3fe7ae2..9eff33b 100644 --- a/tasks/setup-debian.yml +++ b/tasks/setup-debian.yml @@ -10,9 +10,9 @@ tags: - wg-install when: - - ansible_lsb.id is defined - - ansible_lsb.id == "Raspbian" - - ansible_lsb.major_release is version('11', '<') + - ansible_lsb.id is defined + - ansible_lsb.id == "Raspbian" + - ansible_lsb.major_release is version('11', '<') register: wireguard__register_raspbian_setup - name: Setup for Proxmox VE variants diff --git a/tasks/setup-opensuse leap.yml b/tasks/setup-opensuse leap.yml index 6fb98ca..4198f9b 100644 --- a/tasks/setup-opensuse leap.yml +++ b/tasks/setup-opensuse leap.yml @@ -1,8 +1,7 @@ --- -# Copyright (C) 2020 Robert Wimmer +# Copyright (C) 2020-2022 Robert Wimmer # SPDX-License-Identifier: GPL-3.0-or-later - - name: (openSUSE Leap) Install WireGuard packages community.general.zypper: name: diff --git a/tasks/setup-rocky-8.yml b/tasks/setup-rocky-8.yml index aa617c3..c8650b7 100644 --- a/tasks/setup-rocky-8.yml +++ b/tasks/setup-rocky-8.yml @@ -1,5 +1,5 @@ --- -# Copyright (C) 2021 Robert Wimmer +# Copyright (C) 2021-2022 Robert Wimmer # SPDX-License-Identifier: GPL-3.0-or-later - name: (Rocky Linux 8) Tasks for standard kernel diff --git a/tasks/setup-ubuntu.yml b/tasks/setup-ubuntu.yml index 1337a1a..9f957d0 100644 --- a/tasks/setup-ubuntu.yml +++ b/tasks/setup-ubuntu.yml @@ -1,5 +1,5 @@ --- -# Copyright (C) 2018-2020 Robert Wimmer +# Copyright (C) 2018-2022 Robert Wimmer # SPDX-License-Identifier: GPL-3.0-or-later - name: (Ubuntu) Update APT package cache diff --git a/templates/etc/wireguard/wg.conf.j2 b/templates/etc/wireguard/wg.conf.j2 index f8929dd..5fd4b3f 100644 --- a/templates/etc/wireguard/wg.conf.j2 +++ b/templates/etc/wireguard/wg.conf.j2 @@ -1,5 +1,5 @@ #jinja2: lstrip_blocks:"True",trim_blocks:"True" -{# Copyright (C) 2018-2020 Robert Wimmer +{# Copyright (C) 2018-2022 Robert Wimmer # SPDX-License-Identifier: GPL-3.0-or-later #} # {{ ansible_managed }}