diff --git a/roles/wg_spoke/README.md b/roles/wg_spoke/README.md new file mode 100644 index 0000000..c0ba380 --- /dev/null +++ b/roles/wg_spoke/README.md @@ -0,0 +1,46 @@ +wg_spoke +========= + +Configure the host as a Spoke in Wireguard Spoke&Hub topology. + +Requirements +------------ + +Ubuntu 20.04, 22.04 or 24.04. + +Role Variables +-------------- + +```yaml +iface_name: name of the Wireguard interface (network), config file is named after it; WARNING, dashes are not supported +spoke_ipv4_vpn: IPv4 address that this Spoke should expect on the VPN +subnet: something like "10.0.0.0" +netmask: CIDR-style netmask without a slash, e.g. "24" +spoke_pkey: Spoke private key (Wireguard-generated, base64) +hub_pubkey: Hub public key (Wireguard-generated, base64) +hub_ipv4_wan: WAN (Internet) IPv4 address of the Hub +hub_ipv4_vpn: IPv4 address of the Hub on the VPN +hub_port: Hub should be listening on this port +wg_spoke_hide_secrets: whether or not prevent Ansible from logging tasks that handle sensitive info like keys (default is `true`) +wg_spoke_logging: whether or not to send Wireguard dyndbg logs to the kernel buffer accesible via journalctl -ek (default is `true`) +``` + +Dependencies +------------ + +None + +Example Playbook +---------------- + +See `molecule/default/converge.yml`. + +License +------- + +BSD + +Author Information +------------------ + +corvus-migratorius@proton.me diff --git a/roles/wg_spoke/defaults/main.yml b/roles/wg_spoke/defaults/main.yml new file mode 100644 index 0000000..3cb9c8b --- /dev/null +++ b/roles/wg_spoke/defaults/main.yml @@ -0,0 +1,3 @@ +--- +wg_spoke_hide_secrets: true +wg_spoke_logging: true diff --git a/roles/wg_spoke/handlers/main.yml b/roles/wg_spoke/handlers/main.yml new file mode 100644 index 0000000..7372f6c --- /dev/null +++ b/roles/wg_spoke/handlers/main.yml @@ -0,0 +1,7 @@ +--- +- name: "Run the Wireguard service" + ansible.builtin.systemd_service: + name: wg-quick@{{ iface_name }} + state: restarted + enabled: true + daemon_reload: true diff --git a/roles/wg_spoke/meta/main.yml b/roles/wg_spoke/meta/main.yml new file mode 100644 index 0000000..396d62a --- /dev/null +++ b/roles/wg_spoke/meta/main.yml @@ -0,0 +1,17 @@ +--- +galaxy_info: + role_name: "wg_spoke" + namespace: genlab + author: "Alexander Gorelyshev" + company: "Genlab, LLC" + description: "" + license: "MIT" + min_ansible_version: "2.1" + + platforms: + - name: "Ubuntu" + versions: ["focal", "jammy", "noble"] + + galaxy_tags: [] + +dependencies: [] diff --git a/roles/wg_spoke/molecule/default/converge.yml b/roles/wg_spoke/molecule/default/converge.yml new file mode 100644 index 0000000..cc5f583 --- /dev/null +++ b/roles/wg_spoke/molecule/default/converge.yml @@ -0,0 +1,20 @@ +--- +- name: Converge + hosts: all + roles: + - role: genlab.common.wg_spoke + iface_name: adm + subnet: "10.0.0.0" + netmask: "24" + spoke_ipv4_vpn: "10.0.0.1" + spoke_port: "51820" + spoke_pkey: eGqGx4A5ufFKatLflPFKNuzFgGuospIe08iPbTlEhm0= + hub_pubkey: EvcoZ21/p0AHz5y95jwjVIR9puljc2kXqh/f3U1A4nk= + # hub_psk: 5qmMuLuGQT7w8VnHPsZDO4vRF5wEKcpEtaCQW1BLmbg= + hub_ipv4_wan: "1.2.3.4" + hub_ipv4_vpn: "10.0.0.254" + hub_port: "51820" + dns_server: "10.0.0.254:5300" + domain: "adm.local" + wg_spoke_hide_secrets: false + wg_spoke_logging: false # doesn't work in Github Actions environment diff --git a/roles/wg_spoke/molecule/default/molecule.yml b/roles/wg_spoke/molecule/default/molecule.yml new file mode 100644 index 0000000..fd2f06d --- /dev/null +++ b/roles/wg_spoke/molecule/default/molecule.yml @@ -0,0 +1,27 @@ +--- +dependency: + name: galaxy + +driver: + name: docker + +platforms: + - name: ubuntu + image: geerlingguy/docker-${MOLECULE_DISTRO:-ubuntu2204}-ansible:latest + pre_build_image: true + command: ${MOLECULE_DOCKER_COMMAND:-""} + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:rw + cgroupns_mode: host + privileged: true + +provisioner: + name: ansible + +verifier: + name: ansible + +lint: | + set -e + yamllint . + ansible-lint . diff --git a/roles/wg_spoke/molecule/default/verify.yml b/roles/wg_spoke/molecule/default/verify.yml new file mode 100644 index 0000000..38f93ff --- /dev/null +++ b/roles/wg_spoke/molecule/default/verify.yml @@ -0,0 +1,13 @@ +--- +- name: Verify + hosts: all + gather_facts: false + any_errors_fatal: true + vars: + iface_name: adm + + tasks: + - name: "Check that the Wireguard service is running" + ansible.builtin.service: + name: wg-quick@{{ iface_name }} + state: started diff --git a/roles/wg_spoke/tasks/deploy.yml b/roles/wg_spoke/tasks/deploy.yml new file mode 100644 index 0000000..faa60ad --- /dev/null +++ b/roles/wg_spoke/tasks/deploy.yml @@ -0,0 +1,41 @@ +--- +- name: "Install Wireguard system-wide" + ansible.builtin.apt: + name: wireguard + state: present + update_cache: true + cache_valid_time: 3600 + +- name: "Ensure no dashes in the interface name" + when: "'-' in iface_name" + ansible.builtin.fail: + msg: "The interface name must not contain dashes, got: '{{ iface_name }}'" + +- name: "Create a Spoke configuration file" + no_log: "{{ wg_spoke_hide_secrets }}" + notify: "Run the Wireguard service" + ansible.builtin.blockinfile: + path: "/etc/wireguard/{{ iface_name }}.conf" + create: true + owner: root + group: root + mode: "0600" + state: present + block: | + [Interface] # Local settings for this node + Address = {{ spoke_ipv4_vpn }}/32 + ListenPort = {{ spoke_port }} + PrivateKey = {{ spoke_pkey }} + + {% if dns_server is defined and domain is defined %} + PostUp = resolvectl dns %i {{ dns_server }}; resolvectl domain %i {{ domain }} + {% endif %} + + [Peer] # Settings for the Hub peer + PublicKey = {{ hub_pubkey }} + {% if spoke_psk is defined %} + PresharedKey = {{ spoke_psk }} + {% endif %} + AllowedIPs = {{ subnet }}/{{ netmask }} + Endpoint = {{ hub_ipv4_wan }}:{{ hub_port }} + PersistentKeepalive = 20 diff --git a/roles/wg_spoke/tasks/logging.yml b/roles/wg_spoke/tasks/logging.yml new file mode 100644 index 0000000..8989ae4 --- /dev/null +++ b/roles/wg_spoke/tasks/logging.yml @@ -0,0 +1,11 @@ +--- +# SRC https://www.procustodibus.com/blog/2021/03/wireguard-logs/ +- name: "Add wireguard module" + community.general.modprobe: + name: wireguard + state: present + +- name: "Turn on Wireguard dyndbg logging into kernel message buffer" + changed_when: false + ansible.builtin.shell: + cmd: echo module wireguard +p > /sys/kernel/debug/dynamic_debug/control diff --git a/roles/wg_spoke/tasks/main.yml b/roles/wg_spoke/tasks/main.yml new file mode 100644 index 0000000..d25fec3 --- /dev/null +++ b/roles/wg_spoke/tasks/main.yml @@ -0,0 +1,9 @@ +--- +- name: "Include Wireguard deployment tasks" + ansible.builtin.include_tasks: + file: "tasks/deploy.yml" + +- name: "Include Wireguard logging configuration tasks" + when: wg_spoke_logging is true + ansible.builtin.include_tasks: + file: "tasks/logging.yml" diff --git a/roles/wg_spoke/vars/main.yml b/roles/wg_spoke/vars/main.yml new file mode 100644 index 0000000..ed97d53 --- /dev/null +++ b/roles/wg_spoke/vars/main.yml @@ -0,0 +1 @@ +---