diff --git a/CHANGELOG.md b/CHANGELOG.md index e2c3942..aec6e1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,19 @@ Changelog --------- +**8.0.0** + +- add `Debian 11 (Bullseye)` support +- add 'Fedora 34` support +- remove `Fedora 32` support (EOL was in May 2021) +- fix various issues reported by `ansible-lint` +- Archlinux: As `linux-lts` is using kernel `5.10` now there is no need to install `wireguard-lts` + WireGuard DKMS packages any longer (and this packages are gone anyway) + **7.12.0** - Refactor `wg-install` tag handling. For more details see [Fix tag "wg-install" & Add no_log](https://github.com/githubixx/ansible-role-wireguard/pull/110) and [Tag wg-install is not applied properly](Tag wg-install is not applied properly) (contribution by @moonrail) diff --git a/README.md b/README.md index 2d56293..744dcf3 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ @@ -7,31 +7,28 @@ SPDX-License-Identifier: GPL-3.0-or-later ansible-role-wireguard ====================== -This Ansible role is used in my blog series [Kubernetes the not so hard way with Ansible](https://www.tauceti.blog/post/kubernetes-the-not-so-hard-way-with-ansible-wireguard/) but can be used standalone of course. The latest release is [available via Ansible Galaxy](https://galaxy.ansible.com/githubixx/ansible_role_wireguard). I use WireGuard and this Ansible role to setup a fully meshed VPN between all nodes of my little Kubernetes cluster. This VPN also includes two clients so that I can communicate securely with the Kubernetes API server. Also my Postfix mailserver running as K8s DaemonSet forwards mails to my internal Postfix through WireGuard VPN. - -I used [PeerVPN](https://peervpn.net/) before but that wasn't updated for a while. As I moved my cloud hosts from Scaleway to Hetzner cloud it was a good time to switch the VPN solution ;-) In general PeerVPN still works perfectly fine esp. if you need a easy to setup fully meshed network (where every node is able to talk to all other nodes and even if node `A` should be able to talk to Node `C` via node `B` ;-) ). But PeerVPN needs also lot of CPU resources and throughput could be better. That's solved with [WireGuard](https://www.wireguard.io/). +This Ansible role is used in my blog series [Kubernetes the not so hard way with Ansible](https://www.tauceti.blog/post/kubernetes-the-not-so-hard-way-with-ansible-wireguard/) but can be used standalone of course. The latest release is [available via Ansible Galaxy](https://galaxy.ansible.com/githubixx/ansible_role_wireguard). I use WireGuard and this Ansible role to setup a fully meshed VPN between all nodes of my little Kubernetes cluster. In general WireGuard is a network tunnel (VPN) for IPv4 and IPv6 that uses UDP. If you need more information about [WireGuard](https://www.wireguard.io/) you can find a good introduction here: [Installing WireGuard, the Modern VPN](https://research.kudelskisecurity.com/2017/06/07/installing-wireguard-the-modern-vpn/). -This role is tested with Ubuntu 18.04 (Bionic Beaver), Ubuntu 20.04 (Focal Fossa) and Archlinux. Ubuntu 16.04 (Xenial Xerus), Debian 10 (Buster), Fedora 32 (or later), CentOS 7/8 and partially MacOS (see below) might also work but only best effort (code for this operating systems was submitted by other contributors). +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 33 (or later) and CentOS 7/8 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. ### Running the VPN on MacOS While this playbook configures, enables and starts a `systemd` service on Linux in a such a way that no additional action is needed, on MacOS it installs the required packages and it just generates the correct `wg0.conf` file that is then placed in the specified `wireguard_remote_directory` (`/opt/local/etc/wireguard` by default). In order to run the VPN, then, you need to: -``` +```bash sudo wg-quick up wg0 ``` and to deactivate it -``` +```bash sudo wg-quick down wg0 ``` or you can install the [official app](https://apps.apple.com/it/app/wireguard/id1451685025?l=en&mt=12) and import the `wg0.conf` file. - Versions -------- @@ -40,7 +37,9 @@ I tag every release and try to stay with [semantic versioning](http://semver.org Requirements ------------ -By default port `51820` (protocol UDP) should be accessible from the outside. But you can adjust the port by changing the variable `wireguard_port`. Also IP forwarding needs to be enabled e.g. via `echo 1 > /proc/sys/net/ipv4/ip_forward `. I decided not to implement this task in this Ansible role. IMHO that should be handled elsewhere. You can use my [ansible-role-harden-linux](https://github.com/githubixx/ansible-role-harden-linux) e.g. Besides changing sysctl entries (which you need to enable IP forwarding) it also manages firewall settings among other things. Nevertheless the `PreUp`, `PreDown`, `PostUp` and `PostDown` hooks may be a good place to do some network related stuff before a WireGuard interface comes up or goes down. +By default port `51820` (protocol UDP) should be accessible from the outside. But you can adjust the port by changing the variable `wireguard_port`. Also IP forwarding needs to be enabled e.g. via `echo 1 > /proc/sys/net/ipv4/ip_forward`. I decided not to implement this task in this Ansible role. IMHO that should be handled elsewhere. +You can use my [ansible-role-harden-linux](https://github.com/githubixx/ansible-role-harden-linux) e.g. Besides changing sysctl entries (which you need to enable IP forwarding) it also manages firewall settings among other things. +Nevertheless the `PreUp`, `PreDown`, `PostUp` and `PostDown` hooks may be a good place to do some network related stuff before a WireGuard interface comes up or goes down. Changelog --------- @@ -164,7 +163,7 @@ Here is a litte example for what I use the playbook: I use WireGuard to setup a First, here is a part of my Ansible `hosts` file: -``` +```ini [vpn] controller0[1:3].i.domain.tld worker0[1:2].i.domain.tld @@ -178,11 +177,12 @@ controller0[1:3].i.domain.tld worker0[1:2].i.domain.tld ``` -As you can see I've three groups here: `vpn` (all hosts on that will get WireGuard installed), `k8s_controller` (the Kubernetes controller nodes) and `k8s_worker` (the Kubernetes worker nodes). The `i` in the domainname is for `internal`. All the `i.domain.tld` DNS entries have a `A` record that points to the WireGuard IP that we define shortly for every host e.g.: ` controller01.i.domain.tld. IN A 10.8.0.101`. The reason for that is that all Kubernetes components only binds and listen on the WireGuard interface in my setup. And since I need this internal IPs for all my Kubernetes components I specify the internal DNS entries in my Ansible `hosts` file. That way I can use the Ansible inventory hostnames and variables very easy in the playbooks and templates. +As you can see I've three groups here: `vpn` (all hosts on that will get WireGuard installed), `k8s_controller` (the Kubernetes controller nodes) and `k8s_worker` (the Kubernetes worker nodes). The `i` in the domainname is for `internal`. All the `i.domain.tld` DNS entries have a `A` record that points to the WireGuard IP that we define shortly for every host e.g.: `controller01.i.domain.tld. IN A 10.8.0.101`. The reason for that is that all Kubernetes components only binds and listen on the WireGuard interface in my setup. And since I need this internal IPs for all my Kubernetes components I specify the internal DNS entries in my Ansible `hosts` file. That way I can use the Ansible inventory hostnames and variables very easy in the playbooks and templates. For the Kubernetes controller nodes I've defined the following host variables: Ansible host file: `host_vars/controller01.i.domain.tld` + ```yaml --- wireguard_address: "10.8.0.101/24" @@ -192,6 +192,7 @@ ansible_python_interpreter: /usr/bin/python3 ``` Ansible host file: `host_vars/controller02.i.domain.tld`: + ```yaml --- wireguard_address: "10.8.0.102/24" @@ -214,6 +215,7 @@ I've specified `ansible_python_interpreter` here for every node as the controlle For the Kubernetes worker I've defined the following variables: Ansible host file: `host_vars/worker01.i.domain.tld` + ```yaml --- wireguard_address: "10.8.0.111/24" @@ -224,6 +226,7 @@ ansible_python_interpreter: /usr/bin/python3 ``` Ansible host file: `host_vars/worker02.i.domain.tld`: + ```yaml --- wireguard_address: "10.8.0.112/24" @@ -374,6 +377,25 @@ Sample playbooks for example above: - githubixx.ansible_role_wireguard ``` +Testing +------- + +This role has a small test setup that is created using [Molecule](https://github.com/ansible-community/molecule), libvirt (vagrant-libvirt) and QEMU/KVM. Please see my blog post [Testing Ansible roles with Molecule, libvirt (vagrant-libvirt) and QEMU/KVM](https://www.tauceti.blog/posts/testing-ansible-roles-with-molecule-libvirt-vagrant-qemu-kvm/) how to setup. The test configuration is [here](https://github.com/githubixx/ansible-role-wireguard/tree/master/molecule/kvm). + +Afterwards molecule can be executed: + +```bash +molecule converge -s kvm +``` + +This will setup quite a few virtual machines (VM) with different supported Linux operating systems. + +To clean up run + +```bash +molecule destroy -s kvm +``` + License ------- diff --git a/meta/main.yml b/meta/main.yml index d9f59f5..e4ed23d 100644 --- a/meta/main.yml +++ b/meta/main.yml @@ -6,26 +6,29 @@ galaxy_info: description: Installs Wireguard incl. systemd integration license: GPL-3.0-or-later min_ansible_version: 2.5 + role_name: ansible_role_wireguard + namespace: githubixx platforms: - - name: ArchLinux - - name: Ubuntu - versions: - - bionic - - focal - - name: Debian - versions: - - buster - - name: EL - versions: - - 7 - - 8 - - name: Fedora - versions: - - 32 - - 33 - - name: opensuse - versions: - - 15.2 + - name: ArchLinux + - name: Ubuntu + versions: + - bionic + - focal + - name: Debian + versions: + - buster + - bullseye + - name: EL + versions: + - 7 + - 8 + - name: Fedora + versions: + - 33 + - 34 + - name: opensuse + versions: + - 15.2 galaxy_tags: - networking - security diff --git a/molecule/kvm/molecule.yml b/molecule/kvm/molecule.yml index 3829cd4..0e85d0d 100644 --- a/molecule/kvm/molecule.yml +++ b/molecule/kvm/molecule.yml @@ -52,8 +52,8 @@ platforms: ip: 192.168.10.40 groups: - vpn - - name: test-wg-fedora32 - box: generic/fedora32 + - name: test-wg-fedora34 + box: generic/fedora34 interfaces: - auto_config: true network_name: private_network @@ -106,6 +106,15 @@ platforms: ip: 192.168.10.100 groups: - vpn + - name: test-wg-debian11 + box: generic/debian11 + interfaces: + - auto_config: true + network_name: private_network + type: static + ip: 192.168.10.110 + groups: + - vpn provisioner: name: ansible @@ -138,7 +147,7 @@ provisioner: wireguard_port: 51820 wireguard_persistent_keepalive: "30" wireguard_endpoint: "192.168.10.40" - test-wg-fedora32: + test-wg-fedora34: wireguard_address: "10.10.10.50/24" wireguard_port: 51820 wireguard_persistent_keepalive: "30" @@ -169,6 +178,12 @@ provisioner: wireguard_port: 51820 wireguard_persistent_keepalive: "30" wireguard_endpoint: "192.168.10.100" + test-wg-debian11: + wireguard_address: "10.10.10.110/24" + wireguard_port: 51820 + wireguard_persistent_keepalive: "30" + wireguard_endpoint: "192.168.10.110" + ansible_python_interpreter: "/usr/bin/python3" scenario: name: kvm diff --git a/tasks/main.yml b/tasks/main.yml index c79139e..e66b308 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -5,7 +5,6 @@ - name: Gather instance facts setup: -# Installing WireGuard [[[1 - include_tasks: file: "{{ item }}" apply: @@ -25,7 +24,7 @@ name: wireguard state: present register: wireguard__register_module_enabled - until: wireguard__register_module_enabled is succeeded + until: wireguard__register_module_enabled is succeeded retries: 10 delay: 10 failed_when: wireguard__register_module_enabled is failure @@ -33,64 +32,66 @@ - wg-install when: not ansible_os_family == 'Darwin' -- block: - # Key handling [[[1 - - name: Register if config/private key already exists on target host - stat: - path: "{{ wireguard_remote_directory }}/{{ wireguard_interface }}.conf" - register: wireguard__register_config_file - - - name: Get wg subcommands - command: "wg --help" - register: wireguard__register_subcommands - changed_when: false - check_mode: no - - - name: Check if wg syncconf subcommand is available - set_fact: - wg_syncconf: "{{ 'syncconf:' in wireguard__register_subcommands.stdout }}" +- name: Generate keys | Check wg syncconf subcommand status + block: + - name: Register if config/private key already exists on target host + stat: + path: "{{ wireguard_remote_directory }}/{{ wireguard_interface }}.conf" + register: wireguard__register_config_file + + - name: Get wg subcommands + command: "wg --help" + register: wireguard__register_subcommands + changed_when: false + check_mode: false + + - name: Check if wg syncconf subcommand is available + set_fact: + wg_syncconf: "{{ 'syncconf:' in wireguard__register_subcommands.stdout }}" + + - name: Show syncconf subcommand status + debug: + var: wg_syncconf tags: - wg-generate-keys - wg-config -- name: Show syncconf subcommand status - debug: - var: wg_syncconf - -- block: - - name: Generate WireGuard private key - command: "wg genkey" - register: wireguard__register_private_key - changed_when: false - no_log: '{{ ansible_verbosity < 3 }}' - tags: - - wg-generate-keys - - - name: Set private key fact - set_fact: - wireguard_private_key: "{{ wireguard__register_private_key.stdout }}" - no_log: '{{ ansible_verbosity < 3 }}' - tags: - - wg-generate-keys +- name: WireGuard private key handling for new keys + block: + - name: Generate WireGuard private key + command: "wg genkey" + register: wireguard__register_private_key + changed_when: false + no_log: '{{ ansible_verbosity < 3 }}' + tags: + - wg-generate-keys + + - name: Set private key fact + set_fact: + wireguard_private_key: "{{ wireguard__register_private_key.stdout }}" + no_log: '{{ ansible_verbosity < 3 }}' + tags: + - wg-generate-keys when: - not wireguard__register_config_file.stat.exists - wireguard_private_key is not defined -- block: - - name: Read WireGuard config file - slurp: - src: "{{ wireguard_remote_directory }}/{{ wireguard_interface }}.conf" - register: wireguard__register_config - no_log: '{{ ansible_verbosity < 3 }}' - tags: - - wg-config - - - name: Set private key fact - set_fact: - wireguard_private_key: "{{ wireguard__register_config['content'] | b64decode | regex_findall('PrivateKey = (.*)') | first }}" - no_log: '{{ ansible_verbosity < 3 }}' - tags: - - wg-config +- name: WireGuard private key handling for existing keys + block: + - name: Read WireGuard config file + slurp: + src: "{{ wireguard_remote_directory }}/{{ wireguard_interface }}.conf" + register: wireguard__register_config + no_log: '{{ ansible_verbosity < 3 }}' + tags: + - wg-config + + - name: Set private key fact + set_fact: + wireguard_private_key: "{{ wireguard__register_config['content'] | b64decode | regex_findall('PrivateKey = (.*)') | first }}" + no_log: '{{ ansible_verbosity < 3 }}' + tags: + - wg-config when: - wireguard__register_config_file.stat.exists - wireguard_private_key is not defined @@ -101,7 +102,7 @@ stdin: "{{ wireguard_private_key }}" register: wireguard__register_public_key changed_when: false - check_mode: no + check_mode: false no_log: '{{ ansible_verbosity < 3 }}' tags: - wg-config @@ -112,7 +113,6 @@ tags: - wg-config -# Configuration [[[1 - name: Create WireGuard configuration directory file: dest: "{{ wireguard_remote_directory }}" @@ -141,7 +141,6 @@ tags: - wg-config -# Service [[[1 - name: Start and enable WireGuard service service: name: "wg-quick@{{ wireguard_interface }}" diff --git a/tasks/setup-archlinux.yml b/tasks/setup-archlinux.yml index 2881ca2..a95c730 100644 --- a/tasks/setup-archlinux.yml +++ b/tasks/setup-archlinux.yml @@ -1,28 +1,7 @@ --- -# Copyright (C) 2018-2020 Robert Wimmer +# Copyright (C) 2018-2021 Robert Wimmer # SPDX-License-Identifier: GPL-3.0-or-later -- name: (Archlinux) Install wireguard-lts package - pacman: - name: "{{ item.name }}" - state: "{{ item.state }}" - with_items: - - { name: wireguard-dkms, state: absent } - - { name: wireguard-lts, state: present } - become: yes - when: - - ansible_kernel is match(".*-lts$") - - ansible_kernel is version('5.6', '<') - -- name: (Archlinux) Install wireguard-dkms package - pacman: - name: wireguard-dkms - state: present - become: yes - when: - - not ansible_kernel is match(".*-lts$") - - ansible_kernel is version('5.6', '<') - - name: (Archlinux) Install wireguard-tools package pacman: name: wireguard-tools diff --git a/tasks/setup-centos-7.yml b/tasks/setup-centos-7.yml index 81e32cd..85bc258 100644 --- a/tasks/setup-centos-7.yml +++ b/tasks/setup-centos-7.yml @@ -7,12 +7,12 @@ name: - epel-release - https://www.elrepo.org/elrepo-release-7.el7.elrepo.noarch.rpm - update_cache: yes + update_cache: true - name: (CentOS 7) Install yum-plugin-elrepo yum: name: yum-plugin-elrepo - update_cache: yes + update_cache: true - name: (CentOS 7) Ensure WireGuard DKMS package is removed yum: diff --git a/tasks/setup-centos-8.yml b/tasks/setup-centos-8.yml index 69810d0..93f0768 100644 --- a/tasks/setup-centos-8.yml +++ b/tasks/setup-centos-8.yml @@ -5,9 +5,9 @@ - name: (CentOS 8) Install EPEL & ELRepo repository yum: name: - - epel-release - - elrepo-release - update_cache: yes + - epel-release + - elrepo-release + update_cache: true - name: (CentOS 8) Ensure WireGuard DKMS package is removed yum: diff --git a/tasks/setup-debian-pve-variant.yml b/tasks/setup-debian-pve-variant.yml index 408f6bd..05aca42 100644 --- a/tasks/setup-debian-pve-variant.yml +++ b/tasks/setup-debian-pve-variant.yml @@ -8,7 +8,7 @@ apt_repository: repo: "deb http://deb.debian.org/debian buster-backports main" state: "{{ 'present' if (ansible_distribution_version | int <= 10) else 'absent' }}" - update_cache: yes + update_cache: true - name: (Proxmox) Install kernel headers for the currently running kernel to compile WireGuard with DKMS apt: diff --git a/tasks/setup-debian-raspbian.yml b/tasks/setup-debian-raspbian.yml index 8930f61..b303820 100644 --- a/tasks/setup-debian-raspbian.yml +++ b/tasks/setup-debian-raspbian.yml @@ -21,12 +21,12 @@ apt_repository: repo: "deb http://deb.debian.org/debian buster-backports main" state: present - update_cache: yes + update_cache: true - name: (Raspbian) Install latest kernel apt: name: - - "raspberrypi-kernel" + - "raspberrypi-kernel" state: latest register: wireguard__register_kernel_update @@ -53,7 +53,7 @@ command: /lib/molly-guard/shutdown -r now async: 1 poll: 0 - ignore_unreachable: yes + ignore_unreachable: true when: - ansible_version.full is version('2.8.0', '<') - wireguard__register_kernel_update is changed @@ -69,7 +69,7 @@ - name: (Raspbian) Install latest kernel headers to compile Wireguard with DKMS apt: name: - - "raspberrypi-kernel-headers" + - "raspberrypi-kernel-headers" state: latest - name: (Raspbian) Install WireGuard packages diff --git a/tasks/setup-debian-vanilla.yml b/tasks/setup-debian-vanilla.yml index 2142023..56200c1 100644 --- a/tasks/setup-debian-vanilla.yml +++ b/tasks/setup-debian-vanilla.yml @@ -1,32 +1,37 @@ --- -# Copyright (C) 2018-2020 Robert Wimmer +# Copyright (C) 2018-2021 Robert Wimmer # Copyright (C) 2019-2020 Ties de Kock # SPDX-License-Identifier: GPL-3.0-or-later -- name: (Debian) Add WireGuard repository on buster - apt_repository: - repo: "deb http://deb.debian.org/debian buster-backports main" - state: "{{ 'present' if (ansible_distribution_version | int <= 10) else 'absent' }}" - update_cache: yes +- name: (Debian) Tasks for Debian version <= 10 + block: + - name: (Debian) Add WireGuard repository on buster + apt_repository: + repo: "deb http://deb.debian.org/debian buster-backports main" + state: present + update_cache: true -- name: (Debian) Install kernel headers for the currently running kernel to compile Wireguard with DKMS - apt: - name: - - "linux-headers-{{ ansible_kernel }}" - state: present + - name: (Debian) Install kernel headers for the currently running kernel to compile Wireguard with DKMS + apt: + name: + - "linux-headers-{{ ansible_kernel }}" + state: present -- name: (Debian) Get architecture - command: "dpkg --print-architecture" - register: wireguard__fact_dpkg_arch - changed_when: false - check_mode: no + - name: (Debian) Get architecture + command: "dpkg --print-architecture" + register: wireguard__fact_dpkg_arch + changed_when: false + check_mode: false -- name: (Debian) Install kernel headers metapackage to ensure headers will be installed - apt: - name: - - "linux-headers-{{ wireguard__fact_dpkg_arch.stdout }}" - state: present - when: ('-cloud-' not in ansible_kernel) + - name: (Debian) Install kernel headers metapackage to ensure headers will be installed + apt: + name: + - "linux-headers-{{ wireguard__fact_dpkg_arch.stdout }}" + state: present + when: + - ('-cloud-' not in ansible_kernel) + when: + - ansible_lsb.major_release is version('11', '<') - name: (Debian) Install WireGuard packages apt: diff --git a/tasks/setup-fedora-32.yml b/tasks/setup-fedora-32.yml deleted file mode 100644 index a206898..0000000 --- a/tasks/setup-fedora-32.yml +++ /dev/null @@ -1,18 +0,0 @@ ---- -# Copyright (C) 2020 Ties de Kock -# SPDX-License-Identifier: GPL-3.0-or-later - -- name: (Fedora) Add WireGuard COPR - yum_repository: - name: "jdoss-wireguard" - description: "Copr repo for WireGuard owned by jdoss" - baseurl: "https://copr-be.cloud.fedoraproject.org/results/jdoss/wireguard/fedora-$releasever-$basearch/" - gpgkey: "https://copr-be.cloud.fedoraproject.org/results/jdoss/wireguard/pubkey.gpg" - gpgcheck: yes - -- name: (Fedora) Install WireGuard packages - yum: - name: - - "wireguard-dkms" - - "wireguard-tools" - state: present diff --git a/tasks/setup-macosx.yml b/tasks/setup-macosx.yml index 3f45e53..ee77ab0 100644 --- a/tasks/setup-macosx.yml +++ b/tasks/setup-macosx.yml @@ -6,7 +6,7 @@ package: name: wireguard-go state: present - become: yes + become: true - name: (MacOS) Install wireguard-tools package package: diff --git a/tasks/setup-ubuntu.yml b/tasks/setup-ubuntu.yml index 05ca3ae..a059ae4 100644 --- a/tasks/setup-ubuntu.yml +++ b/tasks/setup-ubuntu.yml @@ -7,15 +7,16 @@ update_cache: "{{ wireguard_ubuntu_update_cache }}" cache_valid_time: "{{ wireguard_ubuntu_cache_valid_time }}" -- block: - - name: (Ubuntu) Install support packages needed for Wireguard (for Ubuntu < 19.10) - package: - name: "{{ packages }}" - state: present - vars: - packages: - - software-properties-common - - linux-headers-{{ ansible_kernel }} +- name: (Ubuntu) Tasks for Ubuntu < 19.10 + block: + - name: (Ubuntu) Install support packages needed for Wireguard (for Ubuntu < 19.10) + package: + name: "{{ packages }}" + state: present + vars: + packages: + - software-properties-common + - linux-headers-{{ ansible_kernel }} when: - ansible_lsb.major_release is version('19.10', '<')