diff --git a/ansible/inventory/full/group_vars/vpn/main.yml b/ansible/inventory/full/group_vars/vpn/main.yml index 32db2a0..260ffa8 100644 --- a/ansible/inventory/full/group_vars/vpn/main.yml +++ b/ansible/inventory/full/group_vars/vpn/main.yml @@ -12,9 +12,10 @@ wireguard_service_state: started # Or, it might be because PersistentKeepalive is actually also needed on the # server but it's being omitted currently. See the issue I opened: # https://github.com/githubixx/ansible-role-wireguard/issues/217#issue-2871281915 -wireguard_persistent_keepalive: 15 +wireguard_persistent_keepalive: 25 wireguard_ipv6_subnet: "fde0:fb5b:2593::/64" +wireguard_ipv4_subnet: "10.4.4.0/24" # Setting this here doesn't seem to work. We set it during runtime later # public_ipv6_subnet: "{{ hostvars[groups['embassy'][0]].ipv6_subnet }}" @@ -23,12 +24,21 @@ wireguard_ipv6_subnet: "fde0:fb5b:2593::/64" nat_map: moirai-clotho.local: vpn_ipv6: "{{ wireguard_ipv6_subnet | ansible.utils.ipaddr('16') }}" + vpn_ipv4: "{{ wireguard_ipv4_subnet | ansible.utils.ipaddr('16') }}" vps_ipv6: "{{ public_ipv6_subnet | ansible.utils.ipaddr('16') }}" + vps_ipv4: "{{ ansible_default_ipv4.address }}" + port_mappings: + - external_port: 20050 + internal_port: 20050 moirai-lachesis.local: vpn_ipv6: "{{ wireguard_ipv6_subnet | ansible.utils.ipaddr('17') }}" + vpn_ipv4: "{{ wireguard_ipv4_subnet | ansible.utils.ipaddr('17') }}" vps_ipv6: "{{ public_ipv6_subnet | ansible.utils.ipaddr('17') }}" + vps_ipv4: "{{ ansible_default_ipv4.address }}" moirai-atropos.local: vpn_ipv6: "{{ wireguard_ipv6_subnet | ansible.utils.ipaddr('18') }}" + vpn_ipv4: "{{ wireguard_ipv4_subnet | ansible.utils.ipaddr('18') }}" vps_ipv6: "{{ public_ipv6_subnet | ansible.utils.ipaddr('18') }}" + vps_ipv4: "{{ ansible_default_ipv4.address }}" diff --git a/ansible/inventory/full/group_vars/vpn_client/main.yml b/ansible/inventory/full/group_vars/vpn_client/main.yml index 455ff51..196f015 100644 --- a/ansible/inventory/full/group_vars/vpn_client/main.yml +++ b/ansible/inventory/full/group_vars/vpn_client/main.yml @@ -1,5 +1,6 @@ wireguard_addresses: - "{{ nat_map[inventory_hostname].vpn_ipv6 | ansible.utils.ipaddr('address') }}" + - "{{ nat_map[inventory_hostname].vpn_ipv4 | ansible.utils.ipaddr('address') }}" # wireguard_endpoint: "{{ nat_map[inventory_hostname].vpn_ipv6 }}" wireguard_endpoint: "" @@ -8,11 +9,11 @@ wireguard_endpoint: "" # wireguard_dns: 10.0.123.123 # don't route local addresses through the wg tunnel -# wireguard_preup: - # - ip route add 10.0.0.0/16 via 10.0.0.1 dev eth0 proto static onlink +wireguard_preup: + - ip route add 10.0.0.0/16 via 10.0.0.1 dev eth0 proto static onlink -# wireguard_postdown: - # - ip route del 10.0.0.0/16 via 10.0.0.1 dev eth0 proto static onlink +wireguard_postdown: + - ip route del 10.0.0.0/16 via 10.0.0.1 dev eth0 proto static onlink # Ok, I could not get the stuff below working properly. What I _wanted_ to do # was make it so that _only_ traffic that was sent from the wireguard tunnel diff --git a/ansible/inventory/full/group_vars/vpn_server/main.yml b/ansible/inventory/full/group_vars/vpn_server/main.yml index 5a79c13..9cb3480 100644 --- a/ansible/inventory/full/group_vars/vpn_server/main.yml +++ b/ansible/inventory/full/group_vars/vpn_server/main.yml @@ -2,6 +2,7 @@ # 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 }}" @@ -14,7 +15,12 @@ wireguard_preup: 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 @@ -23,7 +29,7 @@ wireguard_postup: | # Same for SFTP over TCP. - ip6tables -t nat -A PREROUTING -p tcp -d {{ value.vps_ipv6 | ansible.utils.ipaddr('address') }} --dport 2022 -j DNAT --to-destination {{ value.vpn_ipv6 | ansible.utils.ipaddr('address') }} - # Incoming packets to an internal VPN IP are SNAT'd to use this node's public + # 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') }} @@ -32,6 +38,14 @@ wireguard_postup: | # like ICMP6 and whatnot. - ip6tables -t nat -A PREROUTING -p udp -d {{ value.vps_ipv6 | ansible.utils.ipaddr('address') }} --dport 20000:20100 -j DNAT --to-destination {{ value.vpn_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.port_mappings | 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 %} @@ -39,6 +53,12 @@ wireguard_postup: | 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.port_mappings | 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 PREROUTING -p udp -d {{ value.vps_ipv6 | ansible.utils.ipaddr('address') }} --dport 20000:20100 -j DNAT --to-destination {{ value.vpn_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') }} @@ -46,6 +66,10 @@ wireguard_predown: | - ip6tables -t nat -D PREROUTING -p tcp -d {{ value.vps_ipv6 | ansible.utils.ipaddr('address') }} --dport 20000:20100 -j DNAT --to-destination {{ value.vpn_ipv6 | ansible.utils.ipaddr('address') }} - 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: @@ -63,5 +87,5 @@ wireguard_postdown: # 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" +wireguard_allowed_ips: "0.0.0.0/0, ::0/0" diff --git a/ansible/wings.yml b/ansible/wings.yml index 6db6db8..5031650 100644 --- a/ansible/wings.yml +++ b/ansible/wings.yml @@ -17,6 +17,7 @@ msg: > Expected ipv6_subnet to be defined. This should have been done in Terraform or otherwise. + tasks: # As mentioned in the other file, if I set this statically on group_vars, # things seem to break. @@ -41,13 +42,12 @@ line: 'PubkeyAuthentication yes' register: publickeyauthentication - - when: inventory_hostname == groups['embassy'][0] + - when: inventory_hostname == groups['embassy'][0] and (passwordauthentication.changed or publickeyauthentication.changed) name: Restart SSH become: true service: name: ssh state: restarted - when: passwordauthentication.changed or publickeyauthentication.changed - name: Set up VPN hosts: vpn @@ -55,6 +55,21 @@ roles: - githubixx.ansible_role_wireguard + # We should really try to get this in upstream, this is so jank. +- name: Patch VPN server settings + hosts: vpn_server + become: true + tasks: + - shell: + cmd: | + sed -i \ + '/PublicKey/a PersistentKeepalive = {{ wireguard_persistent_keepalive }}' \ + /etc/wireguard/wg0.conf + - service: + name: wg-quick@wg0 + state: "{{ 'restarted' if wireguard_service_state != 'stopped' }}" + enabled: "{{ wireguard_service_enabled }}" + - name: Install wings hosts: moirai_wings remote_user: ubuntu diff --git a/tf/modules/embassy/main.tf b/tf/modules/embassy/main.tf index c918774..178b439 100644 --- a/tf/modules/embassy/main.tf +++ b/tf/modules/embassy/main.tf @@ -56,6 +56,52 @@ resource "linode_firewall" "embassy" { ipv6 = ["::/0"] } + inbound { + label = "allow-frp-tcp" + action = "ACCEPT" + protocol = "TCP" + ports = "7000" + ipv4 = ["0.0.0.0/0"] + ipv6 = ["::/0"] + } + + # For FRP server KCP + inbound { + label = "allow-frp-udp" + action = "ACCEPT" + protocol = "UDP" + ports = "7000" + ipv4 = ["0.0.0.0/0"] + ipv6 = ["::/0"] + } + + inbound { + label = "allow-frp-udp" + action = "ACCEPT" + protocol = "UDP" + ports = "7000" + ipv4 = ["0.0.0.0/0"] + ipv6 = ["::/0"] + } + + inbound { + label = "allow-frp-proxies-tcp" + action = "ACCEPT" + protocol = "TCP" + ports = "21000-21100" + ipv4 = ["0.0.0.0/0"] + ipv6 = ["::/0"] + } + + inbound { + label = "allow-frp-proxies-udp" + action = "ACCEPT" + protocol = "UDP" + ports = "21000-21100" + ipv4 = ["0.0.0.0/0"] + ipv6 = ["::/0"] + } + inbound { label = "allow-sftp" action = "ACCEPT"