Create role for nftables router
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
This commit is contained in:
parent
22c970d9b4
commit
592d3a630a
10 changed files with 394 additions and 0 deletions
|
@ -26,6 +26,8 @@ bird_router_prefsrc: 10.132.0.254
|
||||||
bird_ospf_ifaces:
|
bird_ospf_ifaces:
|
||||||
ens19:
|
ens19:
|
||||||
stub: true
|
stub: true
|
||||||
|
ens20:
|
||||||
|
stub: true
|
||||||
gs:
|
gs:
|
||||||
type: pointopoint
|
type: pointopoint
|
||||||
cost: 2000
|
cost: 2000
|
||||||
|
|
7
roles/nftables_router/handlers/main.yml
Normal file
7
roles/nftables_router/handlers/main.yml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
- name: Reload nftables
|
||||||
|
become: true
|
||||||
|
systemd:
|
||||||
|
name: nftables.service
|
||||||
|
state: reloaded
|
||||||
|
...
|
38
roles/nftables_router/tasks/main.yml
Normal file
38
roles/nftables_router/tasks/main.yml
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
---
|
||||||
|
- name: Install nftables
|
||||||
|
become: true
|
||||||
|
apt:
|
||||||
|
name: nftables
|
||||||
|
state: latest
|
||||||
|
|
||||||
|
- name: Create nftables.d directory
|
||||||
|
become: true
|
||||||
|
file:
|
||||||
|
path: /etc/nftables.d
|
||||||
|
state: directory
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: u=rwx,g=rx,o=
|
||||||
|
|
||||||
|
- name: Configure nftables
|
||||||
|
become: true
|
||||||
|
template:
|
||||||
|
src: "{{ item }}.j2"
|
||||||
|
dest: "/etc/{{ item }}"
|
||||||
|
loop:
|
||||||
|
- nftables.d/10-vars.conf
|
||||||
|
- nftables.d/20-blacklist.conf
|
||||||
|
- nftables.d/30-rp-filter.conf
|
||||||
|
- nftables.d/40-signup.conf
|
||||||
|
- nftables.d/50-filter.conf
|
||||||
|
- nftables.d/60-nat.conf
|
||||||
|
- nftables.conf
|
||||||
|
notify: Reload nftables
|
||||||
|
|
||||||
|
- name: Enable and start nftables
|
||||||
|
become: true
|
||||||
|
systemd:
|
||||||
|
name: nftables.service
|
||||||
|
state: started
|
||||||
|
enabled: true
|
||||||
|
...
|
5
roles/nftables_router/templates/nftables.conf.j2
Normal file
5
roles/nftables_router/templates/nftables.conf.j2
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{{ ansible_managed | comment }}
|
||||||
|
|
||||||
|
flush ruleset
|
||||||
|
|
||||||
|
include "/etc/nftables.d/*.conf"
|
55
roles/nftables_router/templates/nftables.d/10-vars.conf.j2
Normal file
55
roles/nftables_router/templates/nftables.d/10-vars.conf.j2
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
{{ ansible_managed | comment }}
|
||||||
|
|
||||||
|
## Interconnexion
|
||||||
|
|
||||||
|
# Réseaux d'interconnexion
|
||||||
|
define interco_v4 = { 192.168.0.0/31, 192.168.0.2/31, 10.129.0.0/16 }
|
||||||
|
define interco_v6 = { 2a09:6840:129::0/48 }
|
||||||
|
|
||||||
|
|
||||||
|
## Administration
|
||||||
|
|
||||||
|
# Réseaux d'administration
|
||||||
|
define adm_v4 = { 10.128.0.0/16, 10.133.0.0/16 }
|
||||||
|
define adm_v6 = { 2a09:6840:128::0/48, 2a09:6840:133::0/48 }
|
||||||
|
|
||||||
|
# Serveurs de centralisation des journaux
|
||||||
|
define syslog_adm_v4 = { 10.128.0.51 }
|
||||||
|
define syslog_adm_v6 = { 2a09:6840:128::251 }
|
||||||
|
|
||||||
|
# Adresses des bastions autorisés
|
||||||
|
define bastion_v4 = { 10.128.0.224, 10.133.0.250 }
|
||||||
|
define bastion_v6 = { 2a09:6840:133::250 }
|
||||||
|
|
||||||
|
|
||||||
|
## Services
|
||||||
|
|
||||||
|
# Réseaux de services privés
|
||||||
|
define svc_v4 = { 10.132.0.0/16 }
|
||||||
|
define svc_v6 = { 2a09:6840:132::0/48 }
|
||||||
|
|
||||||
|
|
||||||
|
## Adhérents
|
||||||
|
|
||||||
|
# Réseaux des adhérents
|
||||||
|
define member_v4 = { 10.50.0.0/16 }
|
||||||
|
define member_v6 = { 2a09:6840:50::0/48 }
|
||||||
|
|
||||||
|
# Sous-réseau d'inscription des adhérents
|
||||||
|
define signup_v4 = { 10.50.0.0/16 }
|
||||||
|
define signup_v6 = { 2a09:6840:50::0/48 }
|
||||||
|
|
||||||
|
# Hôtes déclencheurs d'accès à Internet pour inscription
|
||||||
|
define signup_trigger_v4 = { 1.1.1.1 }
|
||||||
|
define signup_trigger_v6 = { 2606:4700:4700::1111 }
|
||||||
|
|
||||||
|
|
||||||
|
## NAT
|
||||||
|
|
||||||
|
# Interface sur laquelle appliquer le NAT
|
||||||
|
define wan_iface = "ens18"
|
||||||
|
|
||||||
|
define member_priv_v4 = { 10.50.0.0/16 }
|
||||||
|
define member_nat_v4 = 92.222.211.198
|
||||||
|
|
||||||
|
define any_nat_v4 = 92.222.211.198
|
|
@ -0,0 +1,31 @@
|
||||||
|
{{ ansible_managed | comment }}
|
||||||
|
|
||||||
|
table inet blacklist {
|
||||||
|
|
||||||
|
set blacklist_v4 {
|
||||||
|
type ipv4_addr
|
||||||
|
flags interval
|
||||||
|
}
|
||||||
|
|
||||||
|
set blacklist_v6 {
|
||||||
|
type ipv6_addr
|
||||||
|
flags interval
|
||||||
|
}
|
||||||
|
|
||||||
|
# Compteur des paquets ignorés car les adresses étaient en liste noire
|
||||||
|
counter blacklist {}
|
||||||
|
|
||||||
|
# Cette chaîne est appliquée très tôt (avant le conntrack entre autres)
|
||||||
|
# afin de limiter autant que possible l'impact des hôtes en liste noire
|
||||||
|
# (notamment en cas d'attaque par déni de service)
|
||||||
|
chain filter {
|
||||||
|
type filter hook prerouting priority -310
|
||||||
|
policy accept
|
||||||
|
|
||||||
|
# On ne journalise pas pour limiter la charge sur les serveurs de
|
||||||
|
# journalisation
|
||||||
|
ip saddr @blacklist_v4 counter name blacklist drop
|
||||||
|
ip6 saddr @blacklist_v6 counter name blacklist drop
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
{{ ansible_managed | comment }}
|
||||||
|
|
||||||
|
# Simule le comportement de rp_filter=1, mais avec support d'IPv6 (ce qui
|
||||||
|
# n'est pas le cas de l'implémentation du noyau)
|
||||||
|
#
|
||||||
|
# https://wiki.nftables.org/wiki-nftables/index.php/Routing_information
|
||||||
|
# Le "eq 0" n'est pas très joli, mais ça semble être la façon
|
||||||
|
# "normale" de le faire
|
||||||
|
# Voir : https://netdevconf.info/1.2/slides/oct6/08_nft_netdev12_florian.pdf
|
||||||
|
table inet reverse_path_filter {
|
||||||
|
|
||||||
|
chain filter {
|
||||||
|
type filter hook prerouting priority -300
|
||||||
|
policy accept
|
||||||
|
|
||||||
|
fib saddr . iif oif eq 0 \
|
||||||
|
log prefix "rp-filter" group 0 counter drop
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
48
roles/nftables_router/templates/nftables.d/40-signup.conf.j2
Normal file
48
roles/nftables_router/templates/nftables.d/40-signup.conf.j2
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
{{ ansible_managed | comment }}
|
||||||
|
|
||||||
|
table inet signup {
|
||||||
|
|
||||||
|
set triggered {
|
||||||
|
type ether_addr
|
||||||
|
timeout 24h
|
||||||
|
}
|
||||||
|
|
||||||
|
set allowed {
|
||||||
|
type ether_addr
|
||||||
|
timeout 30m
|
||||||
|
}
|
||||||
|
|
||||||
|
chain trigger {
|
||||||
|
log prefix "signup-trigger" group 0
|
||||||
|
add @triggered { ether saddr }
|
||||||
|
add @allowed { ether saddr }
|
||||||
|
}
|
||||||
|
|
||||||
|
chain filter {
|
||||||
|
# Si l'adresse MAC est temporairement autorisée, on ne bloque pas
|
||||||
|
ether saddr @allowed return
|
||||||
|
|
||||||
|
# Si l'adresse n'est pas autorisée (cf. règle précédente) mais qu'elle
|
||||||
|
# a accédé récemment à un déclencheur, cela signifie qu'elle a déjà
|
||||||
|
# « consommé son crédit », donc on bloque
|
||||||
|
ether saddr @triggered drop
|
||||||
|
|
||||||
|
# Si la machine tente de se connecter à un des hôtes déclencheurs,
|
||||||
|
# on enregistre son adresse MAC et on laisse passer la connexion
|
||||||
|
ip daddr $signup_trigger_v4 goto trigger
|
||||||
|
ip6 daddr $signup_trigger_v6 goto trigger
|
||||||
|
|
||||||
|
# La machine a tenté de se connecter vers une destination qui ne
|
||||||
|
# déclenche pas l'accès à Internet, donc on bloque
|
||||||
|
drop
|
||||||
|
}
|
||||||
|
|
||||||
|
chain forward {
|
||||||
|
type filter hook forward priority -10
|
||||||
|
policy accept
|
||||||
|
|
||||||
|
ip saddr $signup_v4 goto filter
|
||||||
|
ip6 saddr $signup_v6 goto filter
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
164
roles/nftables_router/templates/nftables.d/50-filter.conf.j2
Normal file
164
roles/nftables_router/templates/nftables.d/50-filter.conf.j2
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
{{ ansible_managed | comment }}
|
||||||
|
|
||||||
|
table inet filter {
|
||||||
|
|
||||||
|
chain conntrack {
|
||||||
|
ct state invalid counter drop
|
||||||
|
ct state { established, related } counter accept
|
||||||
|
}
|
||||||
|
|
||||||
|
chain input_from_anywhere {
|
||||||
|
# C'est pas gentil de bloquer ICMP(v6), alors on le fait pas
|
||||||
|
ip protocol icmp counter accept
|
||||||
|
ip6 nexthdr icmpv6 counter accept
|
||||||
|
|
||||||
|
# Wireguard
|
||||||
|
udp dport { 5412, 5413 } counter accept
|
||||||
|
|
||||||
|
# Temporaire
|
||||||
|
tcp dport 22 counter accept
|
||||||
|
}
|
||||||
|
|
||||||
|
chain input_from_interco {
|
||||||
|
# Il faut n'accepter que le multicast OSPF et des trucs
|
||||||
|
# comme ça
|
||||||
|
counter accept
|
||||||
|
}
|
||||||
|
|
||||||
|
chain input_from_member {
|
||||||
|
log prefix "in-from-member" group 0
|
||||||
|
}
|
||||||
|
|
||||||
|
chain input_from_svc {
|
||||||
|
log prefix "in-from-svc" group 0
|
||||||
|
}
|
||||||
|
|
||||||
|
chain input_from_adm {
|
||||||
|
log prefix "in-from-adm" group 0
|
||||||
|
|
||||||
|
tcp dport 22 counter accept
|
||||||
|
}
|
||||||
|
|
||||||
|
chain input {
|
||||||
|
type filter hook input priority 0
|
||||||
|
policy drop
|
||||||
|
|
||||||
|
iif lo accept
|
||||||
|
|
||||||
|
jump conntrack
|
||||||
|
|
||||||
|
jump input_from_anywhere
|
||||||
|
|
||||||
|
ip saddr $interco_v4 goto input_from_interco
|
||||||
|
ip6 saddr $interco_v6 goto input_from_interco
|
||||||
|
|
||||||
|
ip saddr $member_v4 goto input_from_member
|
||||||
|
ip6 saddr $member_v6 goto input_from_member
|
||||||
|
|
||||||
|
ip saddr $svc_v4 goto input_from_svc
|
||||||
|
ip6 saddr $svc_v6 goto input_from_svc
|
||||||
|
|
||||||
|
ip saddr $adm_v4 goto input_from_adm
|
||||||
|
ip6 saddr $adm_v6 goto input_from_adm
|
||||||
|
}
|
||||||
|
|
||||||
|
chain output {
|
||||||
|
type filter hook output priority 0
|
||||||
|
policy accept
|
||||||
|
}
|
||||||
|
|
||||||
|
chain forward_to_interco {
|
||||||
|
ip saddr $interco_v4 accept
|
||||||
|
ip6 saddr $interco_v6 accept
|
||||||
|
}
|
||||||
|
|
||||||
|
chain forward_to_member_re2o_ports {
|
||||||
|
# TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
chain forward_to_member {
|
||||||
|
# Les adhérents peuvent communiquer entre eux
|
||||||
|
ip saddr $member_v4 accept
|
||||||
|
ip6 saddr $member_v6 accept
|
||||||
|
|
||||||
|
# L'administration n'a pas accès à l'extérieur
|
||||||
|
ip saddr $adm_v4 drop
|
||||||
|
ip6 saddr $adm_v6 drop
|
||||||
|
|
||||||
|
# Les ouvertures de ports sont générées par re2o
|
||||||
|
goto forward_to_member_re2o_ports
|
||||||
|
}
|
||||||
|
|
||||||
|
chain forward_to_svc {
|
||||||
|
}
|
||||||
|
|
||||||
|
chain forward_to_adm {
|
||||||
|
log prefix "fwd-to-adm" group 0
|
||||||
|
|
||||||
|
# Seules les machines du réseau d'administration peuvent accéder au
|
||||||
|
# réseau d'administration
|
||||||
|
ip saddr != $adm_v4 drop
|
||||||
|
ip6 saddr != $adm_v6 drop
|
||||||
|
|
||||||
|
# Les bastions ont accès à toute l'administration
|
||||||
|
ip saddr $bastion_v4 accept
|
||||||
|
ip6 saddr $bastion_v6 accept
|
||||||
|
|
||||||
|
# Tous les serveurs ont accès au collecteur de logs
|
||||||
|
ip daddr $syslog_adm_v4 tcp dport 20514 accept
|
||||||
|
ip daddr $syslog_adm_v4 udp dport 514 accept
|
||||||
|
ip6 daddr $syslog_adm_v6 tcp dport 20514 accept
|
||||||
|
ip6 daddr $syslog_adm_v6 udp dport 514 accept
|
||||||
|
|
||||||
|
# ntp + apt + dns
|
||||||
|
}
|
||||||
|
|
||||||
|
chain forward_to_inet {
|
||||||
|
log prefix "fwd-to-inet" group 0
|
||||||
|
|
||||||
|
# On évite certains problèmes de spam
|
||||||
|
ip saddr $member_v4 udp dport 25 drop
|
||||||
|
ip6 saddr $member_v6 udp dport 25 drop
|
||||||
|
|
||||||
|
# Les adhérents ont accès à internet
|
||||||
|
ip saddr $member_v4 accept
|
||||||
|
ip6 saddr $member_v6 accept
|
||||||
|
|
||||||
|
# Les réseaux de services ont accès à Internet
|
||||||
|
ip saddr $svc_v4 accept
|
||||||
|
ip6 saddr $svc_v6 accept
|
||||||
|
}
|
||||||
|
|
||||||
|
# Remarque : on utilise 'drop' et pas 'reject' pour conntrackd
|
||||||
|
chain forward {
|
||||||
|
type filter hook forward priority 0
|
||||||
|
policy drop
|
||||||
|
|
||||||
|
iif lo accept
|
||||||
|
|
||||||
|
jump conntrack
|
||||||
|
|
||||||
|
# http://lists.netfilter.org/pipermail/netfilter-buglog/2017-August/003868.html
|
||||||
|
#ip daddr vmap {
|
||||||
|
# $interco_v4 : goto forward_to_interco,
|
||||||
|
# $member_v4 : goto forward_to_member,
|
||||||
|
# $svc_v4 : goto forward_to_svc,
|
||||||
|
# $adm_v4 : goto forward_to_adm,
|
||||||
|
#}
|
||||||
|
|
||||||
|
ip daddr $interco_v4 goto forward_to_interco
|
||||||
|
ip6 daddr $interco_v6 goto forward_to_interco
|
||||||
|
|
||||||
|
ip daddr $member_v4 goto forward_to_member
|
||||||
|
ip6 daddr $member_v6 goto forward_to_member
|
||||||
|
|
||||||
|
ip daddr $svc_v4 goto forward_to_svc
|
||||||
|
ip6 daddr $svc_v6 goto forward_to_svc
|
||||||
|
|
||||||
|
ip daddr $adm_v4 goto forward_to_adm
|
||||||
|
ip6 daddr $adm_v6 goto forward_to_adm
|
||||||
|
|
||||||
|
goto forward_to_inet
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
24
roles/nftables_router/templates/nftables.d/60-nat.conf.j2
Normal file
24
roles/nftables_router/templates/nftables.d/60-nat.conf.j2
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
{{ ansible_managed | comment }}
|
||||||
|
|
||||||
|
table ip nat {
|
||||||
|
|
||||||
|
chain prerouting {
|
||||||
|
type nat hook prerouting priority -100
|
||||||
|
policy accept
|
||||||
|
}
|
||||||
|
|
||||||
|
chain snat_to_wan {
|
||||||
|
log prefix "snat-to-wan" group 0
|
||||||
|
|
||||||
|
ip saddr $member_priv_v4 snat $member_nat_v4 persistent
|
||||||
|
snat $any_nat_v4 persistent
|
||||||
|
}
|
||||||
|
|
||||||
|
chain postrouting {
|
||||||
|
type nat hook prerouting priority 100
|
||||||
|
policy accept
|
||||||
|
|
||||||
|
# oifname $wan_iface goto snat_to_wan
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue