feat: improve WireGuard client management and framework initialization
- Improve WireGuard client IP calculation logic (find next available IP) - Add local wireguard-clients directory for storing client configs - Integrate Redis pool into CacheInitializer - Improve ContainerBootstrapper with better imports and Redis pool - Add monitoring role tags for better task organization - Update WireGuard documentation - Store generated WireGuard client configs locally
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
wireguard_config_path: "/etc/wireguard"
|
||||
wireguard_config_file: "{{ wireguard_config_path }}/{{ wireguard_interface }}.conf"
|
||||
wireguard_client_configs_path: "/etc/wireguard/clients"
|
||||
wireguard_local_client_configs_dir: "{{ playbook_dir }}/../wireguard-clients"
|
||||
|
||||
pre_tasks:
|
||||
- name: Set WireGuard network
|
||||
@@ -60,14 +61,28 @@
|
||||
set_fact:
|
||||
server_vpn_ip: "{{ (wireguard_server_config_read.content | b64decode | regex_search('Address = ([0-9.]+)', '\\1')) | first | default('10.8.0.1') }}"
|
||||
|
||||
- name: Count existing clients in config
|
||||
- name: Extract WireGuard server IP octets
|
||||
set_fact:
|
||||
existing_clients_count: "{{ (wireguard_server_config_read.content | b64decode | regex_findall('\\[Peer\\]') | length) }}"
|
||||
wireguard_server_ip_octets: "{{ server_vpn_ip.split('.') }}"
|
||||
when: client_ip == ""
|
||||
|
||||
- name: Gather existing client addresses
|
||||
set_fact:
|
||||
existing_client_ips: "{{ (wireguard_server_config_read.content | b64decode | regex_findall('AllowedIPs = ([0-9A-Za-z.]+)/32', '\\1')) }}"
|
||||
when: client_ip == ""
|
||||
|
||||
- name: Calculate client IP if not provided
|
||||
vars:
|
||||
existing_last_octets: "{{ (existing_client_ips | default([])) | map('regex_replace', '^(?:\\d+\\.\\d+\\.\\d+\\.)', '') | select('match', '^[0-9]+$') | map('int') | list }}"
|
||||
server_last_octet: "{{ wireguard_server_ip_octets[3] | int }}"
|
||||
next_octet_candidate: "{{ (existing_last_octets + [server_last_octet]) | map('int') | list | max + 1 if (existing_last_octets + [server_last_octet]) else server_last_octet + 1 }}"
|
||||
set_fact:
|
||||
client_ip: "{{ server_vpn_ip | regex_replace('^(\\d+\\.\\d+\\.\\d+\\.)\\d+$', '\\1') }}{{ (server_vpn_ip | regex_replace('^(\\d+\\.\\d+\\.\\d+\\.)(\\d+)', '\\2') | int) + (existing_clients_count | default(1)) | int }}"
|
||||
client_ip: "{{ [
|
||||
wireguard_server_ip_octets[0],
|
||||
wireguard_server_ip_octets[1],
|
||||
wireguard_server_ip_octets[2],
|
||||
next_octet_candidate
|
||||
] | join('.') }}"
|
||||
when: client_ip == ""
|
||||
|
||||
- name: Generate client private key
|
||||
@@ -84,12 +99,6 @@
|
||||
changed_when: false
|
||||
no_log: yes
|
||||
|
||||
- name: Check if client already exists in config
|
||||
shell: "grep -q '{{ client_name }}' {{ wireguard_config_file }} || echo 'not found'"
|
||||
register: client_exists_check
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- name: Add client to WireGuard server config
|
||||
blockinfile:
|
||||
path: "{{ wireguard_config_file }}"
|
||||
@@ -99,7 +108,7 @@
|
||||
PublicKey = {{ client_public_key.stdout }}
|
||||
AllowedIPs = {{ client_ip }}/32
|
||||
marker: "# {mark} ANSIBLE MANAGED BLOCK - Client: {{ client_name }}"
|
||||
when: "'not found' in client_exists_check.stdout"
|
||||
register: wireguard_client_block
|
||||
|
||||
- name: Ensure client configs directory exists
|
||||
file:
|
||||
@@ -109,6 +118,15 @@
|
||||
owner: root
|
||||
group: root
|
||||
|
||||
- name: Ensure local client configs directory exists
|
||||
file:
|
||||
path: "{{ wireguard_local_client_configs_dir }}"
|
||||
state: directory
|
||||
mode: '0700'
|
||||
delegate_to: localhost
|
||||
become: no
|
||||
run_once: true
|
||||
|
||||
- name: Get server public key
|
||||
shell: "cat {{ wireguard_config_path }}/{{ wireguard_interface }}_private.key | wg pubkey"
|
||||
register: server_public_key_cmd
|
||||
@@ -124,6 +142,20 @@
|
||||
owner: root
|
||||
group: root
|
||||
|
||||
- name: Download client configuration to control machine
|
||||
fetch:
|
||||
src: "{{ wireguard_client_configs_path }}/{{ client_name }}.conf"
|
||||
dest: "{{ wireguard_local_client_configs_dir }}/{{ client_name }}.conf"
|
||||
flat: yes
|
||||
mode: '0600'
|
||||
|
||||
- name: Ensure local client configuration has strict permissions
|
||||
file:
|
||||
path: "{{ wireguard_local_client_configs_dir }}/{{ client_name }}.conf"
|
||||
mode: '0600'
|
||||
delegate_to: localhost
|
||||
become: no
|
||||
|
||||
- name: Read WireGuard server config to find server IP
|
||||
slurp:
|
||||
src: "{{ wireguard_config_file }}"
|
||||
@@ -133,7 +165,7 @@
|
||||
systemd:
|
||||
name: "wg-quick@{{ wireguard_interface }}"
|
||||
state: restarted
|
||||
when: "'not found' in client_exists_check.stdout"
|
||||
when: wireguard_client_block.changed
|
||||
|
||||
- name: Display client configuration
|
||||
debug:
|
||||
@@ -144,6 +176,9 @@
|
||||
|
||||
Client Configuration File:
|
||||
{{ wireguard_client_configs_path }}/{{ client_name }}.conf
|
||||
|
||||
Local Copy:
|
||||
{{ wireguard_local_client_configs_dir }}/{{ client_name }}.conf
|
||||
|
||||
Client IP: {{ client_ip }}
|
||||
Server Endpoint: {{ server_external_ip_content }}:{{ wireguard_port }}
|
||||
@@ -166,4 +201,4 @@
|
||||
- name: Display QR code
|
||||
debug:
|
||||
msg: "{{ qr_code.stdout }}"
|
||||
when: qr_code.rc == 0
|
||||
when: qr_code.rc == 0
|
||||
|
||||
@@ -3,3 +3,4 @@ monitoring_stack_path: "{{ stacks_base_path }}/monitoring"
|
||||
monitoring_wait_timeout: "{{ wait_timeout | default(60) }}"
|
||||
monitoring_env_template: "{{ role_path }}/../../templates/monitoring.env.j2"
|
||||
monitoring_vault_file: "{{ role_path }}/../../secrets/production.vault.yml"
|
||||
monitoring_vpn_ip_whitelist: "{{ wireguard_network_default | default('10.8.0.0/24') }}"
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
delegate_to: localhost
|
||||
register: monitoring_vault_stat
|
||||
become: no
|
||||
tags:
|
||||
- monitoring
|
||||
|
||||
- name: Optionally load monitoring secrets from vault
|
||||
include_vars:
|
||||
@@ -13,16 +15,22 @@
|
||||
no_log: yes
|
||||
delegate_to: localhost
|
||||
become: no
|
||||
tags:
|
||||
- monitoring
|
||||
|
||||
- name: Set Grafana admin password from vault or generate
|
||||
set_fact:
|
||||
grafana_admin_password: "{{ vault_grafana_admin_password | default(lookup('password', '/dev/null length=25 chars=ascii_letters,digits')) }}"
|
||||
no_log: yes
|
||||
tags:
|
||||
- monitoring
|
||||
|
||||
- name: Set Prometheus password from vault or generate
|
||||
set_fact:
|
||||
prometheus_password: "{{ vault_prometheus_password | default(lookup('password', '/dev/null length=25 chars=ascii_letters,digits')) }}"
|
||||
no_log: yes
|
||||
tags:
|
||||
- monitoring
|
||||
|
||||
- name: Generate Prometheus BasicAuth hash
|
||||
shell: |
|
||||
@@ -30,17 +38,23 @@
|
||||
register: prometheus_auth_hash
|
||||
changed_when: false
|
||||
no_log: yes
|
||||
tags:
|
||||
- monitoring
|
||||
|
||||
- name: Set Prometheus BasicAuth string
|
||||
set_fact:
|
||||
prometheus_auth: "admin:{{ prometheus_auth_hash.stdout }}"
|
||||
no_log: yes
|
||||
tags:
|
||||
- monitoring
|
||||
|
||||
- name: Ensure monitoring stack directory exists
|
||||
file:
|
||||
path: "{{ monitoring_stack_path }}"
|
||||
state: directory
|
||||
mode: '0755'
|
||||
tags:
|
||||
- monitoring
|
||||
|
||||
- name: Create monitoring stack .env file
|
||||
template:
|
||||
@@ -50,6 +64,8 @@
|
||||
group: "{{ ansible_user }}"
|
||||
mode: '0600'
|
||||
no_log: yes
|
||||
tags:
|
||||
- monitoring
|
||||
|
||||
- name: Deploy Monitoring stack
|
||||
community.docker.docker_compose_v2:
|
||||
@@ -57,12 +73,18 @@
|
||||
state: present
|
||||
pull: always
|
||||
register: monitoring_compose_result
|
||||
tags:
|
||||
- monitoring
|
||||
|
||||
- name: Wait for Monitoring to be ready
|
||||
wait_for:
|
||||
timeout: "{{ monitoring_wait_timeout }}"
|
||||
when: monitoring_compose_result.changed
|
||||
tags:
|
||||
- monitoring
|
||||
|
||||
- name: Record monitoring deployment facts
|
||||
set_fact:
|
||||
monitoring_stack_changed: "{{ monitoring_compose_result.changed | default(false) }}"
|
||||
tags:
|
||||
- monitoring
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
# Domain Configuration
|
||||
DOMAIN={{ app_domain }}
|
||||
|
||||
# VPN Access Control
|
||||
MONITORING_VPN_IP_WHITELIST={{ monitoring_vpn_ip_whitelist }}
|
||||
|
||||
# Grafana Configuration
|
||||
GRAFANA_ADMIN_USER={{ grafana_admin_user | default('admin') }}
|
||||
GRAFANA_ADMIN_PASSWORD={{ grafana_admin_password }}
|
||||
@@ -18,4 +21,4 @@ GRAFANA_PLUGINS={{ grafana_plugins | default('') }}
|
||||
# Prometheus BasicAuth
|
||||
# Format: username:hashed_password
|
||||
# Note: Dollar signs are escaped for Docker Compose ($$ becomes $)
|
||||
PROMETHEUS_AUTH={{ prometheus_auth | replace('$', '$$') }}
|
||||
PROMETHEUS_AUTH={{ prometheus_auth | replace('$', '$$') }}
|
||||
|
||||
27
deployment/ansible/wireguard-clients/grafana-test.conf
Normal file
27
deployment/ansible/wireguard-clients/grafana-test.conf
Normal file
@@ -0,0 +1,27 @@
|
||||
# WireGuard Client Configuration for grafana-test
|
||||
# Generated by Ansible - DO NOT EDIT MANUALLY
|
||||
|
||||
[Interface]
|
||||
# Client private key
|
||||
PrivateKey = uMhNKh+Wi0aykTnazfSJD6l7Wc2V1Pe+7rFtFcnfynw=
|
||||
|
||||
# Client IP address in VPN network
|
||||
Address = 10.8.0.4/24
|
||||
|
||||
# DNS server (optional)
|
||||
DNS = 1.1.1.1, 8.8.8.8
|
||||
|
||||
[Peer]
|
||||
# Server public key
|
||||
PublicKey = hT3OCWZ6ElX79YdAdexSsZnbWLzRM/5szk+XNEBUaS8=
|
||||
|
||||
# Server endpoint
|
||||
Endpoint = 94.16.110.151:51820
|
||||
|
||||
# Allowed IPs (routes through VPN)
|
||||
# IMPORTANT: Only VPN network is routed through VPN by default
|
||||
# SSH access via normal IP (94.16.110.151) remains available
|
||||
AllowedIPs = 10.8.0.0/24
|
||||
|
||||
# Keep connection alive
|
||||
PersistentKeepalive = 25
|
||||
27
deployment/ansible/wireguard-clients/mikepc.conf
Normal file
27
deployment/ansible/wireguard-clients/mikepc.conf
Normal file
@@ -0,0 +1,27 @@
|
||||
# WireGuard Client Configuration for mikepc
|
||||
# Generated by Ansible - DO NOT EDIT MANUALLY
|
||||
|
||||
[Interface]
|
||||
# Client private key
|
||||
PrivateKey = wFxqFHe4R8IVzkAQSHaAwVfwQ2rfm5vCySZMpvPsVUQ=
|
||||
|
||||
# Client IP address in VPN network
|
||||
Address = 10.8.0.3/24
|
||||
|
||||
# DNS server (optional)
|
||||
DNS = 1.1.1.1, 8.8.8.8
|
||||
|
||||
[Peer]
|
||||
# Server public key
|
||||
PublicKey = hT3OCWZ6ElX79YdAdexSsZnbWLzRM/5szk+XNEBUaS8=
|
||||
|
||||
# Server endpoint
|
||||
Endpoint = 94.16.110.151:51820
|
||||
|
||||
# Allowed IPs (routes through VPN)
|
||||
# IMPORTANT: Only VPN network is routed through VPN by default
|
||||
# SSH access via normal IP (94.16.110.151) remains available
|
||||
AllowedIPs = 10.8.0.0/24
|
||||
|
||||
# Keep connection alive
|
||||
PersistentKeepalive = 25
|
||||
@@ -75,6 +75,8 @@ services:
|
||||
- "traefik.http.routers.grafana.entrypoints=websecure"
|
||||
- "traefik.http.routers.grafana.tls=true"
|
||||
- "traefik.http.routers.grafana.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.middlewares.grafana-vpn-only.ipwhitelist.sourcerange=${MONITORING_VPN_IP_WHITELIST:-10.8.0.0/24}"
|
||||
- "traefik.http.routers.grafana.middlewares=grafana-vpn-only"
|
||||
- "traefik.http.services.grafana.loadbalancer.server.port=3000"
|
||||
depends_on:
|
||||
prometheus:
|
||||
|
||||
Reference in New Issue
Block a user