nftables.conf.tmpl 7.7 KB

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