Browse Source

Merge pull request #5 from BarbarossaTM/nftables

Add 1st shot for nftables state
Maximilian Wilhelm 2 years ago
parent
commit
ac7dfac461
3 changed files with 217 additions and 0 deletions
  1. 49 0
      _modules/ffho_netfilter.py
  2. 21 0
      nftables/init.sls
  3. 147 0
      nftables/nftables.conf.tmpl

+ 49 - 0
_modules/ffho_netfilter.py

@@ -0,0 +1,49 @@
+#
+# FFHO netfilter helper functions
+#
+
+def generate_service_rules (services, acls, af):
+	rules = []
+
+	for srv in services:
+		rule = ""
+		comment = srv['descr']
+
+		# If there are no DST IPs set at all or DST IPs for this AF set, we have a rule to build,
+		# if this is NOT the case, there is no rule for this AF to generate, carry on.
+		if not ((not srv['ips']['4'] and not srv['ips']['6']) or srv['ips'][str(af)]):
+			continue
+
+		# Is/are IP(s) set for this service?
+		if srv['ips'][str(af)]:
+			rule += "ip" if af == 4 else "ip6"
+
+			dst_ips = srv['ips'][str(af)]
+			if len (dst_ips) == 1:
+				rule += " daddr %s " % dst_ips[0]
+			else:
+				rule += " daddr { %s } " % ", ".join (dst_ips)
+
+		# ACL defined for this service?
+		if srv['acl']:
+			rule += "ip" if af == 4 else "ip6"
+			acl = acls[srv['acl']][af]
+
+			# Many entries
+			if type (acl) == list:
+				rule += " saddr { %s } " % ", ".join (acl)
+			else:
+				rule += " saddr %s " % acl
+
+			comment += " (acl: %s)" % srv['acl']
+
+		# Multiple ports?
+		if len (srv['ports']) > 1:
+			ports = "{ %s }" % ", ".join (map (str, sorted (srv['ports'])))
+		else:
+			ports = srv['ports'][0]
+
+		rule += "%s dport %s counter accept comment \"%s\"" % (srv['proto'], ports, comment)
+		rules.append (rule)
+
+	return rules

+ 21 - 0
nftables/init.sls

@@ -0,0 +1,21 @@
+#
+# nftables state
+#
+
+nftables:
+  pkg.installed:
+    - name: nftables
+  service.running:
+    - enable: true
+    - reload: true
+
+
+/etc/nftables.conf:
+  file.managed:
+   - source: salt://nftables/nftables.conf.tmpl
+   - template: jinja
+   - mode: 755
+   - require:
+     - pkg: nftables
+   - watch_in:
+     - service: nftables

+ 147 - 0
nftables/nftables.conf.tmpl

