92 lines
5.6 KiB
YAML

# This should really be set per host, but I'm abusing the fact that there's only
# one vpn_server host
wireguard_addresses:
- "{{ wireguard_ipv6_subnet | ansible.utils.ipaddr('net') | ansible.utils.ipaddr('1') }}"
- "{{ wireguard_ipv4_subnet | ansible.utils.ipaddr('net') | ansible.utils.ipaddr('1') }}"
wireguard_endpoint: "{{ inventory_hostname }}"
wireguard_preup:
- echo 1 > /proc/sys/net/ipv4/ip_forward
- echo 1 > /proc/sys/net/ipv6/conf/all/forwarding
# Disable autoconf while running. We assign some IP addresses that get removed
# by autoconf otherwise.
- echo 0 > /proc/sys/net/ipv6/conf/eth0/autoconf
wireguard_postup: |
{% filter from_yaml %}
- ip6tables -A FORWARD -i wg0 -j ACCEPT
- ip6tables -A FORWARD -o wg0 -j ACCEPT
- iptables -A FORWARD -i wg0 -j ACCEPT
- iptables -A FORWARD -o wg0 -j ACCEPT
{% for value in (nat_map | dict2items | map(attribute='value')) %}
# IPv6 will have a 1:1 port mapping
- ip -6 addr add {{ value.vps_ipv6 }} dev eth0
# Incoming packets to this node's public IP are DNAT'd and forwarded to the
# matching internal VPN IP
{% for range in value.ipv6_port_ranges | default([]) %}
- ip6tables -t nat -A PREROUTING -p tcp -d {{ value.vps_ipv6 | ansible.utils.ipaddr('address') }} --dport {{ range }} -j DNAT --to-destination {{ value.vpn_ipv6 | ansible.utils.ipaddr('address') }}
- ip6tables -t nat -A PREROUTING -p udp -d {{ value.vps_ipv6 | ansible.utils.ipaddr('address') }} --dport {{ range }} -j DNAT --to-destination {{ value.vpn_ipv6 | ansible.utils.ipaddr('address') }}
{% endfor %}
# Incoming packets from an internal VPN IP are SNAT'd to use this node's public
# IP. I think `-j MASQUERADE` might work here rather than doing the SNAT
# manually(?), but I don't mind being explicit here.
- ip6tables -t nat -A POSTROUTING -p tcp -s {{ value.vpn_ipv6 | ansible.utils.ipaddr('address') }} -j SNAT --to-source {{ value.vps_ipv6 | ansible.utils.ipaddr('address') }}
- ip6tables -t nat -A POSTROUTING -p udp -s {{ value.vpn_ipv6 | ansible.utils.ipaddr('address') }} -j SNAT --to-source {{ value.vps_ipv6 | ansible.utils.ipaddr('address') }}
# IPv4 will have manual port mapping
{% for mapping in value.ipv4_port_mapping | default([]) %}
- iptables -t nat -A PREROUTING -p tcp -d {{ value.vps_ipv4 | ansible.utils.ipaddr('address') }} --dport {{ mapping.external_port }} -j DNAT --to-destination {{ value.vpn_ipv4 | ansible.utils.ipaddr('address') }}:{{ mapping.internal_port }}
- iptables -t nat -A PREROUTING -p udp -d {{ value.vps_ipv4 | ansible.utils.ipaddr('address') }} --dport {{ mapping.external_port }} -j DNAT --to-destination {{ value.vpn_ipv4 | ansible.utils.ipaddr('address') }}:{{ mapping.internal_port }}
{% endfor %}
# We're going to masquerade even if it's not from an internal port
- iptables -t nat -A POSTROUTING -s {{ value.vpn_ipv4 | ansible.utils.ipaddr('address') }} -j MASQUERADE
{% endfor %}
{% endfilter %}
# Exact reverse of above to delete all the rules
wireguard_predown: |
{% filter from_yaml %}
{% for value in (nat_map | dict2items | map(attribute='value') | reverse) %}
- iptables -t nat -D POSTROUTING -s {{ value.vpn_ipv4 | ansible.utils.ipaddr('address') }} -j MASQUERADE
{% for mapping in value.ipv4_port_mapping | default([]) | reverse %}
- iptables -t nat -D PREROUTING -p udp -d {{ value.vps_ipv4 | ansible.utils.ipaddr('address') }} --dport {{ mapping.external_port }} -j DNAT --to-destination {{ value.vpn_ipv4 | ansible.utils.ipaddr('address') }}:{{ mapping.internal_port }}
- iptables -t nat -D PREROUTING -p tcp -d {{ value.vps_ipv4 | ansible.utils.ipaddr('address') }} --dport {{ mapping.external_port }} -j DNAT --to-destination {{ value.vpn_ipv4 | ansible.utils.ipaddr('address') }}:{{ mapping.internal_port }}
{% endfor %}
- ip6tables -t nat -D POSTROUTING -p udp -s {{ value.vpn_ipv6 | ansible.utils.ipaddr('address') }} -j SNAT --to-source {{ value.vps_ipv6 | ansible.utils.ipaddr('address') }}
- ip6tables -t nat -D POSTROUTING -p tcp -s {{ value.vpn_ipv6 | ansible.utils.ipaddr('address') }} -j SNAT --to-source {{ value.vps_ipv6 | ansible.utils.ipaddr('address') }}
{% for range in value.ipv6_port_ranges | default([]) | reverse %}
- ip6tables -t nat -D PREROUTING -p udp -d {{ value.vps_ipv6 | ansible.utils.ipaddr('address') }} --dport {{ range }} -j DNAT --to-destination {{ value.vpn_ipv6 | ansible.utils.ipaddr('address') }}
- ip6tables -t nat -D PREROUTING -p tcp -d {{ value.vps_ipv6 | ansible.utils.ipaddr('address') }} --dport {{ range }} -j DNAT --to-destination {{ value.vpn_ipv6 | ansible.utils.ipaddr('address') }}
{% endfor %}
- ip -6 addr del {{ value.vps_ipv6 }} dev eth0
{% endfor %}
- iptables -D FORWARD -o wg0 -j ACCEPT
- iptables -D FORWARD -i wg0 -j ACCEPT
- ip6tables -D FORWARD -o wg0 -j ACCEPT
- ip6tables -D FORWARD -i wg0 -j ACCEPT
{% endfilter %}
wireguard_postdown:
- echo 1 > /proc/sys/net/ipv6/conf/eth0/autoconf
- echo 0 > /proc/sys/net/ipv6/conf/all/forwarding
- echo 0 > /proc/sys/net/ipv4/ip_forward
# https://www.procustodibus.com/blog/2021/03/wireguard-allowedips-calculator/
# Above recommends to just add specific routing rules rather than compute
# an equivalent list of subnets
#
# Yes, this is supposed to be defined on vpn_server rather than vpn_client, like
# I initially thought. The reason for this is likely because the role was meant
# for a fully meshed network rather than a single server with multiple clients,
# and each host defines a list of IPs that should be routed _to this host_, not
# a list of IPs that should be routed to the "server" (because everyone is a
# peer in a fully meshed network)
wireguard_allowed_ips: "0.0.0.0/0, ::0/0"
# Disable IPv4
# wireguard_allowed_ips: "::0/0"