ansible
This commit is contained in:
parent
7974e36c1b
commit
b81f7e15b2
41 changed files with 1632 additions and 0 deletions
39
ansible/roles/wireguard/defaults/main.yaml
Normal file
39
ansible/roles/wireguard/defaults/main.yaml
Normal 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: []
|
||||
21
ansible/roles/wireguard/handlers/main.yaml
Normal file
21
ansible/roles/wireguard/handlers/main.yaml
Normal 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
|
||||
219
ansible/roles/wireguard/tasks/main.yaml
Normal file
219
ansible/roles/wireguard/tasks/main.yaml
Normal 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
|
||||
21
ansible/roles/wireguard/templates/client.conf.j2
Normal file
21
ansible/roles/wireguard/templates/client.conf.j2
Normal 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) }}
|
||||
39
ansible/roles/wireguard/templates/wg0.conf.j2
Normal file
39
ansible/roles/wireguard/templates/wg0.conf.j2
Normal 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 %}
|
||||
Loading…
Add table
Add a link
Reference in a new issue