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:
|
||||
ens19:
|
||||
stub: true
|
||||
ens20:
|
||||
stub: true
|
||||
gs:
|
||||
type: pointopoint
|
||||
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