From dcc038bd7c2f2c999e8d465a7a46eaaced89f7cb Mon Sep 17 00:00:00 2001 From: Jeltz Date: Fri, 13 Jan 2023 08:56:16 +0100 Subject: [PATCH] nftables + bird: add role + fix IP addresses --- playbooks/bird.yml | 4 +- playbooks/ifupdown2.yml | 35 +++- playbooks/nftables.yml | 241 ++++++++++++++++++++++ roles/nftables/defaults/main.yml | 4 + roles/nftables/handlers/main.yml | 6 + roles/nftables/tasks/main.yml | 23 +++ roles/nftables/templates/nftables.conf.j2 | 43 ++++ 7 files changed, 352 insertions(+), 4 deletions(-) create mode 100755 playbooks/nftables.yml create mode 100644 roles/nftables/defaults/main.yml create mode 100644 roles/nftables/handlers/main.yml create mode 100644 roles/nftables/tasks/main.yml create mode 100644 roles/nftables/templates/nftables.conf.j2 diff --git a/playbooks/bird.yml b/playbooks/bird.yml index 7f55f1f..58cfc1a 100755 --- a/playbooks/bird.yml +++ b/playbooks/bird.yml @@ -43,8 +43,8 @@ - 2a09:6840:203:1:5::1 - 10.203.1.5 isp-2.rtr.infra.auro.re: - - 2a09:6840:203:1:5::1 - - 10.203.1.5 + - 2a09:6840:203:1:6::1 + - 10.203.1.6 bird__bgp_sessions: - name: edge1 local: diff --git a/playbooks/ifupdown2.yml b/playbooks/ifupdown2.yml index 57bc7b3..5f4f322 100755 --- a/playbooks/ifupdown2.yml +++ b/playbooks/ifupdown2.yml @@ -7,6 +7,9 @@ adm: - 2a09:6840:128::254 - 10.128.0.254 + int: + - 2a09:6840:206::1 + - 10.206.0.1 # TODO: netbox ifupdown2__hosts: edge-1.rtr.infra.auro.re: @@ -32,7 +35,7 @@ edge-2.rtr.infra.auro.re: ens18: addresses: - - 2a09:6840:128:10:102/56 + - 2a09:6840:128::10:102/56 - 10.128.10.102/16 gateways: "{{ ifupdown2__gateways.adm }}" ens19: @@ -54,11 +57,12 @@ addresses: - 2a09:6840:128::10:3/56 - 10.128.10.3/16 - gateways: "{{ ifupdown2__gateways.adm }}" + #gateways: "{{ ifupdown2__gateways.adm }}" ens19: addresses: - 2a09:6840:206:0:2::1/56 - 10.206.0.2/16 + gateways: "{{ ifupdown2__gateways.int }}" dns-2.int.infra.auro.re: ens18: addresses: @@ -76,7 +80,13 @@ - 10.128.10.1/16 gateways: "{{ ifupdown2__gateways.adm }}" ens19: + addresses: + - 2a09:6840:207:1:2::1/56 - 45.66.108.2/16 + ens20: + addresses: + - 2a09:6840:211:1:1::1/56 + - 10.211.1.1/16 ssh-2.mgmt.infra.auro.re: ens18: addresses: @@ -84,13 +94,19 @@ - 10.128.10.101/16 gateways: "{{ ifupdown2__gateways.adm }}" ens19: + - 2a09:6840:207:1:3::1/56 - 45.66.108.3/16 + ens20: + addresses: + - 2a09:6840:211:1:2::1/56 + - 10.211.1.2/16 infra-1.rtr.infra.auro.re: ens18: addresses: - 2a09:6840:128::10:4/56 - 10.128.10.4/16 gateways: "{{ ifupdown2__gateways.adm }}" + forward: true ens19: addresses: - 2a09:6840:203:1:3::1/56 @@ -117,12 +133,16 @@ enp2s3: ipv6_addrgen: false forward: true + enp2s4: + ipv6_addrgen: false + forward: true infra-2.rtr.infra.auro.re: ens18: addresses: - 2a09:6840:128::10:104/56 - 10.128.10.104/16 gateways: "{{ ifupdown2__gateways.adm }}" + forward: true ens19: addresses: - 2a09:6840:203:4::1/64 @@ -149,6 +169,9 @@ enp2s3: ipv6_addrgen: false forward: true + enp2s4: + ipv6_addrgen: false + forward: true isp-1.rtr.infra.auro.re: ens18: addresses: @@ -215,6 +238,8 @@ - ens20 bridge_vids: - 1000-1004 + bridge_disable_pvid: true + ipv6_addrgen: false forward: true client-0: vlan_id: 1000 @@ -258,6 +283,9 @@ - ens20 bridge_vids: - 1000-1004 + bridge_disable_pvid: true + ipv6_addrgen: false + forward: true client-0: addresses: - 100.64.0.2/27 @@ -300,6 +328,9 @@ - ens20 bridge_vids: - 1000-1004 + bridge_disable_pvid: true + ipv6_addrgen: false + forward: true client-0: addresses: - 100.64.0.3/27 diff --git a/playbooks/nftables.yml b/playbooks/nftables.yml new file mode 100755 index 0000000..9f9de28 --- /dev/null +++ b/playbooks/nftables.yml @@ -0,0 +1,241 @@ +#!/usr/bin/env ansible-playbook +--- +- hosts: + - isp-1.rtr.infra.auro.re + - isp-2.rtr.infra.auro.re + vars: + nftables__vars: + adm_ipv6: 2a09:6840:128::/56 + adm_ipv4: 10.128.0.0/16 + backbone_ipv6: 2a09:6840:203::/56 + backbone_ipv4: 10.203.0.0/16 + mgmt_ipv6: 2a09:6840:211::/56 + mgmt_ipv4: 10.211.0.0/16 + clients_ipv6: 2a09:6841::/48 + clients_ipv4: 100.64.0.0/10 + nftables__tables: + blacklist: + type: inet + sets: + blacklist_ipv6: + type: ipv6_addr + flags: + - interval + blacklist_ipv4: + type: ipv4_addr + flags: + - interval + chains: + filter: + type: filter + hook: prerouting + priority: "raw - 10" + policy: accept + rules: + - "ip6 saddr @blacklist_ipv6 counter drop" + - "ip saddr @blacklist_ipv4 counter drop" + reverse_path_filter: + type: inet + chains: + filter: + type: filter + hook: prerouting + priority: raw + policy: accept + rules: + - "fib saddr . iif oif missing pkttype unicast drop" + filter: + type: inet + sets: + allowed_clients_ipv6: + type: ipv6_addr + flags: + - interval + allowed_clients_ipv4: + type: ipv4_addr + flags: + - interval + chains: + conntrack: + rules: + - "ct state { established, related } accept" + - "ct state invalid counter drop" + input_backbone: + rules: + - "ip6 nexthdr { ospf, vrrp, icmpv6 } accept" + - "ip protocol { ospf, vrrp, icmp } accept" + - "tcp dport 179 accept" + input_mgmt: + rules: + - "ip6 nexthdr icmpv6 accept" + - "ip protocol icmp accept" + - "tcp dport 22 accept" + input_other: + rules: + - "ip6 nexthdr icmpv6 accept" + - "ip protocol icmp accept" + input: + type: filter + hook: input + priority: filter + policy: drop + rules: + - "jump conntrack" + - "iif lo accept" + # FIXME: don't use ifaces + - "ip6 saddr fe80::/10 iifname ens19 goto input_backbone" + - "ip6 saddr vmap { \ + $backbone_ipv6: goto input_backbone, \ + $mgmt_ipv6: goto input_mgmt, \ + $adm_ipv6: goto input_mgmt \ + }" + - "ip saddr vmap { \ + $backbone_ipv4: goto input_backbone, \ + $mgmt_ipv4: goto input_mgmt, \ + $adm_ipv4: goto input_mgmt \ + }" + - "goto input_other" + forward_clients: + rules: + - "ip6 daddr $clients_ipv6 drop" + - "ip daddr $clients_ipv4 drop" + - "ip6 saddr @allowed_clients_ipv6 accept" + - "ip saddr @allowed_clients_ipv4 accept" + forward: + type: filter + hook: forward + priority: filter + policy: drop + rules: + - "jump conntrack" + - "ip6 saddr $clients_ipv6 goto forward_clients" + - "ip saddr $clients_ipv4 goto forward_clients" + output: + type: filter + hook: output + priority: filter + policy: accept + rules: + - "jump conntrack" + roles: + - nftables + +- hosts: + - infra-1.rtr.infra.auro.re + - infra-2.rtr.infra.auro.re + vars: + nftables__vars: + adm_ipv6: 2a09:6840:128::/56 + adm_ipv4: 10.128.0.0/16 + backbone_ipv6: 2a09:6840:203::/56 + backbone_ipv4: 10.203.0.0/16 + mgmt_ipv6: 2a09:6840:211::/56 + mgmt_ipv4: 10.211.0.0/16 + int_ipv6: 2a09:6840:206::/56 + int_ipv4: 10.206.0.0/16 + local_ipv4: + - 100.64.0.0/10 + - 10.0.0.0/8 + - 45.66.108.0/22 + nftables__tables: + blacklist: + type: inet + sets: + blacklist_ipv6: + type: ipv6_addr + flags: + - interval + blacklist_ipv4: + type: ipv4_addr + flags: + - interval + chains: + filter: + type: filter + hook: prerouting + priority: "raw - 10" + policy: accept + rules: + - "ip6 saddr @blacklist_ipv6 counter drop" + - "ip saddr @blacklist_ipv4 counter drop" + reverse_path_filter: + type: inet + chains: + filter: + type: filter + hook: prerouting + priority: raw + policy: accept + rules: + - "fib saddr . iif oif missing pkttype unicast drop" + filter: + type: inet + chains: + conntrack: + rules: + - "ct state { established, related } accept" + - "ct state invalid counter drop" + input_backbone: + rules: + - "ip6 nexthdr { ospf, vrrp, icmpv6 } accept" + - "ip protocol { ospf, vrrp, icmp } accept" + - "tcp dport 179 accept" + input_mgmt: + rules: + - "ip6 nexthdr icmpv6 accept" + - "ip protocol icmp accept" + - "tcp dport 22 accept" + input_other: + rules: + - "ip6 nexthdr icmpv6 accept" + - "ip protocol icmp accept" + input: + type: filter + hook: input + priority: filter + policy: drop + rules: + - "jump conntrack" + - "iif lo accept" + # FIXME: don't use ifaces + - "ip6 saddr fe80::/10 iifname ens19 goto input_backbone" + - "ip6 saddr vmap { \ + $backbone_ipv6: goto input_backbone, \ + $mgmt_ipv6: goto input_mgmt, \ + $adm_ipv6: goto input_mgmt \ + }" + - "ip saddr vmap { \ + $backbone_ipv4: goto input_backbone, \ + $mgmt_ipv4: goto input_mgmt, \ + $adm_ipv4: goto input_mgmt \ + }" + - "goto input_other" + forward: + type: filter + hook: forward + priority: filter + policy: drop + rules: + - "jump conntrack" + - "ip6 saddr $int_ipv6 accept" # FIXME + - "ip saddr $int_ipv4 accept" # FIXME + output: + type: filter + hook: output + priority: filter + policy: accept + rules: + - "jump conntrack" + nat: + type: ip + chains: + postrouting: + type: nat + hook: postrouting + priority: srcnat + policy: accept + rules: + - "ip daddr != $local_ipv4 snat to 10.128.10.4" + roles: + - nftables +... diff --git a/roles/nftables/defaults/main.yml b/roles/nftables/defaults/main.yml new file mode 100644 index 0000000..2d5bce0 --- /dev/null +++ b/roles/nftables/defaults/main.yml @@ -0,0 +1,4 @@ +--- +nftables__vars: {} +nftables__tables: {} +... diff --git a/roles/nftables/handlers/main.yml b/roles/nftables/handlers/main.yml new file mode 100644 index 0000000..1ba13bd --- /dev/null +++ b/roles/nftables/handlers/main.yml @@ -0,0 +1,6 @@ +--- +- name: Reload nftables + systemd: + name: nftables.service + state: reloaded +... diff --git a/roles/nftables/tasks/main.yml b/roles/nftables/tasks/main.yml new file mode 100644 index 0000000..004c77e --- /dev/null +++ b/roles/nftables/tasks/main.yml @@ -0,0 +1,23 @@ +--- +- name: Install nftables + apt: + name: + - nftables + +- name: Configure nftables + template: + src: nftables.conf.j2 + dest: /etc/nftables.conf + validate: "nft -c -f %s" + owner: root + group: root + mode: u=rw,g=r,o= + notify: + - Reload nftables + +- name: Enable and start nftables + systemd: + name: nftables.service + enabled: true + state: started +... diff --git a/roles/nftables/templates/nftables.conf.j2 b/roles/nftables/templates/nftables.conf.j2 new file mode 100644 index 0000000..7bb2800 --- /dev/null +++ b/roles/nftables/templates/nftables.conf.j2 @@ -0,0 +1,43 @@ +{{ ansible_managed | comment }} + +flush ruleset + +{% for name, value in nftables__vars.items() %} +{% if value is iterable and value is not string %} +define {{ name }} = { {{ value | join(", ") }} } +{% else %} +define {{ name }} = {{ value }} +{% endif %} +{% endfor %} + +{% for name, table in nftables__tables.items() %} +table {{ table.type }} {{ name }} { +{% if table.sets is defined %} +{% for name, set in table.sets.items() %} + set {{ name }} { + type {{ set.type }} +{% if set.flags is defined %} + flags {{ set.flags | join(", ") }} +{% endif %} +{% if set.elements is defined %} + elements = { {{ set.elements | join(", ") }} } +{% endif %} + } +{% endfor %} +{% endif %} +{% if table.chains is defined %} +{% for name, chain in table.chains.items() | default({}) %} + chain {{ name }} { +{% if chain.hook is defined %} + type {{ chain.type }} hook {{ chain.hook }} priority {{ chain.priority }} + policy {{ chain.policy }} +{% endif %} +{% for rule in chain.rules %} + {{ rule | indent }} +{% endfor %} + } +{% endfor %} +{% endif %} +} + +{% endfor %}