Browse Source

nftables: Derive/compute monitoring access rules from node information

  With this commit the netfilter module will compute required nftables rules to
  allow monitoring systems accessing all nodes based on the configuration given
  within the 'monitoring' pillar.

  The pillar could look like this:

    monitoring:
      librenms:
        role: librenms
        nftables_rule_spec: "udp dport 161"

      prometheus:
        role: prometheus
        nftables_rule_spec: "tcp dport 9100"

      icinga2:
        role: icinga2server

Signed-off-by: Maximilian Wilhelm <max@sdn.clinic>
Maximilian Wilhelm 1 year ago
parent
commit
07349ed721
2 changed files with 61 additions and 18 deletions
  1. 53 0
      _modules/ffho_netfilter.py
  2. 8 18
      nftables/nftables.conf.tmpl

+ 53 - 0
_modules/ffho_netfilter.py

@@ -402,3 +402,56 @@ def get_vxlan_interfaces (interfaces):
 			vxlan_ifaces.append (iface)
 
 	return vxlan_ifaces
+
+#
+# Generate rules to allow access for/from monitoring systems
+def generate_monitoring_rules (nodes, monitoring_cfg):
+	rules = {
+		4 : [],
+		6 : [],
+	}
+
+	systems = {}
+
+	# Prepare systems dict with configuration from pillar
+	for sysname, cfg in monitoring_cfg.items ():
+		if 'role' not in cfg:
+			continue
+
+		systems[sysname] = {
+			'role' : cfg['role'],
+			'nftables_rule_spec' : cfg.get ('nftables_rule_spec', ''),
+			'nodes' : {
+				4 : [],
+				6 : [],
+			},
+		}
+
+	# Gather information about monitoring systems from node configurations
+	for node, node_config in nodes.items ():
+		for system, syscfg in systems.items ():
+			ips = node_config.get('primary_ips', {})
+
+			if syscfg['role'] in node_config.get ('roles', []):
+				for af in [4, 6]:
+					ip = ips.get (str (af), "").split ('/')[0]
+					if ip:
+						syscfg['nodes'][af].append (ip)
+
+	# Generate rules for all configured and found systems
+	for sysname in sorted (systems.keys ()):
+		syscfg = systems[sysname]
+
+		for af in [4, 6]:
+			if not syscfg['nodes'][af]:
+				continue
+
+			rule = "ip" if af == 4 else "ip6"
+			rule += " saddr { "
+			rule += ", ".join (sorted (syscfg['nodes'][af]))
+			rule += " } "
+			rule += syscfg['nftables_rule_spec']
+			rule += f" counter accept comment \"{sysname.capitalize()}\""
+			rules[af].append (rule)
+
+	return rules

+ 8 - 18
nftables/nftables.conf.tmpl

@@ -2,17 +2,15 @@
 #
 # /etc/nftables.conf - FFHO packet filter configuration
 #
-{%- set node_config = salt['pillar.get']('nodes:' ~ grains['id']) %}
+{%- set nodes = salt['pillar.get']('nodes', {}) %}
+{%- set node_config = nodes.get (grains['id'], {}) %}
 {%- set roles = node_config.get ('roles', []) %}
 
 {%- set fw_config = salt['pillar.get']('firewall', {}) %}
 {%- set admin_access = fw_config.get ('admin_access') %}
 {%- set ssh = fw_config.get ('ssh') %}
-
-{%- set prometheus_hosts = salt['pillar.get']('firewall:acls:prometheus') %}
-{%- set icinga2_queriers = salt['pillar.get']('monitoring:icinga2:queriers', []) %}
-{%- set nms_list = salt['pillar.get']('globals:snmp:nms_list', []) %}
-
+{%- set monitoring_cfg = salt['pillar.get']('monitoring') %}
+{%- set monitoring_rules = salt['ffho_netfilter.generate_monitoring_rules'](nodes, monitoring_cfg) %}
 {%- set services = salt['ffho_netfilter.generate_service_rules'](fw_config, node_config) %}
 {%- set forward = salt['ffho_netfilter.generate_forward_policy'](fw_config, node_config) %}
 {%- set nat_policy = salt['ffho_netfilter.generate_nat_policy'](node_config) %}
@@ -111,12 +109,8 @@ table ip filter {
 {%- endif %}
 
 	chain monitoring {
-		ip saddr { {{ prometheus_hosts[4]|join(", ") }} } tcp dport 9100 counter accept comment "prometheus"
-{%- for ip in icinga2_queriers if not ":" in ip %}
-		ip saddr {{ ip }} counter accept comment "Icinga2"
-{%- endfor %}
-{%- for ip in nms_list if not ":" in ip %}
-		ip saddr {{ ip }} udp dport 161 counter accept comment "NMS"
+{%- for rule in monitoring_rules[4] %}
+		{{ rule }}
 {%- endfor %}
 	}
 
@@ -240,12 +234,8 @@ table ip6 filter {
 {%- endif %}
 
 	chain monitoring {
-		ip6 saddr { {{ prometheus_hosts[6]|join(", ") }} } tcp dport 9100 counter accept comment "prometheus"
-{%- for ip in icinga2_queriers if ":" in ip %}
-		ip6 saddr {{ ip }} counter accept comment "Icinga2"
-{%- endfor %}
-{%- for ip in nms_list if ":" in ip %}
-		ip6 saddr {{ ip }} udp dport 161 counter accept comment "NMS"
+{%- for rule in monitoring_rules[6] %}
+		{{ rule }}
 {%- endfor %}
 	}