host_exporters: IPMI exporter with sudo-pinned FreeIPMI tools for hosts with a BMC
This commit is contained in:
@@ -2,3 +2,28 @@
|
|||||||
# Adds prometheus-smartctl-exporter (trixie-backports) next to the node exporter
|
# Adds prometheus-smartctl-exporter (trixie-backports) next to the node exporter
|
||||||
# on hosts with physical disks.
|
# on hosts with physical disks.
|
||||||
host_exporters_smart: false
|
host_exporters_smart: false
|
||||||
|
|
||||||
|
# Adds ipmitool and prometheus-ipmi-exporter (port 9290) on hosts with a BMC reachable through /dev/ipmi0.
|
||||||
|
host_exporters_ipmi: false
|
||||||
|
host_exporters_ipmi_collectors:
|
||||||
|
- ipmi
|
||||||
|
- bmc
|
||||||
|
- sel
|
||||||
|
- chassis
|
||||||
|
# FreeIPMI tool behind each collector and the fixed arguments the exporter (1.10) passes before
|
||||||
|
# --config-file <temporary file>. sudo admits exactly these, so a compromised exporter cannot
|
||||||
|
# run chassis control or clear the SEL. A different exporter version needs matching arguments
|
||||||
|
# (ipmi_up stays 0 until then). dcmi is not listed: the S1200RP BMC has no power monitoring.
|
||||||
|
host_exporters_ipmi_tools:
|
||||||
|
ipmi:
|
||||||
|
tool: ipmimonitoring
|
||||||
|
args: --quiet-cache --ignore-unrecognized-events --comma-separated-output --no-header-output --sdr-cache-recreate --output-event-bitmask --output-sensor-state
|
||||||
|
bmc:
|
||||||
|
tool: bmc-info
|
||||||
|
args: ""
|
||||||
|
sel:
|
||||||
|
tool: ipmi-sel
|
||||||
|
args: --info
|
||||||
|
chassis:
|
||||||
|
tool: ipmi-chassis
|
||||||
|
args: --get-chassis-status
|
||||||
|
|||||||
@@ -69,3 +69,91 @@
|
|||||||
enabled: true
|
enabled: true
|
||||||
state: started
|
state: started
|
||||||
ignore_errors: "{{ ansible_check_mode }}"
|
ignore_errors: "{{ ansible_check_mode }}"
|
||||||
|
|
||||||
|
# Reads the BMC through /dev/ipmi0, read-only: no raw commands, no configuration.
|
||||||
|
# FreeIPMI refuses in-band access for any uid but 0, so the exporter runs as the packaged
|
||||||
|
# unprivileged user prometheus and starts the FreeIPMI tools it needs through sudo.
|
||||||
|
- name: Install the IPMI exporter
|
||||||
|
when: host_exporters_ipmi
|
||||||
|
block:
|
||||||
|
- name: Install ipmitool and the IPMI exporter
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name:
|
||||||
|
- ipmitool
|
||||||
|
- sudo
|
||||||
|
- prometheus-ipmi-exporter
|
||||||
|
install_recommends: false
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Allow the exporter user to run the FreeIPMI tools
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: /etc/sudoers.d/prometheus-ipmi-exporter
|
||||||
|
mode: "0440"
|
||||||
|
validate: visudo -cf %s
|
||||||
|
content: |
|
||||||
|
Defaults:prometheus !log_allowed, !pam_session
|
||||||
|
{% for collector in host_exporters_ipmi_collectors %}
|
||||||
|
prometheus ALL = (root) NOPASSWD: /usr/sbin/{{ host_exporters_ipmi_tools[collector].tool }} {{ host_exporters_ipmi_tools[collector].args }} --config-file /tmp/ipmi_exporter-{{ '[0-9a-f]' * 32 }}
|
||||||
|
{% endfor %}
|
||||||
|
register: host_exporters_ipmi_sudo
|
||||||
|
|
||||||
|
# collector_cmd replaces the tool itself, so each collector gets a wrapper that adds sudo.
|
||||||
|
- name: Create the sudo wrappers directory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /usr/local/libexec/ipmi-exporter
|
||||||
|
state: directory
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
- name: Write the sudo wrappers
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: /usr/local/libexec/ipmi-exporter/{{ item.key }}
|
||||||
|
mode: "0755"
|
||||||
|
content: |
|
||||||
|
#!/bin/sh
|
||||||
|
exec sudo -n /usr/sbin/{{ item.value.tool }} "$@"
|
||||||
|
loop: "{{ host_exporters_ipmi_tools | dict2items | selectattr('key', 'in', host_exporters_ipmi_collectors) | list }}"
|
||||||
|
loop_control:
|
||||||
|
label: "{{ item.key }}"
|
||||||
|
register: host_exporters_ipmi_wrappers
|
||||||
|
|
||||||
|
- name: Write the IPMI exporter configuration
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: /etc/prometheus/ipmi-local.yml
|
||||||
|
mode: "0644"
|
||||||
|
content: |
|
||||||
|
modules:
|
||||||
|
default:
|
||||||
|
collectors:
|
||||||
|
{% for collector in host_exporters_ipmi_collectors %}
|
||||||
|
- {{ collector }}
|
||||||
|
{% endfor %}
|
||||||
|
collector_cmd:
|
||||||
|
{% for collector in host_exporters_ipmi_collectors %}
|
||||||
|
{{ collector }}: /usr/local/libexec/ipmi-exporter/{{ collector }}
|
||||||
|
{% endfor %}
|
||||||
|
register: host_exporters_ipmi_config
|
||||||
|
|
||||||
|
- name: Create the IPMI exporter unit drop-in directory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /etc/systemd/system/prometheus-ipmi-exporter.service.d
|
||||||
|
state: directory
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
# sudo needs setuid, so NoNewPrivileges stays off.
|
||||||
|
- name: Run the IPMI exporter with that configuration
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: /etc/systemd/system/prometheus-ipmi-exporter.service.d/local.conf
|
||||||
|
mode: "0644"
|
||||||
|
content: |
|
||||||
|
[Service]
|
||||||
|
ExecStart=
|
||||||
|
ExecStart=/usr/bin/prometheus-ipmi-exporter --config.file=/etc/prometheus/ipmi-local.yml
|
||||||
|
register: host_exporters_ipmi_unit
|
||||||
|
|
||||||
|
- name: Enable the IPMI exporter
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: prometheus-ipmi-exporter
|
||||||
|
enabled: true
|
||||||
|
state: "{{ 'restarted' if (host_exporters_ipmi_config.changed or host_exporters_ipmi_unit.changed or host_exporters_ipmi_wrappers.changed) else 'started' }}"
|
||||||
|
daemon_reload: true
|
||||||
|
ignore_errors: "{{ ansible_check_mode }}"
|
||||||
|
|||||||
Reference in New Issue
Block a user