nftables.conf.tmpl 8.6 KB

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