@@ -0,0 +1,147 @@
+#!/usr/sbin/nft -f
+#
+# /etc/nftables.conf - FFHO packet filter configuration
+#
+{%- set roles = salt['pillar.get']('nodes:' ~ grains['id'] ~ ':roles', []) %}
+{%- set acls = salt['pillar.get']('firewall:acls') %}
+{%- set admin_access = salt['pillar.get']('firewall:admin_access') %}
+{%- set ssh = salt['pillar.get']("firewall:ssh") %}
+{%- set services = salt['pillar.get']('nodes:' ~ grains['id'] ~ ':services') %}
+{#- TODO: Get RR IPs from netbox #}
+{%- set bgp = { 4: { '10.132.255.1' : 'cr01.in.ffho.net',
+                     '10.132.255.2' : 'cr02.in.ffho.net',
+                     '10.132.255.3' : 'cr03.in.ffho.net', },
+                6: { '2a03:2260:2342:ffff::1' : 'cr01.in.ffho.net',
+                     '2a03:2260:2342:ffff::2' : 'cr02.in.ffho.net',
+                     '2a03:2260:2342:ffff::3' : 'cr03.in.ffho.net', }} %}
+
+flush ruleset
+
+table ip filter {
+	chain input {
+		type filter hook input priority 0; policy drop;
+		iifname "lo" counter accept
+		ip protocol icmp counter jump icmp_chain
+		ct state invalid counter drop
+		counter jump admin_access
+		tcp dport 22 counter jump ssh
+{%- if 'router' in roles %}
+		ip daddr { 224.0.0.5, 224.0.0.6 } meta l4proto ospf accept
+		tcp dport 179 counter jump bgp
+{%- endif %}
+		ct state related,established counter accept
+		counter jump services
+		limit rate 1/second burst 3 packets counter log prefix "netfilter: "
+		limit rate 1/second burst 3 packets counter reject with icmp type admin-prohibited
+		counter drop
+	}
+
+	chain icmp_chain {
+		icmp type { echo-request, destination-unreachable, time-exceeded } counter accept
+	}
+
+	chain admin_access {
+{%- for pfx in admin_access[4].keys()|sort %}
+  {%- set comment = admin_access[4][pfx] %}
+		ip saddr {{ pfx }} counter accept comment "{{ comment }}"
+{%- endfor %}
+	}
+
+{%- if 'router' in roles %}
+	chain bgp {
+  {%- for ip in bgp[4].keys()|sort %}
+    {%- set comment = bgp[4][ip] %}
+		ip saddr {{ ip }} counter accept comment "{{ comment }}"
+  {%- endfor %}
+	}
+{%- endif %}
+
+	chain ssh {
+{%- for pfx in ssh[4].keys()|sort %}
+  {%- set comment = ssh[4][pfx] %}
+		ip saddr {{ pfx }} counter accept comment "{{ comment }}"
+{%- endfor %}
+	}
+
+	chain services {
+{%- for rule in salt['ffho_netfilter.generate_service_rules'](services, acls, 4) %}
+		{{ rule }}
+{%- endfor %}
+	}
+
+	chain log-drop {
+		limit rate 1/second burst 3 packets counter log prefix "netfilter: "
+		counter drop
+	}
+
+	chain log-reject {
+		limit rate 1/second burst 3 packets counter log prefix "netfilter: "
+		limit rate 1/second burst 3 packets counter reject with icmp type admin-prohibited
+		counter drop
+	}
+}
+
+table ip6 filter {
+	chain input {
+		type filter hook input priority 0; policy drop;
+		iifname "lo" counter accept
+		ip6 nexthdr icmpv6 counter jump icmp_chain
+		ct state invalid counter drop comment "Drop packets that do not make sense."
+		counter jump admin_access
+		tcp dport 22 counter jump ssh
+{%- if 'router' in roles %}
+		ip6 saddr fe80::/64 ip6 daddr { ff02::5, ff02::6 } meta l4proto ospf accept
+		tcp dport 179 counter jump bgp
+{%- endif %}
+		ct state related,established counter accept comment "Allow established connections."
+		counter jump services
+		limit rate 1/second burst 3 packets counter log prefix "netfilter: "
+		limit rate 1/second burst 3 packets counter reject with icmpv6 type admin-prohibited
+		counter drop
+	}
+
+	chain icmp_chain {
+		icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply } counter accept
+		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
+	}
+
+	chain admin_access {
+{%- for pfx in admin_access[6].keys()|sort %}
+  {%- set comment = admin_access[6][pfx] %}
+		ip6 saddr {{ pfx }} counter accept comment "{{ comment }}"
+{%- endfor %}
+	}
+
+{%- if 'router' in roles %}
+	chain bgp {
+  {%- for ip in bgp[6].keys()|sort %}
+    {%- set comment = bgp[6][ip] %}
+		ip6 saddr {{ ip }} counter accept comment "{{ comment }}"
+  {%- endfor %}
+	}
+{%- endif %}
+
+	chain ssh {
+{%- for pfx in ssh[6].keys()|sort %}
+  {%- set comment = ssh[6][pfx] %}
+		ip6 saddr {{ pfx }} counter accept comment "{{ comment }}"
+{%- endfor %}
+	}
+
+	chain services {
+{%- for rule in salt['ffho_netfilter.generate_service_rules'](services, acls, 6) %}
+		{{ rule }}
+{%- endfor %}
+	}
+
+	chain log-drop {
+		limit rate 1/second burst 3 packets counter log prefix "netfilter: "
+		counter drop
+	}
+
+	chain log-reject {
+		limit rate 1/second burst 3 packets counter log prefix "netfilter: "
+		limit rate 1/second burst 3 packets counter reject with icmpv6 type admin-prohibited
+		counter drop
+	}
+}