This commit is contained in:
Sergei Poljanski 2025-11-01 17:15:42 +02:00
commit b81f7e15b2
41 changed files with 1632 additions and 0 deletions

View file

@ -0,0 +1,39 @@
---
# WireGuard default configuration
wireguard_interface: wg0
wireguard_port: 60101
wireguard_ipv4: 10.20.0.10
wireguard_ipv6: fd69:69:69::1
wireguard_ipv4_network: 10.20.0.0/24
wireguard_ipv6_network: fd69:69:69::/64
# Directory paths
wireguard_config_dir: /etc/wireguard
wireguard_keys_dir: "{{ wireguard_config_dir }}/keys"
wireguard_clients_dir: "{{ wireguard_config_dir }}/clients"
# Enable IPv4 forwarding
wireguard_enable_forwarding: true
# UFW configuration (if false, will use iptables rules in PostUp/PostDown)
# Default to false since most Debian servers don't have UFW enabled by default
wireguard_enable_ufw: false
# Client configurations
wireguard_clients: []
# Example client structure:
# wireguard_clients:
# - name: laptop
# ipv4: 10.20.0.2
# ipv6: fd69:69:69::2
# preshared_key: true # Optional: generate preshared key for extra security
# - name: phone
# ipv4: 10.20.0.3
# ipv6: fd69:69:69::3
# preshared_key: true
# DNS servers for clients (optional)
wireguard_dns_servers: []
# Additional routes for split tunneling (optional)
wireguard_additional_routes: []

View file

@ -0,0 +1,21 @@
---
- name: restart wireguard
ansible.builtin.shell: |
wg syncconf {{ wireguard_interface }} <(wg-quick strip {{ wireguard_interface }})
args:
executable: /bin/bash
ignore_errors: true
register: wg_sync_result
- name: restart wireguard (fallback)
ansible.builtin.systemd:
name: "wg-quick@{{ wireguard_interface }}"
state: restarted
enabled: true
when: wg_sync_result is failed
- name: reload wireguard
ansible.builtin.shell: |
wg syncconf {{ wireguard_interface }} <(wg-quick strip {{ wireguard_interface }})
args:
executable: /bin/bash

View file

