diff --git a/playbooks/router.yml b/playbooks/router.yml index 2d84734..2608bc6 100755 --- a/playbooks/router.yml +++ b/playbooks/router.yml @@ -110,4 +110,10 @@ - 2a09:6840:134:0:1::/48 roles: - keepalived + +- hosts: + - infra-1.router.auro.re + - infra-2.router.auro.re + roles: + - nftables_infra ... diff --git a/roles/nftables_infra/handlers/main.yml b/roles/nftables_infra/handlers/main.yml new file mode 100644 index 0000000..a350d9a --- /dev/null +++ b/roles/nftables_infra/handlers/main.yml @@ -0,0 +1,6 @@ +--- +- name: Reload nftables + systemd: + name: nftables + state: reloaded +... diff --git a/roles/nftables_infra/tasks/main.yml b/roles/nftables_infra/tasks/main.yml new file mode 100644 index 0000000..a006a3a --- /dev/null +++ b/roles/nftables_infra/tasks/main.yml @@ -0,0 +1,38 @@ +--- +- name: Install nftables + apt: + name: nftables + +- name: Create configuration directory + file: + path: /etc/nftables.d + state: directory + owner: root + group: root + mode: u=rwx,g=rx,o=rx + +- name: Configure nftables + template: + src: "{{ item }}.j2" + dest: "/etc/{{ item }}" + owner: root + group: root + mode: u=rw,g=r,o=r + loop: + - nftables.conf + - nftables.d/10-vars.conf + - nftables.d/20-blacklist.conf + - nftables.d/30-reverse-path-filter.conf + - nftables.d/40-input.conf + - nftables.d/50-output.conf + - nftables.d/60-forward.conf + - nftables.d/70-nat.conf + notify: + - Reload nftables + +- name: Enable and start nftables + systemd: + name: nftables.service + enabled: true + state: started +... diff --git a/roles/nftables_infra/templates/nftables.conf.j2 b/roles/nftables_infra/templates/nftables.conf.j2 new file mode 100644 index 0000000..059f550 --- /dev/null +++ b/roles/nftables_infra/templates/nftables.conf.j2 @@ -0,0 +1,7 @@ +#!/usr/sbin/nft -f + +{{ ansible_managed | comment }} + +flush ruleset + +include "/etc/nftables.d/*.conf" diff --git a/roles/nftables_infra/templates/nftables.d/10-vars.conf.j2 b/roles/nftables_infra/templates/nftables.d/10-vars.conf.j2 new file mode 100644 index 0000000..1ac86f2 --- /dev/null +++ b/roles/nftables_infra/templates/nftables.d/10-vars.conf.j2 @@ -0,0 +1,61 @@ +{{ ansible_managed | comment }} + +define public_server_ipv6 = 2a09:6840:111::/56 +define public_server_ipv4 = 45.66.111.0/24 + +define server_ipv6 = 2a09:6840:128::/48 +define server_ipv4 = 10.128.0.0/16 + +define backbone_ipv6 = 2a09:6840:129::/48 +define backbone_ipv4 = 10.129.0.0/16 + +define ups_ipv6 = 2a09:6840:131::/48 +define ups_ipv4 = 10.131.0.0/16 + +define bmc_ipv6 = 2a09:6840:133::/48 +define bmc_ipv4 = 10.133.0.0/16 + +define pve_ipv6 = 2a09:6840:134::/48 +define pve_ipv4 = 10.134.0.0/16 + +define router_ipv6 = 2a09:6840:135::/48 +define router_ipv4 = 10.135.0.0/16 + +define infra_ipv6 = { + $public_server_ipv6, + $server_ipv6, + $backbone_ipv6, + $ups_ipv6, + $bmc_ipv6, + $pve_ipv6, + $router_ipv6, +} +define infra_ipv4 = { + $public_server_ipv4, + $server_ipv4, + $backbone_ipv4, + $ups_ipv4, + $bmc_ipv4, + $pve_ipv4, + $router_ipv4, +} + +# FIXME: temporary +define egress_internet_ipv6 = { + $server_ipv6, + $pve_ipv6, + $router_ipv6, +} +define egress_internet_ipv4 = { + $server_ipv4, + $pve_ipv4, + $router_ipv4, +} + +# FIXME: bad ipv6 address +define log_ipv6 = 2a09:6840:128::241/128 +define log_ipv4 = 10.128.0.241 + +# FIXME: bad ipv6 address +define prom_infra_v6 = 2a09:6840:128::67/128 +define prom_infra_v4 = 10.128.0.67 diff --git a/roles/nftables_infra/templates/nftables.d/20-blacklist.conf.j2 b/roles/nftables_infra/templates/nftables.d/20-blacklist.conf.j2 new file mode 100644 index 0000000..4773f20 --- /dev/null +++ b/roles/nftables_infra/templates/nftables.d/20-blacklist.conf.j2 @@ -0,0 +1,25 @@ +{{ ansible_managed | comment }} + +table inet blacklist { + + set blacklist_ipv4 { + type ipv4_addr + flags interval + } + + set blacklist_ipv6 { + type ipv6_addr + flags interval + } + + counter blacklist {} + + chain filter { + type filter hook prerouting priority raw - 10 + policy accept + + ip6 saddr @blacklist_ipv6 counter name blacklist drop + ip saddr @blacklist_ipv4 counter name blacklist drop + } + +} diff --git a/roles/nftables_infra/templates/nftables.d/30-reverse-path-filter.conf.j2 b/roles/nftables_infra/templates/nftables.d/30-reverse-path-filter.conf.j2 new file mode 100644 index 0000000..c6ca562 --- /dev/null +++ b/roles/nftables_infra/templates/nftables.d/30-reverse-path-filter.conf.j2 @@ -0,0 +1,14 @@ +{{ ansible_managed | comment }} + +table inet reverse_path_filter { + + chain filter { + type filter hook prerouting priority raw + policy accept + + fib saddr . iif oif missing \ + log prefix "reverse-path-filter" group 1 \ + counter drop + } + +} diff --git a/roles/nftables_infra/templates/nftables.d/40-input.conf.j2 b/roles/nftables_infra/templates/nftables.d/40-input.conf.j2 new file mode 100644 index 0000000..813ea11 --- /dev/null +++ b/roles/nftables_infra/templates/nftables.d/40-input.conf.j2 @@ -0,0 +1,57 @@ +{{ ansible_managed | comment }} + +table inet input { + + chain conntrack { + ct state vmap { + established: counter accept, + related: counter accept, + invalid: counter drop, + } + } + + chain input_from_backbone { + ip6 nexthdr { ospf, vrrp } accept + ip protocol { ospf, vrrp } accept + counter accept # FIXME: temporary + } + + chain input_from_router { + jump conntrack + + tcp dport ssh counter accept + } + + chain input_from_anywhere { + jump conntrack + + # FIXME: limit + ip6 nexthdr icmpv6 counter accept + ip protocol icmp counter accept + } + + chain input { + type filter hook input priority filter + policy drop + + iif lo accept + + jump input_from_anywhere + + # FIXME: temporary + tcp dport ssh accept + + ip6 saddr vmap { + $backbone_ipv6: jump input_from_backbone, + $router_ipv6: jump input_from_router, + } + + ip saddr vmap { + $backbone_ipv4: jump input_from_backbone, + $router_ipv4: jump input_from_router, + } + + reject with icmpx type admin-prohibited + } + +} diff --git a/roles/nftables_infra/templates/nftables.d/50-output.conf.j2 b/roles/nftables_infra/templates/nftables.d/50-output.conf.j2 new file mode 100644 index 0000000..3cd9235 --- /dev/null +++ b/roles/nftables_infra/templates/nftables.d/50-output.conf.j2 @@ -0,0 +1,22 @@ +{{ ansible_managed | comment }} + +table inet output { + + chain conntrack { + ct state vmap { + established: counter accept, + related: counter accept, + invalid: counter drop, + } + } + + chain output { + type filter hook output priority filter + policy accept + + jump conntrack + + counter + } + +} diff --git a/roles/nftables_infra/templates/nftables.d/60-forward.conf.j2 b/roles/nftables_infra/templates/nftables.d/60-forward.conf.j2 new file mode 100644 index 0000000..c2b79f3 --- /dev/null +++ b/roles/nftables_infra/templates/nftables.d/60-forward.conf.j2 @@ -0,0 +1,101 @@ +{{ ansible_managed | comment }} + +table inet forward { + + chain conntrack { + ct state vmap { + established: counter accept, + related: counter accept, + invalid: counter drop, + } + } + + chain forward_to_public_server { + jump conntrack + } + + chain forward_to_server { + jump conntrack + + ip6 saddr $infra_ipv6 ip6 daddr $log_infra_ipv6 jump { + tcp dport 2514 counter accept + udp dport 514 counter accept + } + + ip saddr $infra_ipv4 ip daddr $log_infra_ipv4 jump { + tcp dport 2514 counter accept + udp dport 514 counter accept + } + + ip6 saddr $prom_infra_v6 tcp dport 9100 counter accept + ip saddr $prom_infra_v4 udp dport 161 counter accept + } + + chain forward_to_backbone { + } + + chain forward_to_ups { + jump conntrack + + ip6 saddr $prom_infra_v6 udp dport 161 counter accept + ip saddr $prom_infra_v4 udp dport 161 counter accept + } + + chain forward_to_bmc { + jump conntrack + + ip6 saddr $prom_infra_v6 udp dport 161 counter accept + ip saddr $prom_infra_v4 udp dport 161 counter accept + } + + chain forward_to_pve { + jump conntrack + + ip6 saddr $prom_infra_ipv6 tcp dport 9100 counter accept + ip saddr $prom_infra_ipv4 tcp dport 9100 counter accept + } + + chain forward_to_router { + jump conntrack + + ip6 saddr $prom_infra_ipv6 tcp dport 9100 counter accept + ip saddr $prom_infra_ipv4 tcp dport 9100 counter accept + } + + chain forward_to_internet { + jump conntrack + + ip6 saddr $egress_internet_ipv6 counter accept + ip saddr $egress_internet_ipv4 counter accept + } + + chain forward { + type filter hook forward priority filter + policy drop + + iif lo accept + + ip6 daddr vmap { + $public_server_ipv6: goto forward_to_public_server, + $server_ipv6: goto forward_to_server, + $backbone_ipv6: goto forward_to_backbone, + $ups_ipv6: goto forward_to_ups, + $bmc_ipv6: goto forward_to_bmc, + $pve_ipv6: goto forward_to_pve, + $router_ipv6: goto forward_to_router, + } + + ip daddr vmap { + $public_server_ipv4: goto forward_to_public_server, + $server_ipv4: goto forward_to_server, + $backbone_ipv4: goto forward_to_backbone, + $ups_ipv4: goto forward_to_ups, + $bmc_ipv4: goto forward_to_bmc, + $pve_ipv4: goto forward_to_pve, + $router_ipv4: goto forward_to_router, + } + + goto forward_to_internet + } + +} diff --git a/roles/nftables_infra/templates/nftables.d/70-nat.conf.j2 b/roles/nftables_infra/templates/nftables.d/70-nat.conf.j2 new file mode 100644 index 0000000..5ef48fe --- /dev/null +++ b/roles/nftables_infra/templates/nftables.d/70-nat.conf.j2 @@ -0,0 +1,21 @@ +{{ ansible_managed | comment }} + +table ip nat { + + # chain prerouting { + # type nat hook prerouting dstnat + # polict accept + # } + + # chain postrouting { + # type nat hook postrouting priority srcnat + # policy accept + # + # iif lo return + # + # meta pkttype unicast \ + # ip saddr $nat_v4 ip daddr != $saclay_v4 \ + # snat $snat_any_v4 persistent + # } + +}