# driveripper-ops sudo rules for the UPS dashboard work # # Install as /etc/sudoers.d/dashboards-nut (visudo -cf it first): # # sudo visudo -cf - <<'EOF' ... EOF # syntax check # install -m 0440 deploy/nut-sudoers /tmp/dashboards-nut # sudo mv /tmp/dashboards-nut /etc/sudoers.d/dashboards-nut # # Keep it scoped: paths are absolute (sudoers uses `secure_path`), arguments are wildcards # only where the command is read-only or idempotent, and nothing here allows a shell, # `EDITOR=`, `dnf install` of arbitrary code, or `upsd -c` with an attacker-chosen file. # ---- already present on driveripper (this is what the dashboard setup used) ---------- # # (root) NOPASSWD: /usr/bin/tee /etc/ups/* # write upsd.conf / upsd.users # (root) NOPASSWD: /usr/bin/cp /etc/ups/* /home/ops/* # back up a config before editing # (root) NOPASSWD: /usr/bin/systemctl start|restart|reload|enable * # (root) NOPASSWD: /usr/bin/udevadm * # USB device discovery/replug # (root) NOPASSWD: /usr/bin/firewall-cmd * # only if upsd must serve the LAN # (root) NOPASSWD: /usr/bin/dnf install * # nut, nut-client, nut-dev # ---- still needed: diagnose why upsd runs but binds nothing -------------------------- # # Reading is the blocker. `upsd` is active, both drivers are up, and 3493 has no listener, # but /etc/ups/* is 0640 root:nut and the journal needs group membership: # $ sudo cat /etc/ups/upsd.conf -> Permission denied # $ journalctl -u nut-server -n 50 -> No entries (not in systemd-journal/wheel) # $ upsc -l -> Error: Connection failure: Connection refused Cmnd_Alias NUT_DIAGNOSE = \ /usr/bin/cat /etc/ups/*, \ /usr/bin/systemctl status *, \ /usr/bin/journalctl -u nut-server *, /usr/bin/journalctl -u nut-driver@*, \ /usr/bin/journalctl -u nut*, \ /usr/sbin/ss -ltnp, \ /usr/sbin/getenforce, \ /usr/bin/ausearch *, /usr/sbin/sealert -l *, \ /usr/sbin/semanage port -l, \ /usr/bin/upsdrvctl status, /usr/bin/upsdrvctl status *, \ /usr/bin/upsc *, \ /usr/bin/lsusb # ---- still needed: apply the fix and verify ------------------------------------------ # # `tee /etc/ups/*` already writes configs; these cover the reload path, SELinux booleans, # and a bounded cleanup of the .bak files `tee`-based edits leave behind. Cmnd_Alias NUT_APPLY = \ /usr/bin/tee /etc/ups/upsd.conf, /usr/bin/tee /etc/ups/upsd.users, \ /usr/bin/tee /etc/ups/ups.conf, /usr/bin/tee /etc/ups/nut.conf, \ /usr/bin/rm -f /etc/ups/*.bak-*, \ /usr/bin/upsdrvctl restart, /usr/bin/upsdrvctl restart *, \ /usr/sbin/setsebool -P allow_upsd_tcp_server 1, \ /usr/sbin/setsebool -P nis_enabled 0 # NOTE: deliberately NOT allowed, so an agent cannot power-cycle anything by accident: # /usr/bin/upscmd (any form) — the dashboard's own gated POST is the only command path # systemctl stop * — stopping nut-server would blind the UPS view # editors, shells, `sh -c` — no escape hatches