diff options
| author | Nataliia Solomko <natalirs1985@gmail.com> | 2026-07-02 11:46:45 +0300 |
|---|---|---|
| committer | Nataliia Solomko <natalirs1985@gmail.com> | 2026-07-02 15:34:17 +0300 |
| commit | f56f37924f05bcfebd05342ccb40c53001b3409a (patch) | |
| tree | 81d34c79d743cea47d827e4424ae9ac3182c0e97 | |
| parent | 063e007a5a8eac3bb9ad101206dc94734eeaa595 (diff) | |
| download | vyos-1x-f56f37924f05bcfebd05342ccb40c53001b3409a.tar.gz vyos-1x-f56f37924f05bcfebd05342ccb40c53001b3409a.zip | |
T9002: grant CAP_NET_RAW to blackbox-exporter when ICMP modules are configured
The blackbox-exporter runs as node_exporter user which cannot create
ICMP sockets due to restricted ping_group_range. Add CAP_NET_RAW
capability to the systemd service when ICMP modules are configured.
In non-VRF mode, use systemd AmbientCapabilities/CapabilityBoundingSet.
In VRF mode, replace runuser with setpriv to preserve the capability
across the UID change.
| -rw-r--r-- | data/templates/prometheus/blackbox_exporter.service.j2 | 16 | ||||
| -rwxr-xr-x | smoketest/scripts/cli/test_service_monitoring_prometheus.py | 46 | ||||
| -rwxr-xr-x | src/conf_mode/service_monitoring_prometheus.py | 8 |
3 files changed, 69 insertions, 1 deletions
diff --git a/data/templates/prometheus/blackbox_exporter.service.j2 b/data/templates/prometheus/blackbox_exporter.service.j2 index 0b846ab73..50e81c5f1 100644 --- a/data/templates/prometheus/blackbox_exporter.service.j2 +++ b/data/templates/prometheus/blackbox_exporter.service.j2 @@ -1,4 +1,14 @@ -{% set vrf_command = 'ip vrf exec ' ~ vrf ~ ' runuser -u node_exporter -- ' if vrf is vyos_defined else '' %} +{% set icmp_enabled = modules is vyos_defined and modules.icmp is vyos_defined and modules.icmp.name is vyos_defined %} +{% if vrf is vyos_defined %} +{% if icmp_enabled %} +{# j2lint: disable=operator-enclosed-by-spaces #} +{% set vrf_command = 'ip vrf exec ' ~ vrf ~ ' setpriv --reuid=node_exporter --regid=node_exporter --init-groups --inh-caps=+net_raw --ambient-caps=+net_raw -- ' %} +{% else %} +{% set vrf_command = 'ip vrf exec ' ~ vrf ~ ' runuser -u node_exporter -- ' %} +{% endif %} +{% else %} +{% set vrf_command = '' %} +{% endif %} [Unit] Description=Blackbox Exporter Documentation=https://github.com/prometheus/blackbox_exporter @@ -8,6 +18,10 @@ After=network.target {% if vrf is not vyos_defined %} User=node_exporter {% endif %} +{% if vrf is not vyos_defined and icmp_enabled %} +AmbientCapabilities=CAP_NET_RAW +CapabilityBoundingSet=CAP_NET_RAW +{% endif %} ExecStart={{ vrf_command }}/usr/sbin/blackbox_exporter \ {% if listen_address is vyos_defined %} {% for address in listen_address %} diff --git a/smoketest/scripts/cli/test_service_monitoring_prometheus.py b/smoketest/scripts/cli/test_service_monitoring_prometheus.py index df27162ef..a60e92842 100755 --- a/smoketest/scripts/cli/test_service_monitoring_prometheus.py +++ b/smoketest/scripts/cli/test_service_monitoring_prometheus.py @@ -158,6 +158,52 @@ class TestMonitoringPrometheus(VyOSUnitTestSHIM.TestCase): # Check for running process self.assertTrue(process_named_running(BLACKBOX_EXPORTER_PROCESS_NAME)) + def test_05_blackbox_exporter_with_icmp(self): + vrf_name = 'bbx' + be_path = base_path + ['blackbox-exporter'] + self.cli_set(be_path + ['listen-address', listen_ip]) + self.cli_set( + be_path + + ['modules', 'icmp', 'name', 'ping4', 'preferred-ip-protocol', 'ipv4'] + ) + + self.cli_commit() + + # Verify CAP_NET_RAW is granted when ICMP module is configured (no VRF case) + file_content = read_file(blackbox_exporter_service_file) + self.assertIn('AmbientCapabilities=CAP_NET_RAW', file_content) + self.assertIn('CapabilityBoundingSet=CAP_NET_RAW', file_content) + + # Check for running process + self.assertTrue(process_named_running(BLACKBOX_EXPORTER_PROCESS_NAME)) + + self.cli_delete(be_path + ['modules', 'icmp']) + self.cli_commit() + + # Verify CAP_NET_RAW is removed when ICMP module is deleted + file_content = read_file(blackbox_exporter_service_file) + self.assertNotIn('CAP_NET_RAW', file_content) + self.assertTrue(process_named_running(BLACKBOX_EXPORTER_PROCESS_NAME)) + + # VRF + ICMP should use setpriv with net_raw capabilities + self.cli_set(['vrf', 'name', vrf_name, 'table', '1111']) + self.cli_set(be_path + ['vrf', vrf_name]) + self.cli_set( + be_path + + ['modules', 'icmp', 'name', 'ping4', 'preferred-ip-protocol', 'ipv4'] + ) + self.cli_commit() + + # Verify VRF uses setpriv instead of systemd capabilities + file_content = read_file(blackbox_exporter_service_file) + self.assertIn('setpriv', file_content) + self.assertIn('--ambient-caps=+net_raw', file_content) + self.assertIn('--inh-caps=+net_raw', file_content) + self.assertNotIn('AmbientCapabilities=CAP_NET_RAW', file_content) + + # Cleanup VRF + self.cli_delete(['vrf', 'name', vrf_name]) + if __name__ == '__main__': unittest.main(verbosity=2, failfast=VyOSUnitTestSHIM.TestCase.debug_on()) diff --git a/src/conf_mode/service_monitoring_prometheus.py b/src/conf_mode/service_monitoring_prometheus.py index b02f9f154..79b557329 100755 --- a/src/conf_mode/service_monitoring_prometheus.py +++ b/src/conf_mode/service_monitoring_prometheus.py @@ -20,6 +20,8 @@ from sys import exit from vyos.config import Config from vyos.configdict import is_node_changed +from vyos.configdict import node_changed +from vyos.configdiff import Diff from vyos.configverify import verify_vrf from vyos.template import render from vyos.utils.process import call @@ -76,6 +78,12 @@ def get_config(config=None): tmp = False for node in ['vrf', 'config-file']: tmp = tmp or is_node_changed(conf, base + ['blackbox-exporter', node]) + modules_changed = node_changed( + conf, + base + ['blackbox-exporter', 'modules'], + expand_nodes=Diff.ADD | Diff.DELETE, + ) + tmp = tmp or 'icmp' in modules_changed if tmp: monitoring.update({'blackbox_exporter_restart_required': {}}) |
