summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNataliia Solomko <natalirs1985@gmail.com>2026-07-02 11:46:45 +0300
committerNataliia Solomko <natalirs1985@gmail.com>2026-07-02 15:34:17 +0300
commitf56f37924f05bcfebd05342ccb40c53001b3409a (patch)
tree81d34c79d743cea47d827e4424ae9ac3182c0e97
parent063e007a5a8eac3bb9ad101206dc94734eeaa595 (diff)
downloadvyos-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.j216
-rwxr-xr-xsmoketest/scripts/cli/test_service_monitoring_prometheus.py46
-rwxr-xr-xsrc/conf_mode/service_monitoring_prometheus.py8
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': {}})