From ec12de4bc29476f7733a2e5abec91687ee8985ad Mon Sep 17 00:00:00 2001 From: Ahmed Abdelhalim Date: Wed, 3 Sep 2025 03:46:34 +0200 Subject: Revert "Refactor: rename wireguard_gateway to gateway" This reverts commit fdd0b5b58f0ebd39ad05e2dcb17faa6603145f97. --- group_vars/all.yml | Bin 1601 -> 1605 bytes host_vars/rpi5.local.yml | Bin 718 -> 717 bytes host_vars/rpi5.local.yml.example | 2 +- host_vars/ubuntu.local.yml | Bin 203 -> 528 bytes molecule/default/converge.yml | 2 +- roles/gateway/README.md | 98 --------------------- roles/gateway/defaults/main.yml | 2 - roles/gateway/handlers/main.yml | 6 -- roles/gateway/meta/argument_specs.yml | 10 --- roles/gateway/meta/main.yml | 20 ----- roles/gateway/tasks/main.yml | 112 ------------------------ roles/wireguard_gateway/README.md | 98 +++++++++++++++++++++ roles/wireguard_gateway/defaults/main.yml | 2 + roles/wireguard_gateway/handlers/main.yml | 6 ++ roles/wireguard_gateway/meta/argument_specs.yml | 10 +++ roles/wireguard_gateway/meta/main.yml | 20 +++++ roles/wireguard_gateway/tasks/main.yml | 112 ++++++++++++++++++++++++ site.yml | 2 +- 18 files changed, 251 insertions(+), 251 deletions(-) delete mode 100644 roles/gateway/README.md delete mode 100644 roles/gateway/defaults/main.yml delete mode 100644 roles/gateway/handlers/main.yml delete mode 100644 roles/gateway/meta/argument_specs.yml delete mode 100644 roles/gateway/meta/main.yml delete mode 100644 roles/gateway/tasks/main.yml create mode 100644 roles/wireguard_gateway/README.md create mode 100644 roles/wireguard_gateway/defaults/main.yml create mode 100644 roles/wireguard_gateway/handlers/main.yml create mode 100644 roles/wireguard_gateway/meta/argument_specs.yml create mode 100644 roles/wireguard_gateway/meta/main.yml create mode 100644 roles/wireguard_gateway/tasks/main.yml diff --git a/group_vars/all.yml b/group_vars/all.yml index 711e9028..9260503e 100644 Binary files a/group_vars/all.yml and b/group_vars/all.yml differ diff --git a/host_vars/rpi5.local.yml b/host_vars/rpi5.local.yml index 4a1dcc5c..80e6dc4d 100644 Binary files a/host_vars/rpi5.local.yml and b/host_vars/rpi5.local.yml differ diff --git a/host_vars/rpi5.local.yml.example b/host_vars/rpi5.local.yml.example index 435307ca..1fc19dd1 100644 --- a/host_vars/rpi5.local.yml.example +++ b/host_vars/rpi5.local.yml.example @@ -16,7 +16,7 @@ pihole_dhcp_hosts: - "ff:ff:ff:ff:ff:fe, 10.0.0.252,TV" - "ff:ff:ff:ff:ff:ff, 10.0.0.253,Printer" -gateway_enabled: true +wireguard_gateway_enabled: true wireguard_autostart_connection: "protonvpn-us-1" wireguard_connections: protonvpn-us-1: | diff --git a/host_vars/ubuntu.local.yml b/host_vars/ubuntu.local.yml index 4b3a00d2..8fc0e6f0 100644 Binary files a/host_vars/ubuntu.local.yml and b/host_vars/ubuntu.local.yml differ diff --git a/molecule/default/converge.yml b/molecule/default/converge.yml index 36eead7b..039fc920 100644 --- a/molecule/default/converge.yml +++ b/molecule/default/converge.yml @@ -44,7 +44,7 @@ - role: "docker" - role: "podman" - role: "wireguard" - - role: "gateway" + - role: "wireguard_gateway" - role: "pihole" when: - lookup('ansible.builtin.env', 'MOLECULE_DISTRO') == 'ubuntu' or diff --git a/roles/gateway/README.md b/roles/gateway/README.md deleted file mode 100644 index 54c45430..00000000 --- a/roles/gateway/README.md +++ /dev/null @@ -1,98 +0,0 @@ -# Ansible Role: gateway - -This role configures a Linux host as a gateway, -routing all traffic from local network clients through. - -## Role Variables - -- `gateway_enabled`: Boolean flag to enable/disable gateway functionality (default: `false`) - -## What This Role Does - -When `gateway_enabled` is `true`, the role: - -- Sets `net.ipv4.ip_forward=1` and `net.ipv6.conf.all.forwarding=1` in `/etc/sysctl.conf` -- Creates custom routing table (100) to route traffic through VPN -- Routes IPv4 and IPv6 traffic from local subnet through VPN interface -- Allows traffic forwarding and established connections - -When `gateway_enabled` is `false`, the role: - -- Removes all routing rules and iptables configurations -- Disables IP forwarding in sysctl configuration -- Cleans up custom routing tables - -## Example Configuration - -```yaml -# In host_vars/rpi5.local.yml -gateway_enabled: true -wireguard_autostart_connection: "protonvpn-us1" - -# WireGuard connection configuration -wireguard_connections: - protonvpn-us1: | - [Interface] - PrivateKey = your_private_key_here - Address = 10.2.0.2/32 - DNS = 10.2.0.1 - - [Peer] - PublicKey = server_public_key - AllowedIPs = 0.0.0.0/0, ::/0 - Endpoint = vpn.example.com:51820 -``` - -## Client Configuration - -For client machines to route through the VPN gateway: - -1. **IPv4**: Set gateway to VPN gateway host's IP -2. **IPv6**: Set IPv6 gateway to VPN gateway host's IPv6 address -3. **Manual network config**: Disable auto-configuration to use custom gateway - -Example client network configuration: - -```yaml -network_ipv4_address: "192.168.1.100" -network_ipv4_gateway: "192.168.1.254" # VPN gateway host -network_ipv6_address: "2001:db8::100/64" -network_ipv6_gateway: "2001:db8::254" # VPN gateway host -``` - -## Technical Details - -### Routing Rules Created - -```bash -# Policy routing rules (priority 200) -ip rule add iif eth0 table 100 priority 200 -ip -6 rule add iif eth0 table 100 priority 200 - -# Custom routing table (table 100) -ip route add default dev wg-connection table 100 -ip -6 route add default dev wg-connection table 100 -``` - -### iptables Rules Created - -```bash -# IPv4 NAT masquerading -iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o wg-connection -j MASQUERADE - -# IPv4 FORWARD rules -iptables -A FORWARD -s 192.168.1.0/24 -j ACCEPT -iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT - -# IPv6 equivalent rules -ip6tables -t nat -A POSTROUTING -s 2001:db8::/64 -o wg-connection -j MASQUERADE -ip6tables -A FORWARD -s 2001:db8::/64 -j ACCEPT -ip6tables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -``` - -## Troubleshooting - -- **Check VPN connection**: `sudo wg show` should show active connection -- **Verify routing**: `ip rule show` and `ip route show table 100` -- **Test connectivity**: `curl ip.me` should show VPN IP from client machines -- **Check iptables**: `sudo iptables -t nat -L -n -v` should show masquerading rules diff --git a/roles/gateway/defaults/main.yml b/roles/gateway/defaults/main.yml deleted file mode 100644 index 8cddb272..00000000 --- a/roles/gateway/defaults/main.yml +++ /dev/null @@ -1,2 +0,0 @@ ---- -gateway_enabled: false diff --git a/roles/gateway/handlers/main.yml b/roles/gateway/handlers/main.yml deleted file mode 100644 index 4b7cb2f2..00000000 --- a/roles/gateway/handlers/main.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -- name: "Reload sysctl" - become: true - ansible.builtin.command: - cmd: "sysctl -p" - changed_when: false diff --git a/roles/gateway/meta/argument_specs.yml b/roles/gateway/meta/argument_specs.yml deleted file mode 100644 index d6520641..00000000 --- a/roles/gateway/meta/argument_specs.yml +++ /dev/null @@ -1,10 +0,0 @@ ---- -argument_specs: - main: - description: "Configure the PI as a network gateway forcing all traffic through it (or through active VPN on it)" - author: "a14m" - options: - gateway_enabled: - description: "Toggle flag for enabling/disabling network gateway configurations" - type: "bool" - default: false diff --git a/roles/gateway/meta/main.yml b/roles/gateway/meta/main.yml deleted file mode 100644 index 36df4aad..00000000 --- a/roles/gateway/meta/main.yml +++ /dev/null @@ -1,20 +0,0 @@ ---- -dependencies: - - "wireguard" - -galaxy_info: - author: "a14m" - description: "Install and configure WireGuard VPN as a network gateway" - company: "kartoffeln.work GmbH." - license: "MIT" - min_ansible_version: "2.18" - platforms: - - name: "ArchLinux" - versions: - - "all" - - name: "Ubuntu" - versions: - - "noble" - - name: "Debian" - versions: - - "bookworm" diff --git a/roles/gateway/tasks/main.yml b/roles/gateway/tasks/main.yml deleted file mode 100644 index f9ccd4cb..00000000 --- a/roles/gateway/tasks/main.yml +++ /dev/null @@ -1,112 +0,0 @@ ---- -- name: "Ensure iptables are installed" - become: true - ansible.builtin.package: - name: "iptables" - state: "present" - -- name: "Configure IP forwarding" - become: true - ansible.builtin.blockinfile: - path: "/etc/sysctl.conf" - state: "{{ 'present' if gateway_enabled else 'absent' }}" - prepend_newline: true - append_newline: true - marker: "# ==== {mark} ANSIBLE GATEWAY CONFIG" - create: true - mode: "0644" - block: | - net.ipv4.ip_forward=1 - net.ipv6.conf.all.forwarding=1 - notify: "Reload sysctl" - -# IPv4 iptables rules -- name: "Add IPv4 NAT masquerading for traffic through internet" - become: true - ansible.builtin.iptables: - table: "nat" - chain: "POSTROUTING" - source: "{{ (ansible_default_ipv4.address.split('.')[0:3] | join('.')) }}.0/24" - out_interface: "{{ ansible_default_ipv4.interface }}" - jump: "MASQUERADE" - comment: "NAT local subnet traffic through internet" - state: "present" - -- name: "Add IPv4 NAT masquerading for traffic through VPN" - become: true - ansible.builtin.iptables: - table: "nat" - chain: "POSTROUTING" - source: "{{ (ansible_default_ipv4.address.split('.')[0:3] | join('.')) }}.0/24" - out_interface: "{{ item }}" - jump: "MASQUERADE" - comment: "NAT local subnet traffic through VPN" - state: "{{ 'present' if gateway_enabled else 'absent' }}" - with_items: "{{ wireguard_connections }}" - -- name: "Add IPv4 FORWARD rule to accept traffic from local subnet" - become: true - ansible.builtin.iptables: - chain: "FORWARD" - source: "{{ (ansible_default_ipv4.address.split('.')[0:3] | join('.')) }}.0/24" - jump: "ACCEPT" - comment: "Allow forwarding from local subnet" - state: "{{ 'present' if gateway_enabled else 'absent' }}" - -- name: "Add IPv4 FORWARD rule to accept established connections" - become: true - ansible.builtin.iptables: - chain: "FORWARD" - match: "conntrack" - ctstate: "RELATED,ESTABLISHED" - jump: "ACCEPT" - comment: "Allow established connections" - state: "{{ 'present' if gateway_enabled else 'absent' }}" - -# IPv6 iptables rules -- name: "Add IPv6 NAT masquerading for traffic through internet" - become: true - ansible.builtin.iptables: - table: "nat" - chain: "POSTROUTING" - source: "{{ (ansible_default_ipv6.address.split(':')[:4] | join(':')) + '::/64' }}" - out_interface: "{{ ansible_default_ipv6.interface }}" - jump: "MASQUERADE" - comment: "NAT IPv6 local subnet traffic through internet" - ip_version: "ipv6" - state: "present" - when: ansible_default_ipv6.address is defined - -- name: "Add IPv6 NAT masquerading for traffic through VPN" - become: true - ansible.builtin.iptables: - table: "nat" - chain: "POSTROUTING" - source: "{{ (ansible_default_ipv6.address.split(':')[:4] | join(':')) + '::/64' }}" - out_interface: "{{ item }}" - jump: "MASQUERADE" - comment: "NAT IPv6 local subnet traffic through VPN" - ip_version: "ipv6" - state: "{{ 'present' if gateway_enabled else 'absent' }}" - with_items: "{{ wireguard_connections }}" - -- name: "Add IPv6 FORWARD rule to accept traffic from local subnet" - become: true - ansible.builtin.iptables: - chain: "FORWARD" - source: "{{ (ansible_default_ipv6.address.split(':')[:4] | join(':')) + '::/64' }}" - jump: "ACCEPT" - comment: "Allow IPv6 forwarding from local subnet" - ip_version: "ipv6" - state: "{{ 'present' if gateway_enabled else 'absent' }}" - -- name: "Add IPv6 FORWARD rule to accept established connections" - become: true - ansible.builtin.iptables: - chain: "FORWARD" - match: "conntrack" - ctstate: "RELATED,ESTABLISHED" - jump: "ACCEPT" - comment: "Allow IPv6 established connections" - ip_version: "ipv6" - state: "{{ 'present' if gateway_enabled else 'absent' }}" diff --git a/roles/wireguard_gateway/README.md b/roles/wireguard_gateway/README.md new file mode 100644 index 00000000..06c3ceb7 --- /dev/null +++ b/roles/wireguard_gateway/README.md @@ -0,0 +1,98 @@ +# Ansible Role: wireguard_gateway + +This role configures a Linux host as a WireGuard VPN gateway, +routing all traffic from local network clients through the VPN connection. + +## Role Variables + +- `wireguard_gateway_enabled`: Boolean flag to enable/disable gateway functionality (default: `false`) + +## What This Role Does + +When `wireguard_gateway_enabled` is `true`, the role: + +- Sets `net.ipv4.ip_forward=1` and `net.ipv6.conf.all.forwarding=1` in `/etc/sysctl.conf` +- Creates custom routing table (100) to route traffic through VPN +- Routes IPv4 and IPv6 traffic from local subnet through VPN interface +- Allows traffic forwarding and established connections + +When `wireguard_gateway_enabled` is `false`, the role: + +- Removes all routing rules and iptables configurations +- Disables IP forwarding in sysctl configuration +- Cleans up custom routing tables + +## Example Configuration + +```yaml +# In host_vars/gateway.yml +wireguard_gateway_enabled: true +wireguard_autostart_connection: "protonvpn-us-1" + +# WireGuard connection configuration +wireguard_connections: + protonvpn-us-1: | + [Interface] + PrivateKey = your_private_key_here + Address = 10.2.0.2/32 + DNS = 10.2.0.1 + + [Peer] + PublicKey = server_public_key + AllowedIPs = 0.0.0.0/0, ::/0 + Endpoint = vpn.example.com:51820 +``` + +## Client Configuration + +For client machines to route through the VPN gateway: + +1. **IPv4**: Set gateway to VPN gateway host's IP +2. **IPv6**: Set IPv6 gateway to VPN gateway host's IPv6 address +3. **Manual network config**: Disable auto-configuration to use custom gateway + +Example client network configuration: + +```yaml +network_ipv4_address: "192.168.1.100" +network_ipv4_gateway: "192.168.1.254" # VPN gateway host +network_ipv6_address: "2001:db8::100/64" +network_ipv6_gateway: "2001:db8::254" # VPN gateway host +``` + +## Technical Details + +### Routing Rules Created + +```bash +# Policy routing rules (priority 200) +ip rule add iif eth0 table 100 priority 200 +ip -6 rule add iif eth0 table 100 priority 200 + +# Custom routing table (table 100) +ip route add default dev wg-connection table 100 +ip -6 route add default dev wg-connection table 100 +``` + +### iptables Rules Created + +```bash +# IPv4 NAT masquerading +iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o wg-connection -j MASQUERADE + +# IPv4 FORWARD rules +iptables -A FORWARD -s 192.168.1.0/24 -j ACCEPT +iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT + +# IPv6 equivalent rules +ip6tables -t nat -A POSTROUTING -s 2001:db8::/64 -o wg-connection -j MASQUERADE +ip6tables -A FORWARD -s 2001:db8::/64 -j ACCEPT +ip6tables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT +``` + +## Troubleshooting + +- **Check VPN connection**: `sudo wg show` should show active connection +- **Verify routing**: `ip rule show` and `ip route show table 100` +- **Test connectivity**: `curl ip.me` should show VPN IP from client machines +- **Check iptables**: `sudo iptables -t nat -L -n -v` should show masquerading rules diff --git a/roles/wireguard_gateway/defaults/main.yml b/roles/wireguard_gateway/defaults/main.yml new file mode 100644 index 00000000..0086e118 --- /dev/null +++ b/roles/wireguard_gateway/defaults/main.yml @@ -0,0 +1,2 @@ +--- +wireguard_gateway_enabled: false diff --git a/roles/wireguard_gateway/handlers/main.yml b/roles/wireguard_gateway/handlers/main.yml new file mode 100644 index 00000000..4b7cb2f2 --- /dev/null +++ b/roles/wireguard_gateway/handlers/main.yml @@ -0,0 +1,6 @@ +--- +- name: "Reload sysctl" + become: true + ansible.builtin.command: + cmd: "sysctl -p" + changed_when: false diff --git a/roles/wireguard_gateway/meta/argument_specs.yml b/roles/wireguard_gateway/meta/argument_specs.yml new file mode 100644 index 00000000..23f755b9 --- /dev/null +++ b/roles/wireguard_gateway/meta/argument_specs.yml @@ -0,0 +1,10 @@ +--- +argument_specs: + main: + description: "Configure WireGuard VPN as a network gateway" + author: "a14m" + options: + wireguard_gateway_enabled: + description: "Toggle flag for enabling/disabling network gateway configurations" + type: "bool" + default: false diff --git a/roles/wireguard_gateway/meta/main.yml b/roles/wireguard_gateway/meta/main.yml new file mode 100644 index 00000000..36df4aad --- /dev/null +++ b/roles/wireguard_gateway/meta/main.yml @@ -0,0 +1,20 @@ +--- +dependencies: + - "wireguard" + +galaxy_info: + author: "a14m" + description: "Install and configure WireGuard VPN as a network gateway" + company: "kartoffeln.work GmbH." + license: "MIT" + min_ansible_version: "2.18" + platforms: + - name: "ArchLinux" + versions: + - "all" + - name: "Ubuntu" + versions: + - "noble" + - name: "Debian" + versions: + - "bookworm" diff --git a/roles/wireguard_gateway/tasks/main.yml b/roles/wireguard_gateway/tasks/main.yml new file mode 100644 index 00000000..c33a49bf --- /dev/null +++ b/roles/wireguard_gateway/tasks/main.yml @@ -0,0 +1,112 @@ +--- +- name: "Ensure iptables are installed" + become: true + ansible.builtin.package: + name: "iptables" + state: "present" + +- name: "Configure IP forwarding" + become: true + ansible.builtin.blockinfile: + path: "/etc/sysctl.conf" + state: "{{ 'present' if wireguard_gateway_enabled else 'absent' }}" + prepend_newline: true + append_newline: true + marker: "# ==== {mark} ANSIBLE WIREGUARD GATEWAY CONFIG" + create: true + mode: "0644" + block: | + net.ipv4.ip_forward=1 + net.ipv6.conf.all.forwarding=1 + notify: "Reload sysctl" + +# IPv4 iptables rules +- name: "Add IPv4 NAT masquerading for traffic through internet" + become: true + ansible.builtin.iptables: + table: "nat" + chain: "POSTROUTING" + source: "{{ (ansible_default_ipv4.address.split('.')[0:3] | join('.')) }}.0/24" + out_interface: "{{ ansible_default_ipv4.interface }}" + jump: "MASQUERADE" + comment: "NAT local subnet traffic through internet" + state: "present" + +- name: "Add IPv4 NAT masquerading for traffic through VPN" + become: true + ansible.builtin.iptables: + table: "nat" + chain: "POSTROUTING" + source: "{{ (ansible_default_ipv4.address.split('.')[0:3] | join('.')) }}.0/24" + out_interface: "{{ item }}" + jump: "MASQUERADE" + comment: "NAT local subnet traffic through VPN" + state: "{{ 'present' if wireguard_gateway_enabled else 'absent' }}" + with_items: "{{ wireguard_connections }}" + +- name: "Add IPv4 FORWARD rule to accept traffic from local subnet" + become: true + ansible.builtin.iptables: + chain: "FORWARD" + source: "{{ (ansible_default_ipv4.address.split('.')[0:3] | join('.')) }}.0/24" + jump: "ACCEPT" + comment: "Allow forwarding from local subnet" + state: "{{ 'present' if wireguard_gateway_enabled else 'absent' }}" + +- name: "Add IPv4 FORWARD rule to accept established connections" + become: true + ansible.builtin.iptables: + chain: "FORWARD" + match: "conntrack" + ctstate: "RELATED,ESTABLISHED" + jump: "ACCEPT" + comment: "Allow established connections" + state: "{{ 'present' if wireguard_gateway_enabled else 'absent' }}" + +# IPv6 iptables rules +- name: "Add IPv6 NAT masquerading for traffic through internet" + become: true + ansible.builtin.iptables: + table: "nat" + chain: "POSTROUTING" + source: "{{ (ansible_default_ipv6.address.split(':')[:4] | join(':')) + '::/64' }}" + out_interface: "{{ ansible_default_ipv6.interface }}" + jump: "MASQUERADE" + comment: "NAT IPv6 local subnet traffic through internet" + ip_version: "ipv6" + state: "present" + when: ansible_default_ipv6.address is defined + +- name: "Add IPv6 NAT masquerading for traffic through VPN" + become: true + ansible.builtin.iptables: + table: "nat" + chain: "POSTROUTING" + source: "{{ (ansible_default_ipv6.address.split(':')[:4] | join(':')) + '::/64' }}" + out_interface: "{{ item }}" + jump: "MASQUERADE" + comment: "NAT IPv6 local subnet traffic through VPN" + ip_version: "ipv6" + state: "{{ 'present' if wireguard_gateway_enabled else 'absent' }}" + with_items: "{{ wireguard_connections }}" + +- name: "Add IPv6 FORWARD rule to accept traffic from local subnet" + become: true + ansible.builtin.iptables: + chain: "FORWARD" + source: "{{ (ansible_default_ipv6.address.split(':')[:4] | join(':')) + '::/64' }}" + jump: "ACCEPT" + comment: "Allow IPv6 forwarding from local subnet" + ip_version: "ipv6" + state: "{{ 'present' if wireguard_gateway_enabled else 'absent' }}" + +- name: "Add IPv6 FORWARD rule to accept established connections" + become: true + ansible.builtin.iptables: + chain: "FORWARD" + match: "conntrack" + ctstate: "RELATED,ESTABLISHED" + jump: "ACCEPT" + comment: "Allow IPv6 established connections" + ip_version: "ipv6" + state: "{{ 'present' if wireguard_gateway_enabled else 'absent' }}" diff --git a/site.yml b/site.yml index 42006b04..0ced1e0b 100644 --- a/site.yml +++ b/site.yml @@ -45,5 +45,5 @@ - role: "locales" - role: "timezone" - role: "wireguard" - - role: "gateway" + - role: "wireguard_gateway" - role: "pihole" -- cgit v1.2.3