diff --git a/host_exporters/defaults/main.yml b/host_exporters/defaults/main.yml new file mode 100644 index 0000000..fc35c48 --- /dev/null +++ b/host_exporters/defaults/main.yml @@ -0,0 +1,4 @@ +--- +# Adds prometheus-smartctl-exporter (trixie-backports) next to the node exporter +# on hosts with physical disks. +host_exporters_smart: false diff --git a/host_exporters/tasks/main.yml b/host_exporters/tasks/main.yml new file mode 100644 index 0000000..292c5cb --- /dev/null +++ b/host_exporters/tasks/main.yml @@ -0,0 +1,69 @@ +--- +# Both exporters listen on all addresses; host_firewall limits who reaches them. +- name: Install the node exporter + ansible.builtin.apt: + name: prometheus-node-exporter + state: present + +- name: Enable the node exporter + ansible.builtin.systemd: + name: prometheus-node-exporter + enabled: true + state: started + # Check mode does not install the package. + ignore_errors: "{{ ansible_check_mode }}" + +- name: Install the smartctl exporter + when: host_exporters_smart + block: + - name: Look for an existing backports source + ansible.builtin.shell: >- + grep -rEqs '^[^#]*{{ ansible_distribution_release }}-backports' + --include='*.list' --include='*.sources' --exclude=host-exporters-backports.sources /etc/apt + register: host_exporters_backports + changed_when: false + failed_when: host_exporters_backports.rc > 1 + check_mode: false + + # Backports stay at priority 100, so only packages named with default_release come from there. + - name: Add the backports source + ansible.builtin.copy: + dest: /etc/apt/sources.list.d/host-exporters-backports.sources + mode: "0644" + content: | + Types: deb + URIs: http://deb.debian.org/debian + Suites: {{ ansible_distribution_release }}-backports + Components: main + Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg + register: host_exporters_source + when: host_exporters_backports.rc == 1 + + # The module rejects default_release while the release is missing from its package cache. + - name: Look for the backports release in the package lists + ansible.builtin.shell: apt-cache policy | grep -q 'n={{ ansible_distribution_release }}-backports' + register: host_exporters_lists + changed_when: false + failed_when: false + check_mode: false + + - name: Refresh the package lists for the backports source + ansible.builtin.apt: + update_cache: true + when: host_exporters_lists.rc != 0 + + - name: Install the smartctl exporter from backports + ansible.builtin.apt: + name: prometheus-smartctl-exporter + default_release: "{{ ansible_distribution_release }}-backports" + state: present + # Check mode does not write the backports source. + ignore_errors: "{{ ansible_check_mode }}" + + # The packaged unit runs as root, which smartctl needs for the disks. + - name: Enable the smartctl exporter + ansible.builtin.systemd: + name: smartctl_exporter + enabled: true + state: started + ignore_errors: "{{ ansible_check_mode }}" diff --git a/host_firewall/defaults/main.yml b/host_firewall/defaults/main.yml index 6196d8d..3ccc87c 100644 --- a/host_firewall/defaults/main.yml +++ b/host_firewall/defaults/main.yml @@ -16,6 +16,12 @@ firewall: admin: v4: {} v6: {} + # Metrics scrapers: on wt0 only these source addresses reach the listed tcp + # ports (the vpn zone applies to every peer). Rendered only when both are set. + scrapers: + tcp: {} + v4: {} + v6: {} # Interface names (nft wildcards allowed) whose traffic is trusted. internal_ifaces: {} # Guest bridges (Proxmox vmbr*): DHCP, router solicitations and the public diff --git a/host_firewall/templates/host.nft.j2 b/host_firewall/templates/host.nft.j2 index f012c19..75bf894 100644 --- a/host_firewall/templates/host.nft.j2 +++ b/host_firewall/templates/host.nft.j2 @@ -18,6 +18,7 @@ set {{ name }} { {% set guest_match = 'iifname { "' ~ (guest_ifaces | join('", "')) ~ '" }' %} {% set dnat = firewall.dnat | default({}, true) | dict2items | rejectattr('value', 'none') | map(attribute='value') | list %} {% set masquerade = firewall.masquerade | default({}, true) | dict2items | rejectattr('value', 'none') | map(attribute='value') | unique | list %} +{% set scrapers = firewall.scrapers | default({}, true) %} {% set forward_guard = firewall.forward_guard | default({}, true) | dict2items | rejectattr('value', 'none') | list %} # Declare-then-delete makes every load one atomic transaction that replaces @@ -36,6 +37,8 @@ table inet host { {{ addr_set('admin_v6', 'ipv6_addr', firewall.admin.v6) }} {{ addr_set('cluster_v4', 'ipv4_addr', cluster.v4) }} {{ addr_set('cluster_v6', 'ipv6_addr', cluster.v6) }} + {{ addr_set('scrapers_v4', 'ipv4_addr', scrapers.v4) }} + {{ addr_set('scrapers_v6', 'ipv6_addr', scrapers.v6) }} set ssh_meter_v4 { type ipv4_addr; flags dynamic; timeout 10m; size 65535; } @@ -85,6 +88,14 @@ table inet host { } chain vpn { +{% if list(scrapers.tcp) %} +{% if list(scrapers.v4) %} + ip saddr @scrapers_v4 tcp dport { {{ list(scrapers.tcp) }} } accept +{% endif %} +{% if list(scrapers.v6) %} + ip6 saddr @scrapers_v6 tcp dport { {{ list(scrapers.tcp) }} } accept +{% endif %} +{% endif %} {% if list(firewall.vpn.tcp) %} tcp dport { {{ list(firewall.vpn.tcp) }} } accept {% endif %}