diff --git a/host_vars/infra-1.router.auro.re.yml b/host_vars/infra-1.router.auro.re.yml new file mode 100644 index 0000000..fa6903b --- /dev/null +++ b/host_vars/infra-1.router.auro.re.yml @@ -0,0 +1,27 @@ +--- +network: + vlan111: + mac_addr: 96:5a:21:48:4a:e5 + vlan128: + mac_addr: 9e:9a:f3:37:a6:2e + vlan129: + mac_addr: 46:dd:ed:55:70:2f + ipv4_addrs: + - 10.129.0.245/16 + ipv6_addrs: + - 2a09:6840:129:0:245::/48 + vlan130: + mac_addr: 8a:ad:f7:04:82:2e + vlan131: + mac_addr: 16:6d:4f:53:fc:28 + vlan133: + mac_addr: 12:ad:28:d5:31:fa + vlan134: + mac_addr: 0e:54:e9:97:c0:5b + vlan135: + mac_addr: ea:f6:32:c3:8b:2c + ipv4_addrs: + - 10.135.0.1/16 + ipv6_addrs: + - 2a09:6840:135:0:1::/48 +... diff --git a/host_vars/infra-2.router.auro.re.yml b/host_vars/infra-2.router.auro.re.yml new file mode 100644 index 0000000..0c81228 --- /dev/null +++ b/host_vars/infra-2.router.auro.re.yml @@ -0,0 +1,27 @@ +--- +network: + vlan111: + mac_addr: 02:ec:c1:23:5d:a3 + vlan128: + mac_addr: a2:24:08:dc:b6:cc + vlan129: + mac_addr: 92:29:ba:00:26:e2 + ipv4_addrs: + - 10.129.0.246/16 + ipv6_addrs: + - 2a09:6840:129:0:246::/48 + vlan130: + mac_addr: 4a:b6:84:e1:8e:4a + vlan131: + mac_addr: ca:10:8d:cc:87:9d + vlan133: + mac_addr: 1e:08:7c:41:1a:bd + vlan134: + mac_addr: 2e:5f:f9:55:07:d2 + vlan135: + mac_addr: 6e:f2:b5:05:fc:c3 + ipv4_addrs: + - 10.135.0.2/16 + ipv6_addrs: + - 2a09:6840:135:0:2::/48 +... diff --git a/playbooks/router.yml b/playbooks/router.yml index c273f0d..7b1b9bd 100755 --- a/playbooks/router.yml +++ b/playbooks/router.yml @@ -1,23 +1,185 @@ #!/usr/bin/env ansible-playbook --- -# Deploy firewall and keepalived -# radvd: IPv6 SLAAC (/64 subnets, private IPs). -# Must NOT be on routeur-aurore-*, or will with DHCPv6! -- hosts: ~routeur-(pacaterie|edc|fleming|gs|rives).*\.adm\.auro\.re +- hosts: + - infra-1.router.auro.re + - infra-2.router.auro.re vars: - update_motd: - unbound: Le routage (avec radvd) est déployé. + networkd_interfaces: + vlan111: + mac_addr: "{{ network.vlan111.mac_addr }}" + link_local: false + forward: true + vlan128: + mac_addr: "{{ network.vlan128.mac_addr }}" + link_local: false + forward: true + vlan129: + mac_addr: "{{ network.vlan129.mac_addr }}" + ip_addrs: "{{ network.vlan129.ipv4_addrs + + network.vlan129.ipv6_addrs }}" + forward: true + vlan130: + mac_addr: "{{ network.vlan130.mac_addr }}" + link_local: false + forward: true + vlan131: + mac_addr: "{{ network.vlan131.mac_addr }}" + link_local: false + forward: true + vlan133: + mac_addr: "{{ network.vlan133.mac_addr }}" + link_local: false + forward: true + vlan134: + mac_addr: "{{ network.vlan134.mac_addr }}" + link_local: false + forward: true + vlan135: + mac_addr: "{{ network.vlan135.mac_addr }}" + ip_addrs: "{{ network.vlan135.ipv4_addrs + + network.vlan135.ipv6_addrs }}" + forward: true roles: - - router - - radvd - - update_motd + - systemd_networkd -# No radvd here -- hosts: ~routeur-aurore.*\.adm\.auro\.re +- hosts: + - infra-1.router.auro.re + - infra-2.router.auro.re vars: - update_motd: - unbound: Le routage (avec DHCPv6) est déployé. + bird_router_id: "{{ network.vlan129.ipv4_addrs[0] | ipaddr('address') }}" + bird_ospf_src: "{{ network.vlan135.ipv4_addrs[0] | ipaddr('address') }}" + bird_ospf_src_v6: "{{ network.vlan135.ipv6_addrs[0] | ipaddr('address') }}" + bird_ospf_interfaces: + vlan111: + stub: true + vlan128: + stub: true + vlan129: + broadcast: true + vlan130: + stub: true + vlan131: + stub: true + vlan133: + stub: true + vlan134: + stub: true roles: - - router - - ipv6_edge_router - - update_motd + - bird + +- hosts: + - infra-1.router.auro.re + - infra-2.router.auro.re + vars: + keepalived_notify_master: "/usr/local/sbin/conntrackd_vrrp primary" + keepalived_notify_backup: "/usr/local/sbin/conntrackd_vrrp backup" + keepalived_notify_fault: "/usr/local/sbin/conntrackd_vrrp fault" + keepalived_virtual_router_id: 42 + keepalived_interface: vlan129 + keepalived_virtual_ipv4_addrs: + vlan111: + - 45.66.111.10/24 # 45.66.111.1/24 + vlan128: + - 10.128.0.16/16 # 10.128.0.1/16 + vlan130: + - 10.130.0.185/16 # 10.130.0.1/16 + vlan131: + - 10.131.0.1/16 + vlan133: + - 10.133.0.1/16 + vlan134: + - 10.134.0.1/16 + keepalived_virtual_ipv6_addrs: + vlan111: + - fe80::200:02ff:fe23:ae26/64 + - 2a09:6840:111:0:10::/56 # 2a09:6840:111:0:1::/56 + vlan128: + - fe80::200:02ff:fe9f:d67a/64 + - 2a09:6840:128:0:16::/48 # 2a09:6840:128:0:1::/48 + vlan130: + - fe80::200:02ff:fee2:9782/64 + - 2a09:6840:130:0:185::/48 # 2a09:6840:130:0:1::/48 + vlan131: + - fe80::200:02ff:fee2:9782/64 + - 2a09:6840:131:0:1::/48 + vlan133: + - fe80::200:02ff:fe8a:0cbc/64 + - 2a09:6840:133:0:1::/48 + vlan134: + - fe80::200:02ff:fe09:38f7/64 + - 2a09:6840:134:0:1::/48 + roles: + - keepalived + +- hosts: + - infra-1.router.auro.re + vars: + conntrackd_ignore_addrs_ipv6: + - ::/128 + - 2a09:6840:111:0:10::/64 + - 2a09:6840:128:0:16::/64 + - 2a09:6840:129:0:245::/64 + - 2a09:6840:129:0:246::/64 + - 2a09:6840:130:0:185::/64 + - 2a09:6840:131:0:248::/64 + - 2a09:6840:133:0:1::/64 + - 2a09:6840:134:0:1::/64 + - 2a09:6840:135:0:1::/64 + - 2a09:6840:135:0:2::/64 + conntrackd_ignore_addrs_ipv4: + - 127.0.0.1/8 + - 45.66.111.10 + - 10.128.0.16 + - 10.129.0.245 + - 10.129.0.246 + - 10.130.0.185 + - 10.131.0.248 + - 10.133.0.1 + - 10.134.0.1 + - 10.135.0.1 + - 10.135.0.2 + conntrackd_udp_dest_ipv6: 10.129.0.246 + conntrackd_udp_listen_ipv6: 10.129.0.245 + conntrackd_udp_iface: vlan129 + roles: + - conntrackd + +- hosts: + - infra-2.router.auro.re + vars: + conntrackd_ignore_addrs_ipv6: + - ::/128 + - 2a09:6840:111:0:10::/64 + - 2a09:6840:128:0:16::/64 + - 2a09:6840:129:0:245::/64 + - 2a09:6840:129:0:246::/64 + - 2a09:6840:130:0:185::/64 + - 2a09:6840:131:0:248::/64 + - 2a09:6840:133:0:1::/64 + - 2a09:6840:134:0:1::/64 + - 2a09:6840:135:0:1::/64 + - 2a09:6840:135:0:2::/64 + conntrackd_ignore_addrs_ipv4: + - 127.0.0.1/8 + - 45.66.111.10 + - 10.128.0.16 + - 10.129.0.245 + - 10.129.0.246 + - 10.130.0.185 + - 10.131.0.248 + - 10.133.0.1 + - 10.134.0.1 + - 10.135.0.1 + - 10.135.0.2 + conntrackd_udp_dest_ipv6: 10.129.0.245 + conntrackd_udp_listen_ipv6: 10.129.0.246 + conntrackd_udp_iface: vlan129 + roles: + - conntrackd + +- hosts: + - infra-1.router.auro.re + - infra-2.router.auro.re + roles: + - nftables_infra +... diff --git a/playbooks/router_old.yml b/playbooks/router_old.yml new file mode 100755 index 0000000..c273f0d --- /dev/null +++ b/playbooks/router_old.yml @@ -0,0 +1,23 @@ +#!/usr/bin/env ansible-playbook +--- +# Deploy firewall and keepalived +# radvd: IPv6 SLAAC (/64 subnets, private IPs). +# Must NOT be on routeur-aurore-*, or will with DHCPv6! +- hosts: ~routeur-(pacaterie|edc|fleming|gs|rives).*\.adm\.auro\.re + vars: + update_motd: + unbound: Le routage (avec radvd) est déployé. + roles: + - router + - radvd + - update_motd + +# No radvd here +- hosts: ~routeur-aurore.*\.adm\.auro\.re + vars: + update_motd: + unbound: Le routage (avec DHCPv6) est déployé. + roles: + - router + - ipv6_edge_router + - update_motd diff --git a/roles/bird/defaults/main.yml b/roles/bird/defaults/main.yml new file mode 100644 index 0000000..eca72f6 --- /dev/null +++ b/roles/bird/defaults/main.yml @@ -0,0 +1,3 @@ +--- +bird_ospf_interfaces: {} +... diff --git a/roles/bird/handlers/main.yml b/roles/bird/handlers/main.yml new file mode 100644 index 0000000..66a62cd --- /dev/null +++ b/roles/bird/handlers/main.yml @@ -0,0 +1,11 @@ +--- +- name: Reload bird + systemd: + name: bird.service + state: reloaded + +- name: Reload bird6 + systemd: + name: bird6.service + state: reloaded +... diff --git a/roles/bird/tasks/main.yml b/roles/bird/tasks/main.yml new file mode 100644 index 0000000..40d1e87 --- /dev/null +++ b/roles/bird/tasks/main.yml @@ -0,0 +1,37 @@ +--- +- name: Install bird + apt: + name: bird + +- name: Configure bird + template: + src: bird.conf + dest: /etc/bird/bird.conf + owner: root + group: bird + mode: u=rw,g=r,o= + notify: + - Reload bird + +- name: Configure bird6 + template: + src: bird6.conf + dest: /etc/bird/bird6.conf + owner: root + group: bird + mode: u=rw,g=r,o= + notify: + - Reload bird6 + +- name: Enable and start bird + systemd: + name: bird.service + enabled: true + state: started + +- name: Enable and start bird6 + systemd: + name: bird6.service + enabled: true + state: started +... diff --git a/roles/bird/templates/bird.conf b/roles/bird/templates/bird.conf new file mode 100644 index 0000000..886dafb --- /dev/null +++ b/roles/bird/templates/bird.conf @@ -0,0 +1,37 @@ +{{ ansible_managed | comment }} + +log syslog all; + +router id {{ bird_router_id }}; + +protocol kernel { + scan time 60; + import none; + export all; + persist; +} + +protocol device { + scan time 60; +} + +protocol ospf backbone { + import filter { +{% if bird_ospf_src_v6 is defined %} + krt_prefsrc = {{ bird_ospf_src }}; +{% endif %} + accept; + }; + export all; + area 0 { +{% for name, iface in bird_ospf_interfaces.items() %} + interface "{{ name }}" { +{% if iface.stub | default(false) %} + stub; +{% elif iface.broadcast | default(false) %} + type broadcast; +{% endif %} + }; +{% endfor %} + }; +} diff --git a/roles/bird/templates/bird6.conf b/roles/bird/templates/bird6.conf new file mode 100644 index 0000000..ae121b7 --- /dev/null +++ b/roles/bird/templates/bird6.conf @@ -0,0 +1,37 @@ +{{ ansible_managed | comment }} + +log syslog all; + +router id {{ bird_router_id }}; + +protocol kernel { + scan time 60; + import none; + export all; + persist; +} + +protocol device { + scan time 60; +} + +protocol ospf backbone { + import filter { +{% if bird_ospf_src_v6 is defined %} + krt_prefsrc = {{ bird_ospf_src_v6 }}; +{% endif %} + accept; + }; + export all; + area 0 { +{% for name, iface in bird_ospf_interfaces.items() %} + interface "{{ name }}" { +{% if iface.stub | default(false) %} + stub; +{% elif iface.broadcast | default(false) %} + type broadcast; +{% endif %} + }; +{% endfor %} + }; +} diff --git a/roles/conntrackd/defaults/main.yml b/roles/conntrackd/defaults/main.yml new file mode 100644 index 0000000..8165c05 --- /dev/null +++ b/roles/conntrackd/defaults/main.yml @@ -0,0 +1,13 @@ +--- +conntrackd_hash_size: 8192 +conntrackd_hash_limit: 65535 +conntrackd_socket_buffer_size: 262142 +conntrackd_socket_buffer_size_max: 655355 +conntrackd_ignore_addrs_ipv6: [] +conntrackd_ignore_addrs_ipv4: [] +conntrackd_ftfw_commit_timeout: 1800 +conntrackd_ftfw_purge_timeout: 5 +conntrackd_udp_listen_port: 3780 +conntrackd_udp_send_buffer: 1249280 +conntrackd_udp_receive_buffer: 1249280 +... diff --git a/roles/conntrackd/handlers/main.yml b/roles/conntrackd/handlers/main.yml new file mode 100644 index 0000000..afdd941 --- /dev/null +++ b/roles/conntrackd/handlers/main.yml @@ -0,0 +1,6 @@ +--- +- name: Restart conntrackd + systemd: + name: conntrackd + state: restarted +... diff --git a/roles/conntrackd/tasks/main.yml b/roles/conntrackd/tasks/main.yml new file mode 100644 index 0000000..c34f5ba --- /dev/null +++ b/roles/conntrackd/tasks/main.yml @@ -0,0 +1,29 @@ +--- +- name: Install conntrackd + apt: + name: conntrackd + +- name: Configure conntrackd + template: + src: conntrackd.conf.j2 + dest: /etc/conntrackd/conntrackd.conf + owner: root + group: root + mode: u=rw,g=r,o=r + notify: + - Restart conntrackd + +- name: Install conntrackd_vrrp script + template: + src: conntrackd_vrrp.j2 + dest: /usr/local/sbin/conntrackd_vrrp + owner: root + group: root + mode: u=rwx,g=r,o=r + +- name: Enable and start conntrackd + systemd: + name: conntrackd + enabled: true + state: started +... diff --git a/roles/conntrackd/templates/conntrackd.conf.j2 b/roles/conntrackd/templates/conntrackd.conf.j2 new file mode 100644 index 0000000..d482c0d --- /dev/null +++ b/roles/conntrackd/templates/conntrackd.conf.j2 @@ -0,0 +1,53 @@ +{{ ansible_managed | comment}} + +General { + HashSize {{ conntrackd_hash_size }} + HashLimit {{ conntrackd_hash_limit }} + + Syslog on + + LockFile /var/log/conntrackd.lock + + UNIX { + Path /var/run/conntrackd.sock + } + + SocketBufferSize {{ conntrackd_socket_buffer_size }} + SocketBufferSizeMaxGrown {{ conntrackd_socket_buffer_size_max }} + + Systemd on + + Filter From Userspace { + Protocol Accept { + TCP + UDP + } + Address Ignore { +{% for addr in conntrackd_ignore_addrs_ipv6 %} + IPv6_address {{ addr }} +{% endfor %} +{% for addr in conntrackd_ignore_addrs_ipv4 %} + IPv4_address {{ addr }} +{% endfor %} + } + } +} + +Sync { + Mode FTFW { + DisableExternalCache off + StartupResync on + CommitTimeout {{ conntrackd_ftfw_commit_timeout }} + PurgeTimeout {{ conntrackd_ftfw_purge_timeout }} + } + + UDP { + IPv6_address {{ conntrackd_udp_listen_ipv6 }} + IPv4_Destination_Address {{ conntrackd_udp_dest_ipv6 }} + Port {{ conntrackd_udp_listen_port }} + Interface {{ conntrackd_udp_iface }} + SndSocketBuffer {{ conntrackd_udp_send_buffer }} + RcvSocketBuffer {{ conntrackd_udp_receive_buffer }} + Checksum on + } +} diff --git a/roles/conntrackd/templates/conntrackd_vrrp.j2 b/roles/conntrackd/templates/conntrackd_vrrp.j2 new file mode 100644 index 0000000..5fdfaab --- /dev/null +++ b/roles/conntrackd/templates/conntrackd_vrrp.j2 @@ -0,0 +1,129 @@ +#!/bin/sh + +{{ ansible_managed | comment }} + +# +# (C) 2006-2011 by Pablo Neira Ayuso +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# Description: +# +# This is the script for primary-backup setups for keepalived +# (http://www.keepalived.org). You may adapt it to make it work with other +# high-availability managers. +# +# Do not forget to include the required modifications to your keepalived.conf +# file to invoke this script during keepalived's state transitions. +# +# Contributions to improve this script are welcome :). +# + +CONNTRACKD_BIN=/usr/sbin/conntrackd +CONNTRACKD_LOCK=/var/lock/conntrack.lock +CONNTRACKD_CONFIG=/etc/conntrackd/conntrackd.conf + +case "$1" in + primary) + # + # commit the external cache into the kernel table + # + $CONNTRACKD_BIN -C $CONNTRACKD_CONFIG -c + if [ $? -eq 1 ] + then + logger "ERROR: failed to invoke conntrackd -c" + fi + + # + # flush the internal and the external caches + # + $CONNTRACKD_BIN -C $CONNTRACKD_CONFIG -f + if [ $? -eq 1 ] + then + logger "ERROR: failed to invoke conntrackd -f" + fi + + # + # resynchronize my internal cache to the kernel table + # + $CONNTRACKD_BIN -C $CONNTRACKD_CONFIG -R + if [ $? -eq 1 ] + then + logger "ERROR: failed to invoke conntrackd -R" + fi + + # + # send a bulk update to backups + # + $CONNTRACKD_BIN -C $CONNTRACKD_CONFIG -B + if [ $? -eq 1 ] + then + logger "ERROR: failed to invoke conntrackd -B" + fi + ;; + backup) + # + # is conntrackd running? request some statistics to check it + # + $CONNTRACKD_BIN -C $CONNTRACKD_CONFIG -s + if [ $? -eq 1 ] + then + # + # something's wrong, do we have a lock file? + # + if [ -f $CONNTRACKD_LOCK ] + then + logger "WARNING: conntrackd was not cleanly stopped." + logger "If you suspect that it has crashed:" + logger "1) Enable coredumps" + logger "2) Try to reproduce the problem" + logger "3) Post the coredump to netfilter-devel@vger.kernel.org" + rm -f $CONNTRACKD_LOCK + fi + $CONNTRACKD_BIN -C $CONNTRACKD_CONFIG -d + if [ $? -eq 1 ] + then + logger "ERROR: cannot launch conntrackd" + exit 1 + fi + fi + # + # shorten kernel conntrack timers to remove the zombie entries. + # + $CONNTRACKD_BIN -C $CONNTRACKD_CONFIG -t + if [ $? -eq 1 ] + then + logger "ERROR: failed to invoke conntrackd -t" + fi + + # + # request resynchronization with master firewall replica (if any) + # Note: this does nothing in the alarm approach. + # + $CONNTRACKD_BIN -C $CONNTRACKD_CONFIG -n + if [ $? -eq 1 ] + then + logger "ERROR: failed to invoke conntrackd -n" + fi + ;; + fault) + # + # shorten kernel conntrack timers to remove the zombie entries. + # + $CONNTRACKD_BIN -C $CONNTRACKD_CONFIG -t + if [ $? -eq 1 ] + then + logger "ERROR: failed to invoke conntrackd -t" + fi + ;; + *) + logger "ERROR: unknown state transition" + echo "Usage: $0 {primary|backup|fault}" + exit 1 + ;; +esac + +exit 0 diff --git a/roles/keepalived/handlers/main.yml b/roles/keepalived/handlers/main.yml new file mode 100644 index 0000000..df390cb --- /dev/null +++ b/roles/keepalived/handlers/main.yml @@ -0,0 +1,6 @@ +--- +- name: Reload keepalived + systemd: + name: keepalived.service + state: reloaded +... diff --git a/roles/keepalived/tasks/main.yml b/roles/keepalived/tasks/main.yml new file mode 100644 index 0000000..6889024 --- /dev/null +++ b/roles/keepalived/tasks/main.yml @@ -0,0 +1,21 @@ +--- +- name: Install keepalived + apt: + name: keepalived + +- name: Configure keepalived + template: + src: keepalived.conf + dest: /etc/keepalived/keepalived.conf + owner: root + group: root + mode: u=rw,g=,o= + notify: + - Reload keepalived + +- name: Enable and start keepalived + systemd: + name: keepalived + enabled: true + state: started +... diff --git a/roles/keepalived/templates/keepalived.conf b/roles/keepalived/templates/keepalived.conf new file mode 100644 index 0000000..878fdb2 --- /dev/null +++ b/roles/keepalived/templates/keepalived.conf @@ -0,0 +1,58 @@ +{{ ansible_managed | comment }} + +global_defs { + dynamic_interfaces + script_user root + enable_script_security + vrrp_version 3 +} + +vrrp_sync_group group { + group { + instance_v4 + instance_v6 + } +{% if keepalived_notify_master %} + notify_master "{{ keepalived_notify_master }}" +{% endif %} +{% if keepalived_notify_backup is defined %} + notify_backup "{{ keepalived_notify_backup }}" +{% endif %} +{% if keepalived_notify_fault is defined %} + notify_fault "{{ keepalived_notify_fault }}" +{% endif %} +} + +vrrp_instance instance_v4 { + virtual_router_id {{ keepalived_virtual_router_id }} + interface {{ keepalived_interface }} + state BACKUP + priority 250 + nopreempt + advert_int 1 + accept + virtual_ipaddress { +{% for dev, addrs in keepalived_virtual_ipv4_addrs.items() %} +{% for addr in addrs %} + {{ addr }} dev {{ dev }} +{% endfor %} +{% endfor %} + } +} + +vrrp_instance instance_v6 { + virtual_router_id {{ keepalived_virtual_router_id }} + interface {{ keepalived_interface }} + state BACKUP + priority 250 + nopreempt + advert_int 1 + accept + virtual_ipaddress { +{% for dev, addrs in keepalived_virtual_ipv6_addrs.items() %} +{% for addr in addrs %} + {{ addr }} dev {{ dev }} +{% endfor %} +{% endfor %} + } +} 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..d640463 --- /dev/null +++ b/roles/nftables_infra/templates/nftables.d/10-vars.conf.j2 @@ -0,0 +1,79 @@ +{{ 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 bastion_ipv6 = 2a09:6840:136::/48 +define bastion_ipv4 = 10.136.0.0/16 + +define infra_ipv6 = { + $public_server_ipv6, + $server_ipv6, + $backbone_ipv6, + $ups_ipv6, + $bmc_ipv6, + $pve_ipv6, + $router_ipv6, + $bastion_ipv6, +} +define infra_ipv4 = { + $public_server_ipv4, + $server_ipv4, + $backbone_ipv4, + $ups_ipv4, + $bmc_ipv4, + $pve_ipv4, + $router_ipv4, + $bastion_ipv4, +} + +# FIXME: temporary +define egress_internet_ipv6 = { + $server_ipv6, + $pve_ipv6, + $router_ipv6, + $bastion_ipv6, +} +define egress_internet_ipv4 = { + $server_ipv4, + $pve_ipv4, + $router_ipv4, + $bastion_ipv4, +} + +define aurore_ipv4 = { + 10.0.0.0/8, + 45.66.108.0/22, +} + +define need_nat_ipv4 = { + 10.0.0.0/8, +} + +define nat_public_ipv4 = 45.66.111.10 + +# FIXME: bad ipv6 address +define log_infra_ipv6 = 2a09:6840:128::241/128 +define log_infra_ipv4 = 10.128.0.241 + +# FIXME: bad ipv6 address +define prom_infra_ipv6 = 2a09:6840:128::67/128 +define prom_infra_ipv4 = 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..a7b8333 --- /dev/null +++ b/roles/nftables_infra/templates/nftables.d/40-input.conf.j2 @@ -0,0 +1,70 @@ +{{ ansible_managed | comment }} + +table inet input { + + chain conntrack { + ct state vmap { + established: accept, + related: accept, + invalid: drop, + } + } + + chain input_from_server { + jump conntrack + + ip6 saddr $prom_infra_ipv6 tcp dport 9100 accept + ip saddr $prom_infra_ipv4 tcp dport 9100 accept + } + + 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_bastion { + 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..ee9840e --- /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: accept, + related: accept, + invalid: 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..f15813b --- /dev/null +++ b/roles/nftables_infra/templates/nftables.d/60-forward.conf.j2 @@ -0,0 +1,116 @@ +{{ ansible_managed | comment }} + +table inet forward { + + chain conntrack { + ct state vmap { + established: accept, + related: accept, + invalid: 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_ipv6 tcp dport 9100 counter accept + ip saddr $prom_infra_ipv4 udp dport 161 counter accept + + ip6 saddr $bastion_ipv6 tcp dport ssh accept + ip saddr $bastion_ipv4 tcp dport ssh accept + } + + chain forward_to_backbone { + } + + chain forward_to_ups { + jump conntrack + + ip6 saddr $prom_infra_ipv6 udp dport 161 counter accept + ip saddr $prom_infra_ipv4 udp dport 161 counter accept + + ip6 saddr $bastion_ipv6 tcp dport ssh accept + ip saddr $bastion_ipv4 tcp dport ssh accept + } + + chain forward_to_bmc { + jump conntrack + + ip6 saddr $prom_infra_ipv6 udp dport 161 counter accept + ip saddr $prom_infra_ipv4 udp dport 161 counter accept + + ip6 saddr $bastion_ipv6 tcp dport ssh accept + ip saddr $bastion_ipv4 tcp dport ssh 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 + + ip6 saddr $bastion_ipv6 tcp dport ssh accept + ip saddr $bastion_ipv4 tcp dport ssh 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 + + ip6 saddr $bastion_ipv6 tcp dport ssh accept + ip saddr $bastion_ipv4 tcp dport ssh 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..dd6fa6a --- /dev/null +++ b/roles/nftables_infra/templates/nftables.d/70-nat.conf.j2 @@ -0,0 +1,19 @@ +{{ ansible_managed | comment }} + +table ip nat { + + chain postrouting { + type nat hook postrouting priority srcnat + policy accept + + iif lo return + + # Is there any other way to do that? + meta pkttype { multicast, broadcast } return + ip daddr 224.0.0.0/24 return + + ip saddr $need_nat_ipv4 ip daddr != $aurore_ipv4 \ + snat $nat_public_ipv4 persistent + } + +} diff --git a/roles/systemd_networkd/handlers/main.yml b/roles/systemd_networkd/handlers/main.yml new file mode 100644 index 0000000..3733060 --- /dev/null +++ b/roles/systemd_networkd/handlers/main.yml @@ -0,0 +1,20 @@ +--- +- name: Update initramfs + command: + cmd: update-initramfs -u + +- name: Restart systemd-networkd + systemd: + name: systemd-networkd.service + state: restarted + +- name: Reboot required + file: + path: /var/run/reboot-required + state: touch + modification_time: preserve + access_time: preserve + owner: root + group: root + mode: u=rw,g=r,o=r +... diff --git a/roles/systemd_networkd/tasks/main.yml b/roles/systemd_networkd/tasks/main.yml new file mode 100644 index 0000000..13327e2 --- /dev/null +++ b/roles/systemd_networkd/tasks/main.yml @@ -0,0 +1,30 @@ +--- +- name: Configure interfaces links + template: + src: link.j2 + dest: "/etc/systemd/network/10-{{ item.key }}.link" + owner: root + group: systemd-network + mode: u=rw,g=r,o= + loop: "{{ networkd_interfaces | dict2items }}" + notify: + - Update initramfs + - Reboot required + +- name: Configure interfaces networks + template: + src: network.j2 + dest: "/etc/systemd/network/10-{{ item.key }}.network" + owner: root + group: systemd-network + mode: u=rw,g=r,o= + loop: "{{ networkd_interfaces | dict2items }}" + notify: + - Restart systemd-networkd + +- name: Enable and start systemd-networkd + systemd: + name: systemd-networkd.service + enabled: true + state: started +... diff --git a/roles/systemd_networkd/templates/link.j2 b/roles/systemd_networkd/templates/link.j2 new file mode 100644 index 0000000..1f0b48a --- /dev/null +++ b/roles/systemd_networkd/templates/link.j2 @@ -0,0 +1,7 @@ +{{ ansible_managed | comment }} + +[Match] +MACAddress={{ item.value.mac_addr }} + +[Link] +Name={{ item.key }} diff --git a/roles/systemd_networkd/templates/network.j2 b/roles/systemd_networkd/templates/network.j2 new file mode 100644 index 0000000..155b173 --- /dev/null +++ b/roles/systemd_networkd/templates/network.j2 @@ -0,0 +1,18 @@ +{{ ansible_managed | comment }} + +[Match] +Name={{ item.key }} + +[Network] +LinkLocalAddressing={{ item.value.link_local | default(true) + | ternary("ipv6", "no") }} +IPForward={{ item.value.forward | default(false) + | ternary("yes", "no") }} + +{% for addr in item.value.ip_addrs | default([]) %} +[Address] +Address={{ addr }} +{% endfor %} + +[FairQueueingControlledDelay] +Parent=root