@ -0,0 +1,219 @@
---
- name: Install WireGuard
ansible.builtin.apt:
name:
- wireguard
- wireguard-tools
state: present
update_cache: true
- name: Install UFW (if needed)
ansible.builtin.apt:
name: ufw
state: present
when: wireguard_enable_ufw
- name: Create WireGuard directories
ansible.builtin.file:
path: "{{ item }}"
state: directory
mode: '0700'
owner: root
group: root
loop:
- "{{ wireguard_config_dir }}"
- "{{ wireguard_keys_dir }}"
- "{{ wireguard_clients_dir }}"
- name: Check if server private key exists
ansible.builtin.stat:
path: "{{ wireguard_keys_dir }}/server_private.key"
register: server_private_key_stat
- name: Generate server private key
ansible.builtin.shell: |
wg genkey > {{ wireguard_keys_dir }}/server_private.key
chmod 600 {{ wireguard_keys_dir }}/server_private.key
when: not server_private_key_stat.stat.exists
- name: Generate server public key
ansible.builtin.shell: |
wg pubkey < {{ wireguard_keys_dir }}/server_private.key > {{ wireguard_keys_dir }}/server_public.key
chmod 600 {{ wireguard_keys_dir }}/server_public.key
when: not server_private_key_stat.stat.exists
- name: Read server private key
ansible.builtin.slurp:
src: "{{ wireguard_keys_dir }}/server_private.key"
register: server_private_key_content
- name: Read server public key
ansible.builtin.slurp:
src: "{{ wireguard_keys_dir }}/server_public.key"
register: server_public_key_content
- name: Set server key facts
ansible.builtin.set_fact:
wireguard_server_private_key: "{{ server_private_key_content.content | b64decode | trim }}"
wireguard_server_public_key: "{{ server_public_key_content.content | b64decode | trim }}"
- name: Generate client keys
block:
- name: Check if client private key exists
ansible.builtin.stat:
path: "{{ wireguard_keys_dir }}/{{ item.name }}_private.key"
register: client_private_key_stats
loop: "{{ wireguard_clients }}"
- name: Generate client private keys
ansible.builtin.shell: |
wg genkey > {{ wireguard_keys_dir }}/{{ item.item.name }}_private.key
chmod 600 {{ wireguard_keys_dir }}/{{ item.item.name }}_private.key
loop: "{{ client_private_key_stats.results }}"
when: not item.stat.exists
- name: Check if client public key exists
ansible.builtin.stat:
path: "{{ wireguard_keys_dir }}/{{ item.name }}_public.key"
register: client_public_key_stats
loop: "{{ wireguard_clients }}"
- name: Generate client public keys
ansible.builtin.shell: |
wg pubkey < {{ wireguard_keys_dir }}/{{ item.item.name }}_private.key > {{ wireguard_keys_dir }}/{{ item.item.name }}_public.key
chmod 600 {{ wireguard_keys_dir }}/{{ item.item.name }}_public.key
loop: "{{ client_public_key_stats.results }}"
when: not item.stat.exists
- name: Check if client preshared key exists
ansible.builtin.stat:
path: "{{ wireguard_keys_dir }}/{{ item.name }}_preshared.key"
register: client_preshared_key_stats
loop: "{{ wireguard_clients }}"
when: item.preshared_key | default(false)
- name: Generate client preshared keys (if enabled)
ansible.builtin.shell: |
wg genpsk > {{ wireguard_keys_dir }}/{{ item.item.name }}_preshared.key
chmod 600 {{ wireguard_keys_dir }}/{{ item.item.name }}_preshared.key
loop: "{{ client_preshared_key_stats.results | default([]) }}"
when:
- client_preshared_key_stats.results is defined
- not item.stat.exists
- name: Read client private keys
ansible.builtin.slurp:
src: "{{ wireguard_keys_dir }}/{{ item.name }}_private.key"
register: client_private_keys
loop: "{{ wireguard_clients }}"
- name: Read client public keys
ansible.builtin.slurp:
src: "{{ wireguard_keys_dir }}/{{ item.name }}_public.key"
register: client_public_keys
loop: "{{ wireguard_clients }}"
- name: Read client preshared keys
ansible.builtin.slurp:
src: "{{ wireguard_keys_dir }}/{{ item.name }}_preshared.key"
register: client_preshared_keys
loop: "{{ wireguard_clients }}"
when: item.preshared_key | default(false)
ignore_errors: true
when: wireguard_clients | length > 0
- name: Process client keys into structured data
ansible.builtin.set_fact:
wireguard_client_configs: "{{ wireguard_client_configs | default([]) + [client_config] }}"
loop: "{{ wireguard_clients }}"
loop_control:
index_var: client_index
vars:
private_key: "{{ client_private_keys.results[client_index].content | b64decode | trim }}"
public_key: "{{ client_public_keys.results[client_index].content | b64decode | trim }}"
preshared_key: "{{ client_preshared_keys.results[client_index].content | b64decode | trim if (item.preshared_key | default(false) and client_preshared_keys.results[client_index] is defined and not client_preshared_keys.results[client_index].failed | default(false)) else '' }}"
client_config:
name: "{{ item.name }}"
ipv4: "{{ item.ipv4 }}"
ipv6: "{{ item.ipv6 }}"
private_key: "{{ private_key }}"
public_key: "{{ public_key }}"
preshared_key: "{{ preshared_key }}"
persistent_keepalive: "{{ item.persistent_keepalive | default(25) }}"
when: wireguard_clients | length > 0
- name: Enable IPv4 forwarding
ansible.posix.sysctl:
name: net.ipv4.ip_forward
value: '1'
sysctl_set: true
state: present
reload: true
when: wireguard_enable_forwarding
- name: Enable IPv6 forwarding
ansible.posix.sysctl:
name: net.ipv6.conf.all.forwarding
value: '1'
sysctl_set: true
state: present
reload: true
when: wireguard_enable_forwarding
- name: Get default network interface
ansible.builtin.shell: ip route | grep default | awk '{print $5}' | head -n1
register: default_interface
changed_when: false
- name: Set default interface fact
ansible.builtin.set_fact:
wireguard_default_interface: "{{ default_interface.stdout }}"
- name: Deploy WireGuard server configuration
ansible.builtin.template:
src: wg0.conf.j2
dest: "{{ wireguard_config_dir }}/{{ wireguard_interface }}.conf"
mode: '0600'
owner: root
group: root
notify: restart wireguard
- name: Configure UFW for WireGuard
block:
- name: Allow WireGuard port through UFW
community.general.ufw:
rule: allow
port: "{{ wireguard_port }}"
proto: udp
- name: Allow forwarding on WireGuard interface
community.general.ufw:
rule: allow
route: true
interface_in: "{{ wireguard_interface }}"
when: wireguard_enable_ufw
- name: Enable and start WireGuard service
ansible.builtin.systemd:
name: "wg-quick@{{ wireguard_interface }}"
enabled: true
state: started
- name: Generate client configuration files
ansible.builtin.template:
src: client.conf.j2
dest: "{{ wireguard_clients_dir }}/{{ item.name }}.conf"
mode: '0600'
owner: root
group: root
loop: "{{ wireguard_client_configs | default([]) }}"
when: wireguard_clients | length > 0
- name: Fetch client configuration files to local machine
ansible.builtin.fetch:
src: "{{ wireguard_clients_dir }}/{{ item.name }}.conf"
dest: "./wireguard-configs/{{ inventory_hostname }}/{{ item.name }}.conf"
flat: true
loop: "{{ wireguard_clients }}"
when: wireguard_clients | length > 0

