feat(power): monitor homelab power and reduce aquamarine idle draw (#501)

Assisted-by: DeepSeek Harness (deepseek-flash)
This commit is contained in:
ryan4yin | 二花 authored and GitHub committed 2026-11-01 20:53:41 +08:00
1 parent a97400df69
commit 0888f87075
18 files changed
+1688 -35

No files matched your search

+58
View File
@@ -0,0 +1,58 @@
{
config,
lib,
mylib,
pkgs,
...
}:
let
cfg = config.modules.powerMonitoring;
in
{
options.modules.powerMonitoring.enable = lib.mkEnableOption ''
Export RAPL CPU energy counters through node_exporter and allow only the
exporter to read them.
This weakens the kernel's root-only energy_uj permission for local RAPL
side-channel reasons, so it is opt-in and must stay disabled on desktops.
'';
config =
lib.mkIf (cfg.enable && config.modules.hardwareTools.enable && pkgs.stdenv.hostPlatform.isx86)
{
services.prometheus.exporters.node.enabledCollectors = [ "rapl" ];
# Only node_exporter needs the counters. Do not grant the interactive
# user or the world read access: both would expose a local RAPL
# side-channel to desktop sessions and unprivileged processes.
users.groups.rapl = lib.mkIf config.services.prometheus.exporters.node.enable { };
users.users = lib.mkIf config.services.prometheus.exporters.node.enable {
node-exporter.extraGroups = [ "rapl" ];
};
systemd.services.rapl-permissions = lib.mkIf config.services.prometheus.exporters.node.enable {
description = "Allow node_exporter to read RAPL energy counters";
wantedBy = [ "multi-user.target" ];
unitConfig.ConditionPathExists = "/sys/class/powercap";
serviceConfig = mylib.systemdHardening.privilegedOneshot // {
Type = "oneshot";
RemainAfterExit = true;
CapabilityBoundingSet = [ "CAP_CHOWN" ];
};
script = ''
shopt -s nullglob
for f in /sys/class/powercap/*/energy_uj; do
chgrp rapl "$f"
chmod 0440 "$f"
done
'';
};
systemd.services.prometheus-node-exporter =
lib.mkIf config.services.prometheus.exporters.node.enable
{
requires = [ "rapl-permissions.service" ];
after = [ "rapl-permissions.service" ];
};
};
}
+4
View File
@@ -5,6 +5,10 @@
../../base
];
# RAPL is a local side channel, so exposure is opt-in and scoped to the
# server role. Desktops keep the kernel-default root-only energy_uj.
modules.powerMonitoring.enable = true;
# Servers used to keep the firewall off, trusting the router alone. They now
# run the shared base firewall (modules/nixos/base/networking/firewall.nix)
# like every other host, as defence in depth behind the router.