From 20bcecbcec82d7def041028ab43d2fc32aeceed0 Mon Sep 17 00:00:00 2001 From: n0mad1k Date: Mon, 9 Mar 2026 15:59:02 -0400 Subject: [PATCH] Harden WireGuard VPN configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add IPv6 ip6tables rules to prevent IPv6 traffic leaks (forwarding was enabled but only IPv4 masquerade existed) - Tighten FORWARD chain: only allow wg0→internet and established return, instead of blanket ACCEPT from wg0 - Scope NAT masquerade to VPN subnet only - Block VPN clients from server-local services (SSH/80/443) via INPUT rules - Set UFW DEFAULT_FORWARD_POLICY=ACCEPT (required for VPN routing; base hardening sets default deny which blocks forwarded packets) - Add SaveConfig = false to prevent runtime state overwriting config - Add reload ufw handler Co-Authored-By: Claude Opus 4.6 --- phantom/playbooks/vpn/main.yml | 5 ++++ phantom/playbooks/vpn/tasks/configure.yml | 33 ++++++++++++++++++++--- phantom/playbooks/vpn/tasks/install.yml | 19 ++++++++----- 3 files changed, 48 insertions(+), 9 deletions(-) diff --git a/phantom/playbooks/vpn/main.yml b/phantom/playbooks/vpn/main.yml index 91d9cdb..a2efe7c 100644 --- a/phantom/playbooks/vpn/main.yml +++ b/phantom/playbooks/vpn/main.yml @@ -18,3 +18,8 @@ - name: Include WireGuard configuration tasks include_tasks: tasks/configure.yml + + handlers: + - name: reload ufw + ufw: + state: reloaded diff --git a/phantom/playbooks/vpn/tasks/configure.yml b/phantom/playbooks/vpn/tasks/configure.yml index 8fb9774..1ae8bc9 100644 --- a/phantom/playbooks/vpn/tasks/configure.yml +++ b/phantom/playbooks/vpn/tasks/configure.yml @@ -24,13 +24,39 @@ SERVER_PRIVKEY=$(cat /etc/wireguard/server_private.key) IFACE={{ primary_interface.stdout | trim }} - cat > /etc/wireguard/wg0.conf << EOF + cat > /etc/wireguard/wg0.conf << 'WGEOF' [Interface] + WGEOF + + # Write dynamic values separately to avoid heredoc variable issues + cat >> /etc/wireguard/wg0.conf << EOF Address = {{ wg_subnet | regex_replace('/\\d+$', '') | regex_replace('\\.[0-9]+$', '.1/24') }} ListenPort = {{ wg_port }} PrivateKey = ${SERVER_PRIVKEY} - PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o ${IFACE} -j MASQUERADE - PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o ${IFACE} -j MASQUERADE + SaveConfig = false + + # IPv4: forward VPN traffic to internet, masquerade source + PostUp = iptables -A FORWARD -i wg0 -o ${IFACE} -j ACCEPT + PostUp = iptables -A FORWARD -i ${IFACE} -o wg0 -m state --state RELATED,ESTABLISHED -j ACCEPT + PostUp = iptables -t nat -A POSTROUTING -o ${IFACE} -s {{ wg_subnet }} -j MASQUERADE + # IPv6: same rules to prevent leaks + PostUp = ip6tables -A FORWARD -i wg0 -o ${IFACE} -j ACCEPT + PostUp = ip6tables -A FORWARD -i ${IFACE} -o wg0 -m state --state RELATED,ESTABLISHED -j ACCEPT + PostUp = ip6tables -t nat -A POSTROUTING -o ${IFACE} -j MASQUERADE + # Block VPN clients from accessing server-local services (except DNS if local) + PostUp = iptables -I INPUT -i wg0 -p tcp --dport 22 -j DROP + PostUp = iptables -I INPUT -i wg0 -p tcp --dport 80 -j DROP + PostUp = iptables -I INPUT -i wg0 -p tcp --dport 443 -j DROP + + PostDown = iptables -D FORWARD -i wg0 -o ${IFACE} -j ACCEPT + PostDown = iptables -D FORWARD -i ${IFACE} -o wg0 -m state --state RELATED,ESTABLISHED -j ACCEPT + PostDown = iptables -t nat -D POSTROUTING -o ${IFACE} -s {{ wg_subnet }} -j MASQUERADE + PostDown = ip6tables -D FORWARD -i wg0 -o ${IFACE} -j ACCEPT + PostDown = ip6tables -D FORWARD -i ${IFACE} -o wg0 -m state --state RELATED,ESTABLISHED -j ACCEPT + PostDown = ip6tables -t nat -D POSTROUTING -o ${IFACE} -j MASQUERADE + PostDown = iptables -D INPUT -i wg0 -p tcp --dport 22 -j DROP + PostDown = iptables -D INPUT -i wg0 -p tcp --dport 80 -j DROP + PostDown = iptables -D INPUT -i wg0 -p tcp --dport 443 -j DROP EOF @@ -38,6 +64,7 @@ CLIENT_PUBKEY=$(cat /etc/wireguard/clients/client${i}_public.key) CLIENT_PSK=$(cat /etc/wireguard/clients/client${i}_psk.key) cat >> /etc/wireguard/wg0.conf << EOF + [Peer] # Client ${i} PublicKey = ${CLIENT_PUBKEY} diff --git a/phantom/playbooks/vpn/tasks/install.yml b/phantom/playbooks/vpn/tasks/install.yml index b5220c3..c764f2a 100644 --- a/phantom/playbooks/vpn/tasks/install.yml +++ b/phantom/playbooks/vpn/tasks/install.yml @@ -24,6 +24,19 @@ sysctl_set: true reload: true +- name: Set UFW default forward policy to accept (required for VPN routing) + lineinfile: + path: /etc/default/ufw + regexp: '^DEFAULT_FORWARD_POLICY=' + line: 'DEFAULT_FORWARD_POLICY="ACCEPT"' + notify: reload ufw + +- name: Allow WireGuard port through UFW + ufw: + rule: allow + port: "{{ wg_port }}" + proto: udp + - name: Generate server private key shell: wg genkey register: wg_server_privkey @@ -46,9 +59,3 @@ shell: "echo '{{ server_privkey_content.content | b64decode | trim }}' | wg pubkey" register: wg_server_pubkey changed_when: false - -- name: Allow WireGuard port through UFW - ufw: - rule: allow - port: "{{ wg_port }}" - proto: udp