nftables.conf.tmpl 8.2 KB

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