Added Wireguard role
This commit is contained in:
parent
1c873cea70
commit
0c76cd5b44
128
roles/wireguard/README.rst
Normal file
128
roles/wireguard/README.rst
Normal file
|
@ -0,0 +1,128 @@
|
|||
Wireguard setup
|
||||
===============
|
||||
|
||||
Wireguard setup role. This role extends `this codebase <https://github.com/lablabs/ansible-collection-wireguard/tree/main/roles/wireguard>`_ to my needs. It's a bit simpler and adds more idempotence, e.g. when replaying the role to add another client to the server.
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
This role was written for Debian (11) and requires root privileges. It also requires to have several collections installed on your ansible host you won't necessarily have depending on your Ansible installation:
|
||||
|
||||
- ansible.posix
|
||||
- community.general (iptables_save module)
|
||||
- ansible.utils (network filters)
|
||||
- netaddr (python package)
|
||||
|
||||
Role Variables
|
||||
--------------
|
||||
|
||||
Variables can be found in the `default vars <defaults/main.yml>`_
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
wireguard_dir: /etc/wireguard
|
||||
wireguard_clients_dir: "{{ wireguard_dir }}/clients"
|
||||
wireguard_clients_download_dir: clients/
|
||||
wireguard_download_clients: false
|
||||
wireguard_serverkeys_download_dir: server/
|
||||
wireguard_download_serverkeys: false
|
||||
|
||||
Defines basic arborescence to store Wireguard files. ``wireguard_download_clients`` and ``wireguard_download_serverkeys`` can optionally set to true in order to download respectively clients and server's keys from the target host.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
wireguard_restore_serverkeys_dir: ""
|
||||
|
||||
Use this variable if you want to use pre-existing keys from a directory to bootstrap Wireguard. Must ends with '/'.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
wireguard_packages:
|
||||
- wireguard
|
||||
|
||||
List of packages to install.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
wireguard_port: 51810
|
||||
|
||||
Port which Wireguard will listen to.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
wireguard_hostname: "{{ inventory_hostname }}"
|
||||
|
||||
Hostname the client will use to connect to the server.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
wireguard_interface: wg0
|
||||
|
||||
Interface which will be mounted to the server.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
nat_out_interface: eth0
|
||||
|
||||
Interface where the traffic will be NATed to on the server.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
wireguard_address: 10.213.213.0/24
|
||||
|
||||
Subnet definition for the VPN network.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
wireguard_keepalive: 25
|
||||
|
||||
Uses this if you wanna specify a keepalive value. See `this <https://github.com/pirate/wireguard-docs#persistentkeepalive>`_ for more information on keepalive.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
wireguard_peers: []
|
||||
|
||||
Lits of peers (clients) you wanna create. You can define specific name, address, allowedIPs, DNS and keepalive for each peer. See playbook below for example.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
filter_forward: false
|
||||
other_interface:
|
||||
|
||||
Set ``filter_forward`` to true and specify an interface name for ``other_interface`` if you wanna drop packets from ``wireguard_interface`` to this interface.
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
None.
|
||||
|
||||
Example Playbook
|
||||
----------------
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
- name: Deploy Wireguard
|
||||
hosts: wireguard_hosts
|
||||
become: true
|
||||
vars:
|
||||
wireguard_hostname: "mywireguard.server.com"
|
||||
wireguard_address: 10.10.10.0/24
|
||||
wireguard_peers:
|
||||
- name: client_001
|
||||
allowed_ip: "0.0.0.0/0, ::/0"
|
||||
address: "10.10.10.2"
|
||||
- name: client_002
|
||||
allowed_ip: "0.0.0.0/0, ::/0"
|
||||
address: "10.10.10.3"
|
||||
roles:
|
||||
- wireguard
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
BSD-3
|
||||
|
||||
Author Information
|
||||
------------------
|
||||
|
||||
Role created by `syrell <https://git.syyrell.com/syrell>`_
|
51
roles/wireguard/defaults/main.yml
Normal file
51
roles/wireguard/defaults/main.yml
Normal file
|
@ -0,0 +1,51 @@
|
|||
---
|
||||
# defaults file for wireguard
|
||||
# Directory to store WireGuard configuration on the remote hosts
|
||||
wireguard_dir: /etc/wireguard
|
||||
wireguard_clients_dir: "{{ wireguard_dir }}/clients"
|
||||
|
||||
# Download client configs
|
||||
wireguard_clients_download_dir: clients/
|
||||
wireguard_download_clients: false
|
||||
|
||||
# Download private, public and preshared keys
|
||||
wireguard_serverkeys_download_dir: server/
|
||||
wireguard_download_serverkeys: false
|
||||
|
||||
# Path to Wireguard keys
|
||||
wireguard_privatekey_path: "{{ wireguard_dir }}/pk"
|
||||
wireguard_publickey_path: "{{ wireguard_dir }}/pubk"
|
||||
wireguard_presharedkey_path: "{{ wireguard_dir }}/psk"
|
||||
|
||||
# When defined, Ansible will restore wireguard keys (private key, public key, preshared key) from this directory.
|
||||
# NOTE: The directory path must end with "/"
|
||||
wireguard_restore_serverkeys_dir: ""
|
||||
|
||||
# List of packages to install
|
||||
wireguard_packages:
|
||||
- wireguard
|
||||
|
||||
# The default port WireGuard will listen if not specified otherwise.
|
||||
wireguard_port: 51810
|
||||
|
||||
# Client destination Hostname
|
||||
wireguard_hostname: "{{ inventory_hostname }}"
|
||||
|
||||
# The default interface name that wireguard should use if not specified otherwise.
|
||||
wireguard_interface: wg0
|
||||
|
||||
# Interface to NAT traffic to
|
||||
nat_out_interface: eth0
|
||||
|
||||
# Base wireguard subnet
|
||||
wireguard_address: 10.213.213.0/24
|
||||
|
||||
# Defines a keepalive value for peers
|
||||
wireguard_keepalive: 0
|
||||
|
||||
# List of peers
|
||||
wireguard_peers: []
|
||||
|
||||
# Add additional forward rule to drop packets to other_interface
|
||||
filter_forward: false
|
||||
other_interface:
|
52
roles/wireguard/meta/main.yml
Normal file
52
roles/wireguard/meta/main.yml
Normal file
|
@ -0,0 +1,52 @@
|
|||
galaxy_info:
|
||||
author: your name
|
||||
description: your role description
|
||||
company: your company (optional)
|
||||
|
||||
# If the issue tracker for your role is not on github, uncomment the
|
||||
# next line and provide a value
|
||||
# issue_tracker_url: http://example.com/issue/tracker
|
||||
|
||||
# Choose a valid license ID from https://spdx.org - some suggested licenses:
|
||||
# - BSD-3-Clause (default)
|
||||
# - MIT
|
||||
# - GPL-2.0-or-later
|
||||
# - GPL-3.0-only
|
||||
# - Apache-2.0
|
||||
# - CC-BY-4.0
|
||||
license: license (GPL-2.0-or-later, MIT, etc)
|
||||
|
||||
min_ansible_version: 2.1
|
||||
|
||||
# If this a Container Enabled role, provide the minimum Ansible Container version.
|
||||
# min_ansible_container_version:
|
||||
|
||||
#
|
||||
# Provide a list of supported platforms, and for each platform a list of versions.
|
||||
# If you don't wish to enumerate all versions for a particular platform, use 'all'.
|
||||
# To view available platforms and versions (or releases), visit:
|
||||
# https://galaxy.ansible.com/api/v1/platforms/
|
||||
#
|
||||
# platforms:
|
||||
# - name: Fedora
|
||||
# versions:
|
||||
# - all
|
||||
# - 25
|
||||
# - name: SomePlatform
|
||||
# versions:
|
||||
# - all
|
||||
# - 1.0
|
||||
# - 7
|
||||
# - 99.99
|
||||
|
||||
galaxy_tags: []
|
||||
# List tags for your role here, one per line. A tag is a keyword that describes
|
||||
# and categorizes the role. Users find roles by searching for tags. Be sure to
|
||||
# remove the '[]' above, if you add tags to this list.
|
||||
#
|
||||
# NOTE: A tag is limited to a single word comprised of alphanumeric characters.
|
||||
# Maximum 20 tags per role.
|
||||
|
||||
dependencies: []
|
||||
# List your role dependencies here, one per line. Be sure to remove the '[]' above,
|
||||
# if you add dependencies to this list.
|
51
roles/wireguard/tasks/clients.yml
Normal file
51
roles/wireguard/tasks/clients.yml
Normal file
|
@ -0,0 +1,51 @@
|
|||
- name: Create client configs directories
|
||||
ansible.builtin.file:
|
||||
path: "{{ wireguard_clients_dir }}/{{ item.FriendlyName }}"
|
||||
mode: 0755
|
||||
state: directory
|
||||
register: existing_client_config
|
||||
|
||||
- name: Wireguard client keys block
|
||||
block:
|
||||
|
||||
- name: Generate WireGuard client private and public keys
|
||||
ansible.builtin.shell: |
|
||||
set -o pipefail
|
||||
umask 077 && wg genkey | tee pk | wg pubkey > pubk
|
||||
args:
|
||||
executable: /bin/bash
|
||||
chdir: "{{ wireguard_clients_dir }}/{{ item.FriendlyName }}"
|
||||
|
||||
- name: Read publickey
|
||||
ansible.builtin.slurp:
|
||||
src: "{{ wireguard_clients_dir }}/{{ item.FriendlyName }}/pubk"
|
||||
register: _client_pubkey_value
|
||||
|
||||
- name: Read privatekey
|
||||
ansible.builtin.slurp:
|
||||
src: "{{ wireguard_clients_dir }}/{{ item.FriendlyName }}/pk"
|
||||
register: _privkey_value
|
||||
|
||||
- name: Create client config
|
||||
ansible.builtin.template:
|
||||
src: "clients.conf.j2"
|
||||
dest: "{{ wireguard_clients_dir }}/{{ item.FriendlyName }}/{{ item.FriendlyName }}.conf"
|
||||
mode: 0644
|
||||
vars:
|
||||
server_public_key: "{{ _pubkey_value['content'] | b64decode | trim }}"
|
||||
preshared_key: "{{ _pskkey_value['content'] | b64decode | trim }}"
|
||||
|
||||
- name: Download client configs
|
||||
ansible.builtin.fetch:
|
||||
src: "{{ wireguard_clients_dir }}/{{ item.FriendlyName }}.conf"
|
||||
dest: "{{ wireguard_clients_download_dir }}/{{ inventory_hostname }}/"
|
||||
flat: true
|
||||
when: wireguard_download_clients | bool
|
||||
|
||||
- name: Append peer to server config
|
||||
ansible.builtin.blockinfile:
|
||||
dest: "{{ wireguard_dir }}/{{ wireguard_interface }}.conf"
|
||||
block: "{{ lookup('template', 'templates/peer.j2') }}"
|
||||
marker: "### {mark} ANSIBLE MANAGED BLOCK FOR {{ item.FriendlyName }} ###"
|
||||
|
||||
when: existing_client_config.changed == true
|
32
roles/wireguard/tasks/firewall.yml
Normal file
32
roles/wireguard/tasks/firewall.yml
Normal file
|
@ -0,0 +1,32 @@
|
|||
- name: Install iptables-persistent
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- iptables
|
||||
- iptables-persistent
|
||||
state: present
|
||||
|
||||
- name: Filter FORWARD packets
|
||||
ansible.builtin.iptables:
|
||||
chain: FORWARD
|
||||
jump: DROP
|
||||
in_interface: "{{ wireguard_interface }}"
|
||||
out_interface: "{{ other_interface }}"
|
||||
when:
|
||||
- filter_forward | bool
|
||||
- other_interface | length > 0
|
||||
|
||||
|
||||
- name: Setup ipv4 IP forward
|
||||
ansible.posix.sysctl:
|
||||
name: net.ipv4.ip_forward
|
||||
value: '1'
|
||||
sysctl_set: true
|
||||
reload: true
|
||||
|
||||
- name: Save current firewall state
|
||||
community.general.iptables_state:
|
||||
state: saved
|
||||
path: /etc/iptables/rules.v4
|
||||
when:
|
||||
- filter_forward | bool
|
||||
- other_interface | length > 0
|
14
roles/wireguard/tasks/init.yml
Normal file
14
roles/wireguard/tasks/init.yml
Normal file
|
@ -0,0 +1,14 @@
|
|||
- name: Create required dirs
|
||||
ansible.builtin.file:
|
||||
path: "{{ item }}"
|
||||
mode: 0755
|
||||
state: directory
|
||||
loop:
|
||||
- "{{ wireguard_dir }}"
|
||||
- "{{ wireguard_clients_dir }}"
|
||||
|
||||
- name: Install WireGuard
|
||||
ansible.builtin.apt:
|
||||
name: "{{ wireguard_packages }}"
|
||||
update_cache: true
|
||||
state: present
|
26
roles/wireguard/tasks/main.yml
Normal file
26
roles/wireguard/tasks/main.yml
Normal file
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
# tasks file for wireguard
|
||||
- name: Init tasks
|
||||
import_tasks: init.yml
|
||||
|
||||
- name: Deploy server
|
||||
import_tasks: server.yml
|
||||
|
||||
- name: Firewalling
|
||||
import_tasks: firewall.yml
|
||||
|
||||
- name: Include Client configs
|
||||
include_tasks: clients.yml
|
||||
loop: "{{ peers | list }}"
|
||||
|
||||
- name: Cleanup secrets from memory
|
||||
ansible.builtin.set_fact:
|
||||
_pskkey_value: ""
|
||||
_pubkey_value: ""
|
||||
_privkey_value: ""
|
||||
|
||||
- name: Restart wg-quick
|
||||
ansible.builtin.systemd:
|
||||
name: wg-quick@wg0.service
|
||||
enabled: yes
|
||||
state: restarted
|
75
roles/wireguard/tasks/server.yml
Normal file
75
roles/wireguard/tasks/server.yml
Normal file
|
@ -0,0 +1,75 @@
|
|||
- name: Wireguard keys block
|
||||
block:
|
||||
- name: Test if private key is already present
|
||||
ansible.builtin.stat:
|
||||
path: "{{ wireguard_privatekey_path }}"
|
||||
register: _priv_key
|
||||
|
||||
- name: Generate WireGuard server private and public keys
|
||||
ansible.builtin.shell: |
|
||||
set -o pipefail
|
||||
umask 077 && wg genkey | tee {{ wireguard_privatekey_path }} | wg pubkey > {{ wireguard_publickey_path }}
|
||||
args:
|
||||
executable: /bin/bash
|
||||
when:
|
||||
- not _priv_key.stat.exists
|
||||
- wireguard_restore_serverkeys_dir | length == 0
|
||||
|
||||
- name: Restore WireGuard private, public and preshared keys
|
||||
ansible.builtin.copy:
|
||||
src: "{{ wireguard_restore_serverkeys_dir }}"
|
||||
dest: "{{ wireguard_dir }}"
|
||||
mode: '0644'
|
||||
when:
|
||||
- not _priv_key.stat.exists
|
||||
- wireguard_restore_serverkeys_dir | length > 0
|
||||
|
||||
- name: Read publickey
|
||||
ansible.builtin.slurp:
|
||||
src: "{{ wireguard_publickey_path }}"
|
||||
register: _pubkey_value
|
||||
|
||||
- name: Read privatekey
|
||||
ansible.builtin.slurp:
|
||||
src: "{{ wireguard_privatekey_path }}"
|
||||
register: _privkey_value
|
||||
|
||||
- name: Test if preshared key is already present
|
||||
ansible.builtin.stat:
|
||||
path: "{{ wireguard_presharedkey_path }}"
|
||||
register: _psk_key
|
||||
|
||||
- name: Generate WireGuard preshared key
|
||||
ansible.builtin.shell: |
|
||||
set -o pipefail
|
||||
umask 077 && wg genpsk | tee {{ wireguard_presharedkey_path }}
|
||||
args:
|
||||
executable: /bin/bash
|
||||
when: not _psk_key.stat.exists
|
||||
|
||||
- name: Read presharedkey
|
||||
ansible.builtin.slurp:
|
||||
src: "{{ wireguard_presharedkey_path }}"
|
||||
register: _pskkey_value
|
||||
|
||||
- name: Create server config
|
||||
ansible.builtin.template:
|
||||
src: server.conf.j2
|
||||
dest: "{{ wireguard_dir }}/{{ wireguard_interface }}.conf"
|
||||
mode: 0700
|
||||
force: no
|
||||
|
||||
- name: Create peers variable from template
|
||||
ansible.builtin.set_fact:
|
||||
peers: "{{ lookup('template', 'templates/peers.j2') | from_yaml }}"
|
||||
|
||||
- name: Download server private key
|
||||
ansible.builtin.fetch:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ wireguard_serverkeys_download_dir }}/{{ inventory_hostname }}/"
|
||||
flat: true
|
||||
loop:
|
||||
- "{{ wireguard_privatekey_path }}"
|
||||
- "{{ wireguard_publickey_path }}"
|
||||
- "{{ wireguard_presharedkey_path }}"
|
||||
when: wireguard_download_serverkeys | bool
|
13
roles/wireguard/templates/clients.conf.j2
Normal file
13
roles/wireguard/templates/clients.conf.j2
Normal file
|
@ -0,0 +1,13 @@
|
|||
[Interface]
|
||||
Address = {{ item.Address }}
|
||||
ListenPort = {{ wireguard_port }}
|
||||
PrivateKey = {{ _privkey_value['content'] | b64decode | trim }}
|
||||
{% if item.DNS|length > 0 %}DNS = {{ item.DNS }}
|
||||
{% endif %}
|
||||
|
||||
[Peer]
|
||||
PublicKey = {{ server_public_key }}
|
||||
PresharedKey = {{ preshared_key }}
|
||||
AllowedIPs = {{ item.AllowedIPs }}
|
||||
Endpoint = {{ wireguard_hostname }}:{{ wireguard_port }}
|
||||
PersistentKeepalive = {{ item.PersistentKeepalive | default(wireguard_keepalive) }}
|
5
roles/wireguard/templates/peer.j2
Normal file
5
roles/wireguard/templates/peer.j2
Normal file
|
@ -0,0 +1,5 @@
|
|||
[peer]
|
||||
# peer_{{ item.FriendlyName }}
|
||||
PublicKey = {{ _client_pubkey_value['content'] | b64decode | trim }}
|
||||
PresharedKey = {{ item.PresharedKey }}
|
||||
AllowedIPs = {{ item.Address }}/32
|
9
roles/wireguard/templates/peers.j2
Normal file
9
roles/wireguard/templates/peers.j2
Normal file
|
@ -0,0 +1,9 @@
|
|||
{% for peer in wireguard_peers %}
|
||||
- WireGuardPeer:
|
||||
FriendlyName: {{ peer.name }}
|
||||
Address: {{ peer.address }}
|
||||
AllowedIPs: "{{ peer.allowed_ip }}{% if not '/' in peer.allowed_ip %}/32{% endif %}"
|
||||
DNS: "{% if peer.dns is defined %}{{ peer.dns }}{% endif %}"
|
||||
PresharedKey: "{{ _pskkey_value['content'] | b64decode | trim }}"
|
||||
PersistentKeepalive: {{ peer.keepalive | default(wireguard_keepalive) }}
|
||||
{% endfor %}
|
6
roles/wireguard/templates/server.conf.j2
Normal file
6
roles/wireguard/templates/server.conf.j2
Normal file
|
@ -0,0 +1,6 @@
|
|||
[Interface]
|
||||
Address = {{ wireguard_server_ip }}
|
||||
ListenPort = {{ wireguard_port }}
|
||||
PrivateKey = {{ _privkey_value['content'] | b64decode | trim }}
|
||||
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -s {{ wireguard_address }} -o {{ nat_out_interface }} -j MASQUERADE
|
||||
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -s {{ wireguard_address }} -o {{ nat_out_interface }} -j MASQUERADE
|
6
roles/wireguard/vars/main.yml
Normal file
6
roles/wireguard/vars/main.yml
Normal file
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
# vars file for wireguard
|
||||
_wireguard_interface_addr: "{{ ansible_default_ipv4.address | default(ansible_all_ipv4_addresses[0]) }}/{{ ansible_default_ipv4.netmask }}"
|
||||
wireguard_server_ip: "{{ wireguard_address | ansible.utils.ipaddr('network') | ansible.utils.ipmath(1) }}"
|
||||
wireguard_subnetmask: "{{ wireguard_address | ansible.utils.ipaddr('prefix') }}"
|
||||
wireguard_peers_allowed_ips: "{{ ([(_wireguard_interface_addr | ansible.utils.ipaddr('network/prefix'))] + (wireguard_additional_routes | default([]))) | join(\", \") }}"
|
Loading…
Reference in New Issue
Block a user