Remove WireGuard integration from production deployment to simplify infrastructure: - Remove docker-compose-direct-access.yml (VPN-bound services) - Remove VPN-only middlewares from Grafana, Prometheus, Portainer - Remove WireGuard middleware definitions from Traefik - Remove WireGuard IPs (10.8.0.0/24) from Traefik forwarded headers All monitoring services now publicly accessible via subdomains: - grafana.michaelschiemer.de (with Grafana native auth) - prometheus.michaelschiemer.de (with Basic Auth) - portainer.michaelschiemer.de (with Portainer native auth) All services use Let's Encrypt SSL certificates via Traefik.
230 lines
7.7 KiB
YAML
230 lines
7.7 KiB
YAML
---
|
|
# WireGuard Client Configuration Generator
|
|
# Usage: ansible-playbook playbooks/generate-wireguard-client.yml -e "client_name=michael-laptop"
|
|
|
|
- name: Generate WireGuard Client Configuration
|
|
hosts: server
|
|
become: true
|
|
gather_facts: true
|
|
|
|
vars:
|
|
# Default values (can be overridden with -e)
|
|
wireguard_config_dir: "/etc/wireguard"
|
|
wireguard_interface: "wg0"
|
|
wireguard_server_endpoint: "{{ ansible_default_ipv4.address }}"
|
|
wireguard_server_port: 51820
|
|
wireguard_vpn_network: "10.8.0.0/24"
|
|
wireguard_server_ip: "10.8.0.1"
|
|
|
|
# Client output directory (local)
|
|
client_config_dir: "{{ playbook_dir }}/../wireguard/configs"
|
|
|
|
# Required variable (must be passed via -e)
|
|
# client_name: "device-name"
|
|
|
|
tasks:
|
|
- name: Validate client_name is provided
|
|
assert:
|
|
that:
|
|
- client_name is defined
|
|
- client_name | length > 0
|
|
fail_msg: "ERROR: client_name must be provided via -e client_name=<name>"
|
|
success_msg: "Generating config for client: {{ client_name }}"
|
|
|
|
- name: Validate client_name format (alphanumeric and hyphens only)
|
|
assert:
|
|
that:
|
|
- client_name is match('^[a-zA-Z0-9-]+$')
|
|
fail_msg: "ERROR: client_name must contain only letters, numbers, and hyphens"
|
|
success_msg: "Client name format is valid"
|
|
|
|
- name: Check if WireGuard server is configured
|
|
stat:
|
|
path: "{{ wireguard_config_dir }}/{{ wireguard_interface }}.conf"
|
|
register: server_config
|
|
|
|
- name: Fail if server config doesn't exist
|
|
fail:
|
|
msg: "WireGuard server config not found. Run setup-wireguard-host.yml first."
|
|
when: not server_config.stat.exists
|
|
|
|
- name: Read server public key
|
|
slurp:
|
|
src: "{{ wireguard_config_dir }}/server_public.key"
|
|
register: server_public_key_raw
|
|
|
|
- name: Set server public key fact
|
|
set_fact:
|
|
server_public_key: "{{ server_public_key_raw.content | b64decode | trim }}"
|
|
|
|
- name: Get next available IP address
|
|
shell: |
|
|
# Parse existing peer IPs from wg0.conf
|
|
existing_ips=$(grep -oP 'AllowedIPs\s*=\s*\K[0-9.]+' {{ wireguard_config_dir }}/{{ wireguard_interface }}.conf 2>/dev/null || echo "")
|
|
|
|
# Start from .2 (server is .1)
|
|
i=2
|
|
while [ $i -le 254 ]; do
|
|
ip="10.8.0.$i"
|
|
if ! echo "$existing_ips" | grep -q "^$ip$"; then
|
|
echo "$ip"
|
|
exit 0
|
|
fi
|
|
i=$((i + 1))
|
|
done
|
|
|
|
echo "ERROR: No free IP addresses" >&2
|
|
exit 1
|
|
register: next_ip_result
|
|
changed_when: false
|
|
|
|
- name: Set client IP fact
|
|
set_fact:
|
|
client_ip: "{{ next_ip_result.stdout | trim }}"
|
|
|
|
- name: Display client IP assignment
|
|
debug:
|
|
msg: "Assigned IP for {{ client_name }}: {{ client_ip }}"
|
|
|
|
- name: Check if client already exists
|
|
shell: |
|
|
grep -q "# Client: {{ client_name }}" {{ wireguard_config_dir }}/{{ wireguard_interface }}.conf
|
|
register: client_exists
|
|
changed_when: false
|
|
failed_when: false
|
|
|
|
- name: Warn if client already exists
|
|
debug:
|
|
msg: "WARNING: Client '{{ client_name }}' already exists in server config. Creating new keys anyway."
|
|
when: client_exists.rc == 0
|
|
|
|
- name: Generate client private key
|
|
shell: wg genkey
|
|
register: client_private_key_result
|
|
changed_when: true
|
|
no_log: true
|
|
|
|
- name: Generate client public key
|
|
shell: echo "{{ client_private_key_result.stdout }}" | wg pubkey
|
|
register: client_public_key_result
|
|
changed_when: false
|
|
no_log: true
|
|
|
|
- name: Generate preshared key
|
|
shell: wg genpsk
|
|
register: preshared_key_result
|
|
changed_when: true
|
|
no_log: true
|
|
|
|
- name: Set client key facts
|
|
set_fact:
|
|
client_private_key: "{{ client_private_key_result.stdout | trim }}"
|
|
client_public_key: "{{ client_public_key_result.stdout | trim }}"
|
|
preshared_key: "{{ preshared_key_result.stdout | trim }}"
|
|
no_log: true
|
|
|
|
- name: Create client config directory on control node
|
|
delegate_to: localhost
|
|
file:
|
|
path: "{{ client_config_dir }}"
|
|
state: directory
|
|
mode: '0755'
|
|
become: false
|
|
|
|
- name: Generate client WireGuard configuration
|
|
delegate_to: localhost
|
|
copy:
|
|
content: |
|
|
[Interface]
|
|
# Client: {{ client_name }}
|
|
# Generated: {{ ansible_date_time.iso8601 }}
|
|
PrivateKey = {{ client_private_key }}
|
|
Address = {{ client_ip }}/32
|
|
DNS = 1.1.1.1, 8.8.8.8
|
|
|
|
[Peer]
|
|
# WireGuard Server
|
|
PublicKey = {{ server_public_key }}
|
|
PresharedKey = {{ preshared_key }}
|
|
Endpoint = {{ wireguard_server_endpoint }}:{{ wireguard_server_port }}
|
|
AllowedIPs = {{ wireguard_vpn_network }}
|
|
PersistentKeepalive = 25
|
|
dest: "{{ client_config_dir }}/{{ client_name }}.conf"
|
|
mode: '0600'
|
|
become: false
|
|
no_log: true
|
|
|
|
- name: Add client peer to server configuration
|
|
blockinfile:
|
|
path: "{{ wireguard_config_dir }}/{{ wireguard_interface }}.conf"
|
|
marker: "# {mark} ANSIBLE MANAGED BLOCK - Client: {{ client_name }}"
|
|
block: |
|
|
|
|
[Peer]
|
|
# Client: {{ client_name }}
|
|
PublicKey = {{ client_public_key }}
|
|
PresharedKey = {{ preshared_key }}
|
|
AllowedIPs = {{ client_ip }}/32
|
|
no_log: true
|
|
|
|
- name: Reload WireGuard configuration
|
|
shell: wg syncconf {{ wireguard_interface }} <(wg-quick strip {{ wireguard_interface }})
|
|
args:
|
|
executable: /bin/bash
|
|
|
|
- name: Generate QR code (ASCII)
|
|
delegate_to: localhost
|
|
shell: |
|
|
qrencode -t ansiutf8 < {{ client_config_dir }}/{{ client_name }}.conf > {{ client_config_dir }}/{{ client_name }}.qr.txt
|
|
become: false
|
|
changed_when: true
|
|
|
|
- name: Generate QR code (PNG)
|
|
delegate_to: localhost
|
|
shell: |
|
|
qrencode -t png -o {{ client_config_dir }}/{{ client_name }}.qr.png < {{ client_config_dir }}/{{ client_name }}.conf
|
|
become: false
|
|
changed_when: true
|
|
|
|
- name: Display QR code for mobile devices
|
|
delegate_to: localhost
|
|
shell: cat {{ client_config_dir }}/{{ client_name }}.qr.txt
|
|
register: qr_code_output
|
|
become: false
|
|
changed_when: false
|
|
|
|
- name: Client configuration summary
|
|
debug:
|
|
msg:
|
|
- "========================================="
|
|
- "WireGuard Client Configuration Created!"
|
|
- "========================================="
|
|
- ""
|
|
- "Client: {{ client_name }}"
|
|
- "IP Address: {{ client_ip }}/32"
|
|
- "Public Key: {{ client_public_key }}"
|
|
- ""
|
|
- "Configuration Files:"
|
|
- " Config: {{ client_config_dir }}/{{ client_name }}.conf"
|
|
- " QR Code (ASCII): {{ client_config_dir }}/{{ client_name }}.qr.txt"
|
|
- " QR Code (PNG): {{ client_config_dir }}/{{ client_name }}.qr.png"
|
|
- ""
|
|
- "Server Configuration:"
|
|
- " Endpoint: {{ wireguard_server_endpoint }}:{{ wireguard_server_port }}"
|
|
- " Allowed IPs: {{ wireguard_vpn_network }}"
|
|
- ""
|
|
- "Next Steps:"
|
|
- " Linux/macOS: sudo cp {{ client_config_dir }}/{{ client_name }}.conf /etc/wireguard/ && sudo wg-quick up {{ client_name }}"
|
|
- " Windows: Import {{ client_name }}.conf in WireGuard GUI"
|
|
- " iOS/Android: Scan QR code with WireGuard app"
|
|
- ""
|
|
- "Test Connection:"
|
|
- " ping {{ wireguard_server_ip }}"
|
|
- " curl -k https://{{ wireguard_server_ip }}:8080 # Traefik Dashboard"
|
|
- ""
|
|
- "========================================="
|
|
|
|
- name: Display QR code
|
|
debug:
|
|
msg: "{{ qr_code_output.stdout_lines }}"
|