Relax NoNewPrivileges only when a least-privilege sudo grant is active

Live proof on a real systemd host (Debian 12 container, full
install/report/update/uninstall cycle) caught what no unit test did:
NoNewPrivileges=true blocks sudo outright, so the --grant-smart and
--grant-pct helpers failed inside the service and SMART/pct silently
disappeared while the install reported success. A unit with an active
grant now sets NoNewPrivileges=false, keeping the rest of the hardening;
a grantless least-privilege install keeps NNP enabled. Docs and contracts
state the trade-off: each grant is a scoped, auditable widening.

Also proven in the same live cycle: the flag-conflict refusals, user and
sudoers provisioning, wrapper execution as the service user, the healthy
privilege report ({runningAsRoot:false, serviceUser:pulse-agent,
smartctlHelper:true}), --update preserving the profile without repeated
flags, and uninstall removing the sudoers file and helpers.
This commit is contained in:
rcourtman
2026-08-20 21:36:34 +01:00
parent 86d0af4979
commit df1290066e
6 changed files with 27 additions and 5 deletions
+5 -1
View File
@@ -146,7 +146,11 @@ dropping the LXC-attach ambient capability grant entirely.
Two optional flags restore the collectors that genuinely need elevation, each
through an exact-command sudoers grant validated with `visudo` and a
root-owned wrapper the agent is pointed at via an absolute-path-only
environment override:
environment override. Because `NoNewPrivileges` blocks `sudo` entirely, a
unit with an active grant sets `NoNewPrivileges=false` while keeping the
remaining hardening; a grantless least-privilege install keeps
`NoNewPrivileges=true`. Choose grants deliberately: each one is a scoped,
auditable widening of the profile.
- `--grant-smart` allows exactly `smartctl`, restoring SMART disk health.
- `--grant-pct` allows exactly `pct list` and `pct df`, restoring Proxmox LXC
@@ -6419,7 +6419,10 @@ installed unit rather than requiring the flags to be repeated. Optional
need elevation through visudo-validated, exact-command sudoers rules and
root-owned wrapper helpers the agent reaches only via the absolute-path-only
`PULSE_SMARTCTL_PATH` / `PULSE_PCT_PATH` overrides; the pct grant covers
`pct list` and `pct df` only and can never widen into `pct exec`. The agent
`pct list` and `pct df` only and can never widen into `pct exec`. An active
grant sets `NoNewPrivileges=false` because NNP blocks sudo outright (proven
on a live systemd host); a grantless profile keeps `NoNewPrivileges=true`.
The agent
authors a `privilege` block in its report (`pkg/agents/host/report.go`
`PrivilegeStatus`: effective root, service user, active helpers) so the
server can present the profile descriptively. Uninstall removes the sudoers
@@ -3474,6 +3474,8 @@ exact-command sudoers rules with root-owned wrapper helpers wired through
flag is refused (never silently downgraded to root) on appliance platforms
and non-systemd init systems, is mutually exclusive with
`--enable-commands`, and `--update` preserves an installed profile and its
grants by reading the existing unit. Uninstall removes the sudoers file and
helper directory. `scripts/installtests/install_sh_test.go`
grants by reading the existing unit. A unit with an active grant sets
`NoNewPrivileges=false` because NNP blocks sudo (proven on a live systemd
host); a grantless profile keeps `NoNewPrivileges=true`. Uninstall removes
the sudoers file and helper directory. `scripts/installtests/install_sh_test.go`
(`TestInstallSHLeastPrivilegeProfile`) pins these invariants.
@@ -2287,6 +2287,8 @@ non-root with a nologin shell, keep every sudoers grant exact-command and
visudo-validated with the pct grant excluding `pct exec`/`start`/`stop`/
`enter`, refuse `--enable-commands` under the profile, refuse unsupported
platforms instead of silently reverting to root, and drop the LXC-attach
ambient capability grant. The agent-reported privilege profile is
ambient capability grant. `NoNewPrivileges` stays enabled on a grantless
profile and is relaxed only when a sudo grant is active, because NNP blocks
sudo outright; that relaxation is part of the grant's declared cost. The agent-reported privilege profile is
informational: the fleet doctor presents it descriptively and must not treat
a non-root agent as unhealthy on that evidence alone.
+8
View File
@@ -1034,6 +1034,14 @@ render_systemd_agent_unit() {
no_new_privileges="false"
restrict_suidsgid="false"
fi
if [[ "$LEAST_PRIVILEGE" == "true" ]] && [[ "$GRANT_SMART" == "true" || "$GRANT_PCT" == "true" ]]; then
# The scoped sudo helpers are the profile's only privilege path, and
# NoNewPrivileges blocks sudo outright ("no new privileges flag is
# set"). Proven on a live systemd host: with NNP on, every helper call
# fails and SMART/pct silently disappear. A grant therefore relaxes
# NNP; a grantless least-privilege install keeps it.
no_new_privileges="false"
fi
if systemd_agent_may_attach_lxc; then
# lxc-attach into an unprivileged guest writes /proc/<pid>/uid_map,
# which needs CAP_SETUID in the parent user namespace. NoNewPrivileges
+3
View File
@@ -5564,6 +5564,9 @@ func TestInstallSHLeastPrivilegeProfile(t *testing.T) {
`"network-online.target" "$SERVICE_USER" ""`,
"# The least-privilege profile never attaches into guests",
`rm -f "$PRIVILEGE_SUDOERS_FILE"`,
// NoNewPrivileges blocks sudo, so an active grant must relax it or
// the helpers silently fail inside the service (proven live).
`if [[ "$LEAST_PRIVILEGE" == "true" ]] && [[ "$GRANT_SMART" == "true" || "$GRANT_PCT" == "true" ]]; then`,
}
for _, needle := range required {
if !strings.Contains(script, needle) {