From 76f3e10ee411b55537e206e92684ab1fa4fb6284 Mon Sep 17 00:00:00 2001 From: Fabio Scotto di Santolo Date: Tue, 15 Sep 2026 22:38:56 +0200 Subject: [PATCH] Verify WireGuard handshakes and restore Podman networking --- AGENTS.md | 7 ++-- README.md | 15 +++++--- ansible/inventory/host_vars/prometheus.yml | 1 + .../roles/wireguard_overlay/defaults/main.yml | 3 ++ .../roles/wireguard_overlay/tasks/main.yml | 34 +++++++++++++++++++ 5 files changed, 54 insertions(+), 6 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 3bf1f7e..b320cad 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -161,8 +161,11 @@ The dotfile vars follow the same split: `desktop_common_dotfiles` carries mode-i use `10.0.0.2:4533` for Navidrome and `10.0.0.2:8384` for the Syncthing GUI. Syncthing does not use host networking: its GUI, transfer, QUIC and discovery ports are explicitly published only on `10.0.0.2`; native transfer/discovery does not use the HTTP proxy. - `wireguard_overlay` manages the required `wg0` path between Prometheus and Atlas, persists private keys only on their - respective hosts, and exchanges only derived public keys. The initial run must include both hosts. Prometheus - opens `51820/udp`; the Atlas backend role admits service ports only in the WireGuard firewalld zone. + respective hosts, exchanges only derived public keys, and verifies a real peer handshake. The initial run must + include both hosts. Prometheus + opens `51820/udp`; after creating the WireGuard firewalld zone, restore Prometheus' rootful Podman networking with + `podman network reload --all` so the existing proxy stack retains container DNS. The Atlas backend role admits + service ports only in the WireGuard firewalld zone. ## Atlas NAS TODO - Provide the required Vault variables and validate the first remote bootstrap on the real Rocky Linux 9 host. diff --git a/README.md b/README.md index 971aeb6..f69c7ba 100644 --- a/README.md +++ b/README.md @@ -219,13 +219,18 @@ clients use NFSv4 and Windows/WSL clients use SMB; both are restricted to the co For the first run, provide `vault_atlas_admin_password_hash`, `vault_atlas_samba_password`, and `vault_atlas_immich_db_password`. Bootstrap the host through its -existing administrator: +existing administrator. Open `51820/udp` towards Prometheus in the provider firewall first, then +include both WireGuard peers in the same idempotent playbook run: ```bash -ansible-playbook ansible/site.yml --limit atlas \ - -e atlas_connection_username= +ansible-playbook ansible/site.yml --limit prometheus,atlas \ + -e atlas_connection_username= \ + -e atlas_create_pool=true ``` +The explicit pool gate is safe to repeat: the role creates the RAIDZ2 pool only when it is absent. +WireGuard waits for a real peer handshake before the play continues. + `vault_atlas_admin_password_hash` must be an `/etc/shadow`-compatible hash, not a clear-text Cockpit password. Subsequent runs use `atlas_admin_username`. Atlas declares storage, sharing, and its LAN firewall rules enabled. Before the first apply, check the existing pool and mountpoints, LAN subnet, @@ -262,7 +267,9 @@ storage paths from the `zpool` mounted at `/zpool`: music is read-only at containers. The backend role never creates the pool. The separate `wireguard_overlay` role manages `wg0` between Prometheus (`10.0.0.1`) and Atlas (`10.0.0.2`), generating private keys once on their respective hosts and exchanging only public keys through Ansible. Prometheus alone opens -`51820/udp` publicly. Backend ports are admitted only in the WireGuard firewalld zone. +`51820/udp` publicly. When the WireGuard zone is created, Ansible reloads firewalld and immediately +reloads Prometheus' rootful Podman networks so the existing proxy stack retains container DNS and +connectivity. Backend ports are admitted only in the WireGuard firewalld zone. `backend_phase1_start_services` stays false during the application-state transfer, so the first real backend run renders the Quadlets without creating an empty Atlas database. After stopping Navidrome diff --git a/ansible/inventory/host_vars/prometheus.yml b/ansible/inventory/host_vars/prometheus.yml index 078e9c3..747c2a8 100644 --- a/ansible/inventory/host_vars/prometheus.yml +++ b/ansible/inventory/host_vars/prometheus.yml @@ -19,6 +19,7 @@ wireguard_overlay_enabled: true wireguard_address: 10.0.0.1/24 wireguard_listen_port: 51820 wireguard_enable_ipv4_forwarding: true +wireguard_reload_rootful_podman_networks: true wireguard_peers: - name: atlas host: atlas diff --git a/ansible/roles/wireguard_overlay/defaults/main.yml b/ansible/roles/wireguard_overlay/defaults/main.yml index 2021f1c..82a20bd 100644 --- a/ansible/roles/wireguard_overlay/defaults/main.yml +++ b/ansible/roles/wireguard_overlay/defaults/main.yml @@ -10,6 +10,9 @@ wireguard_mtu: 1420 wireguard_firewalld_zone: wireguard wireguard_public_firewalld_zone: public wireguard_enable_ipv4_forwarding: false +wireguard_reload_rootful_podman_networks: false +wireguard_handshake_retries: 12 +wireguard_handshake_delay: 5 wireguard_peers: [] wireguard_packages: - wireguard-tools diff --git a/ansible/roles/wireguard_overlay/tasks/main.yml b/ansible/roles/wireguard_overlay/tasks/main.yml index 3295c35..ff5cdfb 100644 --- a/ansible/roles/wireguard_overlay/tasks/main.yml +++ b/ansible/roles/wireguard_overlay/tasks/main.yml @@ -132,6 +132,20 @@ - wireguard_firewalld_zone_result is changed - not ansible_check_mode + - name: Restore rootful Podman networking after firewalld reload + ansible.builtin.command: + argv: + - podman + - network + - reload + - --all + register: wireguard_podman_network_reload + changed_when: wireguard_podman_network_reload.stdout_lines | length > 0 + when: + - wireguard_firewalld_zone_result is changed + - wireguard_reload_rootful_podman_networks | bool + - not ansible_check_mode + - name: Assign the WireGuard interface to its firewalld zone ansible.posix.firewalld: interface: "{{ wireguard_interface }}" @@ -156,3 +170,23 @@ state: started daemon_reload: true when: not ansible_check_mode + + - name: Apply pending WireGuard handlers before verification + ansible.builtin.meta: flush_handlers + when: not ansible_check_mode + + - name: Wait for every WireGuard peer handshake + ansible.builtin.command: + argv: + - wg + - show + - "{{ wireguard_interface }}" + - latest-handshakes + register: wireguard_latest_handshakes + changed_when: false + retries: "{{ wireguard_handshake_retries }}" + delay: "{{ wireguard_handshake_delay }}" + until: + - wireguard_latest_handshakes.stdout_lines | length == wireguard_peers | length + - wireguard_latest_handshakes.stdout_lines | select('search', '\t0$') | list | length == 0 + when: not ansible_check_mode