nftables.conf.tmpl 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. #!/usr/sbin/nft -f
  2. #
  3. # /etc/nftables.conf - FFHO packet filter configuration
  4. #
  5. {%- set node_config = salt['pillar.get']('nodes:' ~ grains['id']) %}
  6. {%- set roles = node_config.get ('roles', []) %}
  7. {%- set fw_config = salt['pillar.get']('firewall', {}) %}
  8. {%- set admin_access = fw_config.get ('admin_access') %}
  9. {%- set ssh = fw_config.get ('ssh') %}
  10. {%- set prometheus_hosts = salt['pillar.get']('firewall:acls:prometheus') %}
  11. {%- set icinga2_queriers = salt['pillar.get']('monitoring:icinga2:queriers', []) %}
  12. {%- set nms_list = salt['pillar.get']('globals:snmp:nms_list', []) %}
  13. {%- set services = salt['ffho_netfilter.generate_service_rules'](fw_config, node_config) %}
  14. {%- set forward = salt['ffho_netfilter.generate_forward_policy'](fw_config, node_config) %}
  15. {%- set nat_policy = salt['ffho_netfilter.generate_nat_policy'](node_config) %}
  16. {%- set mgmt_config = salt['ffho_netfilter.generate_mgmt_config'](fw_config, node_config) %}
  17. {%- set urpf = salt['ffho_netfilter.generate_urpf_policy'](node_config) %}
  18. {%- set ospf_ifaces = salt['ffho_netfilter.get_ospf_active_interface'](node_config) %}
  19. {%- set vxlan_ifaces = salt['ffho_netfilter.get_vxlan_interfaces'](node_config['ifaces']) %}
  20. flush ruleset
  21. table ip filter {
  22. set ibgp-peers {
  23. type ipv4_addr
  24. elements = {
  25. 10.132.255.1, # cr01.in.ffho.net
  26. 10.132.255.2, # cr02.in.ffho.net
  27. 10.132.255.3, # cr03.in.ffho.net
  28. }
  29. }
  30. chain input {
  31. type filter hook input priority 0; policy drop;
  32. iifname "lo" counter accept
  33. udp dport 0 counter drop
  34. tcp dport 7 counter drop comment "Ignore echo protocol queries"
  35. {%- if vxlan_ifaces %}
  36. udp dport 4789 jump vxlan
  37. {%- endif %}
  38. {%- if urpf %}
  39. jump urpf
  40. {%- endif %}
  41. ip protocol icmp jump icmp_chain
  42. ct state invalid counter drop
  43. jump admin_access
  44. jump monitoring
  45. tcp dport 22 counter jump ssh
  46. {%- if ospf_ifaces %}
  47. {#- ifname sets are introduced in nftables 2.11 #}
  48. meta l4proto ospf iifname { {{ ospf_ifaces|join(', ') }} } counter accept
  49. {%- endif %}
  50. {%- if 'router' in roles %}
  51. tcp dport 179 counter jump bgp
  52. {%- endif %}
  53. ct state related,established counter accept
  54. jump services
  55. meta pkttype broadcast counter drop comment "Drop broadcasts before logging"
  56. limit rate 1/second burst 3 packets counter log prefix "nf input: "
  57. limit rate 1/second burst 3 packets counter reject with icmp type admin-prohibited
  58. counter drop
  59. }
  60. chain forward {
  61. type filter hook forward priority 0; policy {{ forward['policy'] }}; # {{ forward['policy_reason'] }}
  62. {%- if urpf %}
  63. jump urpf
  64. {%- endif %}
  65. {%- if mgmt_config and mgmt_config['prefixes'][4] %}
  66. ip daddr { {{ mgmt_config['prefixes'][4]|join(', ') }} } oifname { {{ mgmt_config['ifaces']|join(', ') }} } jump mgmt
  67. {%- endif %}
  68. {%- for rule in forward['rules'].get ('4', []) %}
  69. {{ rule }}
  70. {%- endfor %}
  71. {%- if forward['policy'] == 'drop' %}
  72. limit rate 1/second burst 3 packets counter log prefix "nf forward: "
  73. limit rate 1/second burst 3 packets counter reject with icmp type admin-prohibited
  74. {%- endif %}
  75. }
  76. chain icmp_chain {
  77. icmp type { echo-request, destination-unreachable, time-exceeded } counter accept
  78. }
  79. chain admin_access {
  80. {%- for pfx in admin_access[4].keys()|sort %}
  81. {%- set comment = admin_access[4][pfx] %}
  82. ip saddr {{ pfx }} counter accept comment "{{ comment }}"
  83. {%- endfor %}
  84. }
  85. {%- if 'router' in roles %}
  86. chain bgp {
  87. ip saddr @ibgp-peers counter accept comment "iBGP peers"
  88. # TODO: Add external BGP peers, if any
  89. }
  90. {%- endif %}
  91. {%- if mgmt_config %}
  92. chain mgmt {
  93. ct state related,established counter accept
  94. jump admin_access
  95. jump icmp_chain
  96. jump monitoring
  97. jump log-reject
  98. }
  99. {%- endif %}
  100. chain monitoring {
  101. ip saddr { {{ prometheus_hosts[4]|join(", ") }} } tcp dport 9100 counter accept comment "prometheus"
  102. {%- for ip in icinga2_queriers if not ":" in ip %}
  103. ip saddr {{ ip }} counter accept comment "Icinga2"
  104. {%- endfor %}
  105. {%- for ip in nms_list if not ":" in ip %}
  106. ip saddr {{ ip }} udp dport 161 counter accept comment "NMS"
  107. {%- endfor %}
  108. }
  109. chain ssh {
  110. {%- for pfx in ssh[4].keys()|sort %}
  111. {%- set comment = ssh[4][pfx] %}
  112. ip saddr {{ pfx }} counter accept comment "{{ comment }}"
  113. {%- endfor %}
  114. }
  115. chain services {
  116. {%- for rule in services[4] %}
  117. {{ rule }}
  118. {%- endfor %}
  119. }
  120. {%- if urpf %}
  121. chain urpf {
  122. {%- for iface_cfg in urpf %}
  123. {%- for pfx in iface_cfg[4] %}
  124. iifname {{ iface_cfg['iface'] }} ip saddr {{ pfx }} return
  125. {%- endfor %}
  126. iifname {{ iface_cfg['iface'] }} counter drop
  127. {%- endfor %}
  128. }
  129. {%- endif %}
  130. {%- if vxlan_ifaces %}
  131. chain vxlan {
  132. {%- for iface in vxlan_ifaces %}
  133. iifname {{ iface }} accept
  134. {%- endfor %}
  135. counter drop
  136. }
  137. {%- endif %}
  138. chain log-drop {
  139. limit rate 1/second burst 3 packets counter log prefix "netfilter: "
  140. counter drop
  141. }
  142. chain log-reject {
  143. limit rate 1/second burst 3 packets counter log prefix "netfilter: "
  144. limit rate 1/second burst 3 packets counter reject with icmp type admin-prohibited
  145. counter drop
  146. }
  147. }
  148. table ip6 filter {
  149. set ibgp-peers {
  150. type ipv6_addr
  151. elements = {
  152. 2a03:2260:2342:ffff::1, # cr01.in.ffho.net
  153. 2a03:2260:2342:ffff::2, # cr02.in.ffho.net
  154. 2a03:2260:2342:ffff::3, # cr03.in.ffho.net
  155. }
  156. }
  157. chain input {
  158. type filter hook input priority 0; policy drop;
  159. iifname "lo" counter accept
  160. tcp dport 7 counter drop comment "Ignore echo protocol queries"
  161. {%- if vxlan_ifaces %}
  162. udp dport 4789 jump vxlan
  163. {%- endif %}
  164. {%- if urpf %}
  165. jump urpf
  166. {%- endif %}
  167. meta l4proto icmpv6 jump icmp_chain
  168. ct state invalid counter drop
  169. jump admin_access
  170. jump monitoring
  171. tcp dport 22 counter jump ssh
  172. {%- if ospf_ifaces %}
  173. {#- ifname sets are introduced in nftables 2.11 #}
  174. meta l4proto ospf iifname { {{ ospf_ifaces|join(', ') }} } counter accept
  175. {%- endif %}
  176. {%- if 'router' in roles %}
  177. tcp dport 179 counter jump bgp
  178. {%- endif %}
  179. ct state related,established counter accept
  180. counter jump services
  181. limit rate 1/second burst 3 packets counter log prefix "netfilter: "
  182. limit rate 1/second burst 3 packets counter reject with icmpv6 type admin-prohibited
  183. counter drop
  184. }
  185. chain forward {
  186. type filter hook forward priority 0; policy {{ forward['policy'] }}; # {{ forward['policy_reason'] }}
  187. {%- if urpf %}
  188. jump urpf
  189. {%- endif %}
  190. {%- for rule in forward['rules'].get ('6', []) %}
  191. {{ rule }}
  192. {%- endfor %}
  193. {%- if forward['policy'] == 'drop' %}
  194. limit rate 1/second burst 3 packets counter log prefix "nf forward: "
  195. limit rate 1/second burst 3 packets counter reject with icmpv6 type admin-prohibited
  196. {%- endif %}
  197. }
  198. chain icmp_chain {
  199. icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply } counter accept
  200. icmpv6 type { nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, ind-neighbor-solicit, ind-neighbor-advert } ip6 hoplimit 255 counter accept
  201. icmpv6 type { mld-listener-query, mld-listener-report, mld-listener-reduction } ip6 saddr fe80::/64 counter accept
  202. }
  203. chain admin_access {
  204. {%- for pfx in admin_access[6].keys()|sort %}
  205. {%- set comment = admin_access[6][pfx] %}
  206. ip6 saddr {{ pfx }} counter accept comment "{{ comment }}"
  207. {%- endfor %}
  208. }
  209. {%- if 'router' in roles %}
  210. chain bgp {
  211. ip6 saddr @ibgp-peers counter accept comment "iBGP peers"
  212. # TODO: Add external BGP peers, if any
  213. }
  214. {%- endif %}
  215. chain monitoring {
  216. ip6 saddr { {{ prometheus_hosts[6]|join(", ") }} } tcp dport 9100 counter accept comment "prometheus"
  217. {%- for ip in icinga2_queriers if ":" in ip %}
  218. ip6 saddr {{ ip }} counter accept comment "Icinga2"
  219. {%- endfor %}
  220. {%- for ip in nms_list if ":" in ip %}
  221. ip6 saddr {{ ip }} udp dport 161 counter accept comment "NMS"
  222. {%- endfor %}
  223. }
  224. chain ssh {
  225. {%- for pfx in ssh[6].keys()|sort %}
  226. {%- set comment = ssh[6][pfx] %}
  227. ip6 saddr {{ pfx }} counter accept comment "{{ comment }}"
  228. {%- endfor %}
  229. }
  230. chain services {
  231. {%- for rule in services[6] %}
  232. {{ rule }}
  233. {%- endfor %}
  234. }
  235. {%- if urpf %}
  236. chain urpf {
  237. ip6 saddr fe80::/64 return
  238. {%- for iface_cfg in urpf %}
  239. {%- for pfx in iface_cfg[6] %}
  240. iifname {{ iface_cfg['iface'] }} ip6 saddr {{ pfx }} return
  241. {%- endfor %}
  242. iifname {{ iface_cfg['iface'] }} counter drop
  243. {%- endfor %}
  244. }
  245. {%- endif %}
  246. {%- if vxlan_ifaces %}
  247. chain vxlan {
  248. {%- for iface in vxlan_ifaces %}
  249. iifname {{ iface }} accept
  250. {%- endfor %}
  251. counter drop
  252. }
  253. {%- endif %}
  254. chain log-drop {
  255. limit rate 1/second burst 3 packets counter log prefix "netfilter: "
  256. counter drop
  257. }
  258. chain log-reject {
  259. limit rate 1/second burst 3 packets counter log prefix "netfilter: "
  260. limit rate 1/second burst 3 packets counter reject with icmpv6 type admin-prohibited
  261. counter drop
  262. }
  263. }
  264. {#-
  265. # NAT
  266. #}
  267. {%- for af in [ 4, 6 ] %}
  268. {%- if nat_policy[af] %}
  269. {%- set af_name = "ip" if af == 4 else "ip6" %}
  270. table {{ af_name }} nat {
  271. {%- for chain in ['output', 'prerouting', 'postrouting'] if chain in nat_policy[af] %}
  272. chain {{ chain }} {
  273. type nat hook {{ chain }} priority 0; policy accept;
  274. {%- for rule in nat_policy[af][chain] %}
  275. {{ rule }}
  276. {%- endfor %}
  277. }
  278. {%- endfor %}
  279. }
  280. {%- endif %}
  281. {%- endfor %}