View file

@ -0,0 +1,21 @@
# WireGuard Client Configuration - {{ item.name }}
# Generated by Ansible on {{ ansible_date_time.iso8601 }}
# Server: {{ inventory_hostname }}
[Interface]
PrivateKey = {{ item.private_key }}
Address = {{ item.ipv4 }}/32,{{ item.ipv6 }}/128
{% if wireguard_dns_servers | length > 0 %}
DNS = {{ wireguard_dns_servers | join(', ') }}
{% endif %}
[Peer]
PublicKey = {{ wireguard_server_public_key }}
{% if item.preshared_key %}
PresharedKey = {{ item.preshared_key }}
{% endif %}
Endpoint = {{ ansible_host }}:{{ wireguard_port }}
# Allow all VPN traffic (peer-to-peer connectivity)
AllowedIPs = {{ wireguard_ipv4_network }},{{ wireguard_ipv6_network }}{% if wireguard_additional_routes | length > 0 %},{{ wireguard_additional_routes | join(',') }}{% endif %}
PersistentKeepalive = {{ item.persistent_keepalive | default(25) }}

View file

@ -0,0 +1,39 @@
# WireGuard Server Configuration - {{ wireguard_interface }}
# Generated by Ansible on {{ ansible_date_time.iso8601 }}
[Interface]
Address = {{ wireguard_ipv4 }}/{{ wireguard_ipv4_network.split('/')[-1] }},{{ wireguard_ipv6 }}/{{ wireguard_ipv6_network.split('/')[-1] }}
ListenPort = {{ wireguard_port }}
PrivateKey = {{ wireguard_server_private_key }}
{% if wireguard_enable_ufw %}
# UFW handles firewall rules
{% else %}
# Firewall rules for iptables
PostUp = iptables -I INPUT -p udp --dport {{ wireguard_port }} -j ACCEPT
PostUp = iptables -I FORWARD -i {{ wireguard_default_interface }} -o {{ wireguard_interface }} -j ACCEPT
PostUp = iptables -I FORWARD -i {{ wireguard_interface }} -j ACCEPT
PostUp = iptables -t nat -A POSTROUTING -o {{ wireguard_default_interface }} -j MASQUERADE
PostUp = ip6tables -I FORWARD -i {{ wireguard_interface }} -j ACCEPT
PostUp = ip6tables -t nat -A POSTROUTING -o {{ wireguard_default_interface }} -j MASQUERADE
PostDown = iptables -D INPUT -p udp --dport {{ wireguard_port }} -j ACCEPT
PostDown = iptables -D FORWARD -i {{ wireguard_default_interface }} -o {{ wireguard_interface }} -j ACCEPT
PostDown = iptables -D FORWARD -i {{ wireguard_interface }} -j ACCEPT
PostDown = iptables -t nat -D POSTROUTING -o {{ wireguard_default_interface }} -j MASQUERADE
PostDown = ip6tables -D FORWARD -i {{ wireguard_interface }} -j ACCEPT
PostDown = ip6tables -t nat -D POSTROUTING -o {{ wireguard_default_interface }} -j MASQUERADE
{% endif %}
{% for client in wireguard_client_configs | default([]) %}
### Client {{ client.name }}
[Peer]
PublicKey = {{ client.public_key }}
{% if client.preshared_key %}
PresharedKey = {{ client.preshared_key }}
{% endif %}
AllowedIPs = {{ client.ipv4 }}/32,{{ client.ipv6 }}/128
{% if client.persistent_keepalive | default(25) %}
PersistentKeepalive = {{ client.persistent_keepalive }}
{% endif %}
{% endfor %}