diff --git a/host_vars/.template b/host_vars/.template index ffa40f8..7b265f7 100644 --- a/host_vars/.template +++ b/host_vars/.template @@ -18,6 +18,7 @@ vpn_br0_netmask: vpn_wg0_address: vpn_wg0_interface_private_key: vpn_wg0_peer_public_key: +vpn_wg0_endpoint_address: vpn_remote_subnet: diff --git a/playbooks/filesystem/valkyrie/etc/network/interfaces.d/br0.j2 b/playbooks/filesystem/valkyrie/etc/network/interfaces.d/br0.j2 new file mode 100644 index 0000000..5fa3ee1 --- /dev/null +++ b/playbooks/filesystem/valkyrie/etc/network/interfaces.d/br0.j2 @@ -0,0 +1,18 @@ +auto br0 +iface br0 inet static + pre-up ip link add $IFACE type bridge + + post-up /usr/local/sbin/post-up-$IFACE.nft + + pre-down /usr/local/sbin/pre-down-$IFACE.nft + + post-down ip link del dev $IFACE + + bridge_stp off + bridge_waitport 0 + bridge_fd 0 + bridge_ports none + + address {{ vpn_br0_address }} + broadcast {{ vpn_br0_broadcast }} + netmask {{ vpn_br0_netmask }} diff --git a/playbooks/filesystem/valkyrie/etc/network/interfaces.d/wg0.j2 b/playbooks/filesystem/valkyrie/etc/network/interfaces.d/wg0.j2 new file mode 100644 index 0000000..80318e0 --- /dev/null +++ b/playbooks/filesystem/valkyrie/etc/network/interfaces.d/wg0.j2 @@ -0,0 +1,16 @@ +auto wg0 +iface wg0 inet static + pre-up ip link add $IFACE type wireguard + pre-up wg setconf $IFACE /etc/wireguard/$IFACE.conf + pre-up ip link set mtu 1420 dev $IFACE + + post-up /usr/local/sbin/post-up-$IFACE.nft + post-up ip route add {{ vpn_remote_subnet }} dev $IFACE + + pre-down ip route del {{ vpn_remote_subnet }} dev $IFACE + pre-down /usr/local/sbin/pre-down-$IFACE.nft + + post-down ip link del dev $IFACE + + address {{ vpn_wg0_address }} + netmask {{ vpn_wg0_netmask }} diff --git a/playbooks/filesystem/valkyrie/etc/nftables.conf.j2 b/playbooks/filesystem/valkyrie/etc/nftables.conf.j2 new file mode 100755 index 0000000..f6e155c --- /dev/null +++ b/playbooks/filesystem/valkyrie/etc/nftables.conf.j2 @@ -0,0 +1,38 @@ +#!/usr/sbin/nft -f + +flush ruleset + +table inet filter { + chain input { + type filter hook input priority 0; + + # Accept any localhost traffic. + iif lo accept; + + # Accept traffic originated from us. + ct state established,related accept; + + # Allow ICMP packets. + # Note that for IPv6 nd-neighbor-solicit, nd-router-advert, nd-neighbor-advert are needed to not break connectivity. + ip6 nexthdr icmpv6 icmpv6 type { echo-request, destination-unreachable, packet-too-big, time-exceeded, parameter-problem, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } accept; + ip protocol icmp icmp type { echo-request, destination-unreachable, router-advertisement, time-exceeded, parameter-problem } accept; + + # Drop invalid connections. + ct state invalid drop; + + # Accept HTTP, HTTPS, SSH. + tcp dport { 80, 443, {{ ansible_port }} } ct state new accept; + + # Accept WireGuard. + iif {{ ethx }} udp dport {{ vpn_wg0_port }} accept; + + # Count and drop any other traffic. + counter drop; + } + chain forward { + type filter hook forward priority 0; + } + chain output { + type filter hook output priority 0; + } +} diff --git a/playbooks/filesystem/valkyrie/etc/wireguard/wg0.conf.j2 b/playbooks/filesystem/valkyrie/etc/wireguard/wg0.conf.j2 new file mode 100644 index 0000000..43debb6 --- /dev/null +++ b/playbooks/filesystem/valkyrie/etc/wireguard/wg0.conf.j2 @@ -0,0 +1,8 @@ +[Interface] +PrivateKey = {{ vpn_wg0_interface_private_key }} +ListenPort = {{ vpn_wg0_port }} + +[Peer] +PublicKey = {{ vpn_wg0_peer_public_key }} +PresharedKey = {{ vpn_wg0_preshared_key }} +AllowedIPs = {{ vpn_remote_subnet }} diff --git a/playbooks/filesystem/valkyrie/usr/local/sbin/post-up-br0.nft.j2 b/playbooks/filesystem/valkyrie/usr/local/sbin/post-up-br0.nft.j2 new file mode 100644 index 0000000..a49f136 --- /dev/null +++ b/playbooks/filesystem/valkyrie/usr/local/sbin/post-up-br0.nft.j2 @@ -0,0 +1,13 @@ +#!/usr/bin/env -S nft -f + +table ip br0_nat { + chain prerouting { + type nat hook prerouting priority -100; + iif {{ ethx }} tcp dport { 80, 443 } dnat to {{ vpn_reverse_proxy_address }}; + } + + chain postrouting { + type nat hook postrouting priority 100; + iif br0 oif {{ ethx }} masquerade; + } +} diff --git a/playbooks/filesystem/valkyrie/usr/local/sbin/post-up-wg0.nft.j2 b/playbooks/filesystem/valkyrie/usr/local/sbin/post-up-wg0.nft.j2 new file mode 100644 index 0000000..d49c693 --- /dev/null +++ b/playbooks/filesystem/valkyrie/usr/local/sbin/post-up-wg0.nft.j2 @@ -0,0 +1,16 @@ +#!/usr/bin/env -S nft -f + +table inet wg0_mss_clamping { + chain forward { + type filter hook forward priority 0; + iif wg0 tcp flags syn tcp option maxseg size set rt mtu; + oif wg0 tcp flags syn tcp option maxseg size set rt mtu; + } +} + +table ip wg0_nat { + chain postrouting { + type nat hook postrouting priority 100; + iif wg0 oif {{ ethx }} masquerade; + } +} diff --git a/playbooks/filesystem/valkyrie/usr/local/sbin/pre-down-br0.nft.j2 b/playbooks/filesystem/valkyrie/usr/local/sbin/pre-down-br0.nft.j2 new file mode 100644 index 0000000..f76549c --- /dev/null +++ b/playbooks/filesystem/valkyrie/usr/local/sbin/pre-down-br0.nft.j2 @@ -0,0 +1,4 @@ +#!/usr/bin/env -S nft -f + +flush table ip br0_nat +delete table ip br0_nat diff --git a/playbooks/filesystem/valkyrie/usr/local/sbin/pre-down-wg0.nft.j2 b/playbooks/filesystem/valkyrie/usr/local/sbin/pre-down-wg0.nft.j2 new file mode 100644 index 0000000..f4eac35 --- /dev/null +++ b/playbooks/filesystem/valkyrie/usr/local/sbin/pre-down-wg0.nft.j2 @@ -0,0 +1,7 @@ +#!/usr/bin/env -S nft -f + +flush table inet wg0_mss_clamping +delete table inet wg0_mss_clamping + +flush table ip wg0_nat +delete table ip wg0_nat diff --git a/playbooks/filesystem/yggdrasil/etc/network/interfaces.d/br0.j2 b/playbooks/filesystem/yggdrasil/etc/network/interfaces.d/br0.j2 new file mode 100644 index 0000000..a780aaf --- /dev/null +++ b/playbooks/filesystem/yggdrasil/etc/network/interfaces.d/br0.j2 @@ -0,0 +1,22 @@ +auto br0 +iface br0 inet static + pre-up ip link add $IFACE type bridge + + post-up /usr/local/sbin/post-up-$IFACE.nft + post-up ip rule add dev $IFACE table 66 + post-up ip route add {{ subnet }} dev {{ ethx }} table 66 + + pre-down ip route del {{ subnet }} dev {{ ethx }} table 66 + pre-down ip rule del dev $IFACE table 66 + pre-down /usr/local/sbin/pre-down-$IFACE.nft + + post-down ip link del dev $IFACE + + bridge_stp off + bridge_waitport 0 + bridge_fd 0 + bridge_ports none + + address {{ vpn_br0_address }} + broadcast {{ vpn_br0_broadcast }} + netmask {{ vpn_br0_netmask }} diff --git a/playbooks/filesystem/yggdrasil/etc/network/interfaces.d/wg0.j2 b/playbooks/filesystem/yggdrasil/etc/network/interfaces.d/wg0.j2 new file mode 100644 index 0000000..f293785 --- /dev/null +++ b/playbooks/filesystem/yggdrasil/etc/network/interfaces.d/wg0.j2 @@ -0,0 +1,16 @@ +auto wg0 +iface wg0 inet static + pre-up ip link add $IFACE type wireguard + pre-up wg setconf $IFACE /etc/wireguard/$IFACE.conf + pre-up ip link set mtu 1420 dev $IFACE + + post-up /usr/local/sbin/post-up-$IFACE.nft + post-up ip route add default dev $IFACE table 66 + + pre-down ip route del default dev $IFACE table 66 + pre-down /usr/local/sbin/pre-down-$IFACE.nft + + post-down ip link del dev $IFACE + + address {{ vpn_wg0_address }} + netmask {{ vpn_wg0_netmask }} diff --git a/playbooks/filesystem/common/etc/nftables.conf.j2 b/playbooks/filesystem/yggdrasil/etc/nftables.conf.j2 similarity index 94% rename from playbooks/filesystem/common/etc/nftables.conf.j2 rename to playbooks/filesystem/yggdrasil/etc/nftables.conf.j2 index 40bb451..8e78160 100755 --- a/playbooks/filesystem/common/etc/nftables.conf.j2 +++ b/playbooks/filesystem/yggdrasil/etc/nftables.conf.j2 @@ -20,7 +20,7 @@ table inet filter { # Drop invalid connections. ct state invalid drop; - # Activate the following line to accept common local services. + # Accept HTTP, HTTPS, SSH. tcp dport { 80, 443, {{ ansible_port }} } ct state new accept; # Count and drop any other traffic. diff --git a/playbooks/filesystem/yggdrasil/etc/wireguard/wg0.conf.j2 b/playbooks/filesystem/yggdrasil/etc/wireguard/wg0.conf.j2 new file mode 100644 index 0000000..e436b1a --- /dev/null +++ b/playbooks/filesystem/yggdrasil/etc/wireguard/wg0.conf.j2 @@ -0,0 +1,9 @@ +[Interface] +PrivateKey = {{ vpn_wg0_interface_private_key }} + +[Peer] +PublicKey = {{ vpn_wg0_peer_public_key }} +PresharedKey = {{ vpn_wg0_preshared_key }} +Endpoint = {{ vpn_wg0_endpoint_address }}:{{ vpn_wg0_port }} +AllowedIPs = 0.0.0.0/0 +PersistentKeepalive = 15 diff --git a/playbooks/filesystem/yggdrasil/usr/local/sbin/post-up-br0.nft.j2 b/playbooks/filesystem/yggdrasil/usr/local/sbin/post-up-br0.nft.j2 new file mode 100644 index 0000000..fa6ad54 --- /dev/null +++ b/playbooks/filesystem/yggdrasil/usr/local/sbin/post-up-br0.nft.j2 @@ -0,0 +1,21 @@ +#!/usr/bin/env -S nft -f + +table inet br0_filter { + chain input { + type filter hook input priority -5; + ct state established,related accept; + iif br0 ip daddr {{ subnet }} drop; + } +} + +table ip br0_nat { + chain prerouting { + type nat hook prerouting priority -100; + iif {{ ethx }} tcp dport { 80, 443 } dnat to {{ vpn_reverse_proxy_address }}; + } + + chain postrouting { + type nat hook postrouting priority 100; + iif br0 oif {{ ethx }} masquerade; + } +} diff --git a/playbooks/filesystem/yggdrasil/usr/local/sbin/post-up-wg0.nft.j2 b/playbooks/filesystem/yggdrasil/usr/local/sbin/post-up-wg0.nft.j2 new file mode 100644 index 0000000..290d469 --- /dev/null +++ b/playbooks/filesystem/yggdrasil/usr/local/sbin/post-up-wg0.nft.j2 @@ -0,0 +1,9 @@ +#!/usr/bin/env -S nft -f + +table inet wg0_mss_clamping { + chain forward { + type filter hook forward priority 0; + iif wg0 tcp flags syn tcp option maxseg size set rt mtu; + oif wg0 tcp flags syn tcp option maxseg size set rt mtu; + } +} diff --git a/playbooks/filesystem/yggdrasil/usr/local/sbin/pre-down-br0.nft.j2 b/playbooks/filesystem/yggdrasil/usr/local/sbin/pre-down-br0.nft.j2 new file mode 100644 index 0000000..b7d677f --- /dev/null +++ b/playbooks/filesystem/yggdrasil/usr/local/sbin/pre-down-br0.nft.j2 @@ -0,0 +1,7 @@ +#!/usr/bin/env -S nft -f + +flush table inet br0_filter +delete table inet br0_filter + +flush table ip br0_nat +delete table ip br0_nat diff --git a/playbooks/filesystem/yggdrasil/usr/local/sbin/pre-down-wg0.nft.j2 b/playbooks/filesystem/yggdrasil/usr/local/sbin/pre-down-wg0.nft.j2 new file mode 100644 index 0000000..a0c2259 --- /dev/null +++ b/playbooks/filesystem/yggdrasil/usr/local/sbin/pre-down-wg0.nft.j2 @@ -0,0 +1,4 @@ +#!/usr/bin/env -S nft -f + +flush table inet wg0_mss_clamping +delete table inet wg0_mss_clamping diff --git a/playbooks/tasks/hosts/firewall.yml b/playbooks/tasks/hosts/firewall.yml index 4ae98e5..fd0ca83 100644 --- a/playbooks/tasks/hosts/firewall.yml +++ b/playbooks/tasks/hosts/firewall.yml @@ -4,7 +4,7 @@ - name: Configure nftables template: - src: ./filesystem/common/etc/nftables.conf.j2 + src: ./filesystem/{{ ansible_host }}/etc/nftables.conf.j2 dest: /etc/nftables.conf mode: 0755 register: nftables_conf diff --git a/playbooks/tasks/hosts/utils.yml b/playbooks/tasks/hosts/utils.yml index 070ec84..d4f82a5 100644 --- a/playbooks/tasks/hosts/utils.yml +++ b/playbooks/tasks/hosts/utils.yml @@ -6,3 +6,5 @@ - man - perl - tmux + - tcpdump + - traceroute diff --git a/playbooks/tasks/vpn/bridge.yml b/playbooks/tasks/vpn/bridge.yml new file mode 100644 index 0000000..a277c26 --- /dev/null +++ b/playbooks/tasks/vpn/bridge.yml @@ -0,0 +1,25 @@ +- name: Bridge interface post-up nftables script + template: + src: ./filesystem/{{ ansible_hostname }}/usr/local/sbin/post-up-br0.nft.j2 + dest: /usr/local/sbin/post-up-br0.nft + mode: 0755 + register: br_intf_post_up + +- name: Create bridge interface + template: + src: ./filesystem/{{ ansible_hostname }}/etc/network/interfaces.d/br0.j2 + dest: /etc/network/interfaces.d/br0 + mode: 0644 + register: br_intf + +- name: Restart bridge interface + shell: ifdown br0 && ifup br0 + when: + br_intf_post_up is changed or + br_intf is changed + +- name: Bridge interface pre-down nftables script + template: + src: ./filesystem/{{ ansible_hostname }}/usr/local/sbin/pre-down-br0.nft.j2 + dest: /usr/local/sbin/pre-down-br0.nft + mode: 0755 diff --git a/playbooks/tasks/vpn/ipforward.yml b/playbooks/tasks/vpn/ipforward.yml new file mode 100644 index 0000000..8cf6bda --- /dev/null +++ b/playbooks/tasks/vpn/ipforward.yml @@ -0,0 +1,5 @@ +- sysctl: + name: net.ipv4.ip_forward + value: '1' + sysctl_file: /etc/sysctl.d/local.conf + reload: yes diff --git a/playbooks/tasks/vpn/wireguard.yml b/playbooks/tasks/vpn/wireguard.yml new file mode 100644 index 0000000..fc3c3ff --- /dev/null +++ b/playbooks/tasks/vpn/wireguard.yml @@ -0,0 +1,37 @@ +- name: Install WireGuard + apt: + name: wireguard + +- name: WireGuard interface configuration + template: + src: ./filesystem/{{ ansible_hostname }}/etc/wireguard/wg0.conf.j2 + dest: /etc/wireguard/wg0.conf + mode: 0600 + register: wg_intf_conf + +- name: WireGuard interface post-up nftables script + template: + src: ./filesystem/{{ ansible_hostname }}/usr/local/sbin/post-up-wg0.nft.j2 + dest: /usr/local/sbin/post-up-wg0.nft + mode: 0755 + register: wg_intf_post_up + +- name: Create WireGuard interface + template: + src: ./filesystem/{{ ansible_hostname }}/etc/network/interfaces.d/wg0.j2 + dest: /etc/network/interfaces.d/wg0 + mode: 0644 + register: wg_intf + +- name: Restart WireGuard interface + shell: ifdown wg0 && ifup wg0 + when: + wg_intf_conf is changed or + wg_intf_post_up is changed or + wg_intf is changed + +- name: WireGuard interface pre-down nftables script + template: + src: ./filesystem/{{ ansible_hostname }}/usr/local/sbin/pre-down-wg0.nft.j2 + dest: /usr/local/sbin/pre-down-wg0.nft + mode: 0755 diff --git a/playbooks/vpn.yml b/playbooks/vpn.yml new file mode 100644 index 0000000..16decbf --- /dev/null +++ b/playbooks/vpn.yml @@ -0,0 +1,7 @@ +--- +- hosts: the_nine_worlds + + tasks: + - import_tasks: tasks/vpn/ipforward.yml + - import_tasks: tasks/vpn/bridge.yml + - import_tasks: tasks/vpn/wireguard.yml