Archived
add setup-admin-sudo.sh for passwordless Proxmox tool access
The nixos flake's create-proxmox-resource.sh runs pvesh/qm/pct over non-interactive SSH, which requires NOPASSWD sudo for those binaries. pvesh moved from /usr/sbin to /usr/bin in PVE 8.x, so the script resolves paths at runtime rather than hardcoding them, preventing the silent NOPASSWD-miss that caused ipcc_send_rec errors. - scripts/setup-admin-sudo.sh: new script, takes username, writes /etc/sudoers.d/<user>-proxmox with correct resolved paths and validates it with visudo -c before leaving it in place - scripts/bootstrap.sh: add setup-admin-sudo.sh to post-steps list - scripts/audit.sh: check that a *-proxmox sudoers file exists with NOPASSWD for all three tools Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -76,6 +76,23 @@ else
|
|||||||
audit_fail "no named @pve user found - root@pam is the only account"
|
audit_fail "no named @pve user found - root@pam is the only account"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# --- passwordless sudo for pvesh/qm/pct ---
|
||||||
|
# The nixos flake's create-proxmox-resource.sh runs pvesh/qm/pct over
|
||||||
|
# non-interactive SSH, so the admin user needs NOPASSWD for these tools.
|
||||||
|
SUDO_OK=0
|
||||||
|
for f in /etc/sudoers.d/*-proxmox; do
|
||||||
|
[ -f "$f" ] || continue
|
||||||
|
if grep -qE 'NOPASSWD:.*pvesh' "$f" && grep -qE 'NOPASSWD:.*\bqm\b' "$f" && grep -qE 'NOPASSWD:.*\bpct\b' "$f"; then
|
||||||
|
SUDO_OK=1
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ "$SUDO_OK" -eq 1 ]; then
|
||||||
|
audit_pass "admin user has NOPASSWD sudo for pvesh/qm/pct"
|
||||||
|
else
|
||||||
|
audit_fail "no sudoers file grants NOPASSWD for pvesh/qm/pct (run setup-admin-sudo.sh <username>)"
|
||||||
|
fi
|
||||||
|
|
||||||
# --- time sync ---
|
# --- time sync ---
|
||||||
if timedatectl show -p NTPSynchronized --value 2>/dev/null | grep -qx 'yes'; then
|
if timedatectl show -p NTPSynchronized --value 2>/dev/null | grep -qx 'yes'; then
|
||||||
audit_pass "clock is NTP-synchronized"
|
audit_pass "clock is NTP-synchronized"
|
||||||
|
|||||||
@@ -41,5 +41,6 @@ echo "=== 5/5: disable subscription nag (cosmetic) ==="
|
|||||||
echo
|
echo
|
||||||
echo "=== Base hardening applied. Remaining manual/deliberate steps: ==="
|
echo "=== Base hardening applied. Remaining manual/deliberate steps: ==="
|
||||||
echo " - ${SCRIPT_DIR}/create-admin-user.sh <username>"
|
echo " - ${SCRIPT_DIR}/create-admin-user.sh <username>"
|
||||||
|
echo " - ${SCRIPT_DIR}/setup-admin-sudo.sh <username> (passwordless sudo for pvesh/qm/pct)"
|
||||||
echo " - Enable 2FA/TOTP for that user and root@pam via the web UI"
|
echo " - Enable 2FA/TOTP for that user and root@pam via the web UI"
|
||||||
echo " - ${SCRIPT_DIR}/audit.sh (verify everything above)"
|
echo " - ${SCRIPT_DIR}/audit.sh (verify everything above)"
|
||||||
|
|||||||
Executable
+49
@@ -0,0 +1,49 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Grant a named admin user passwordless sudo for Proxmox management tools
|
||||||
|
# (pvesh, qm, pct) so that scripts in the nixos flake repo can run these
|
||||||
|
# over non-interactive SSH without a TTY for password entry.
|
||||||
|
#
|
||||||
|
# Idempotent - safe to re-run (rewrites if paths have changed). Run as
|
||||||
|
# root on the PVE host.
|
||||||
|
#
|
||||||
|
# Usage: ./setup-admin-sudo.sh <username>
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
# shellcheck source=lib/common.sh
|
||||||
|
source "${SCRIPT_DIR}/lib/common.sh"
|
||||||
|
require_root
|
||||||
|
|
||||||
|
USERNAME="${1:-}"
|
||||||
|
if [ -z "$USERNAME" ]; then
|
||||||
|
echo "Usage: $0 <username>" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Resolve actual binary paths at script time -- they differ across Proxmox
|
||||||
|
# versions (pvesh moved from /usr/sbin to /usr/bin in PVE 8.x) and the
|
||||||
|
# sudoers rule must match the real path or sudo will fall back to
|
||||||
|
# prompting for a password.
|
||||||
|
resolve_bin() {
|
||||||
|
command -v "$1" 2>/dev/null || { echo "ERROR: $1 not found on PATH" >&2; exit 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
PVESH="$(resolve_bin pvesh)"
|
||||||
|
QM="$(resolve_bin qm)"
|
||||||
|
PCT="$(resolve_bin pct)"
|
||||||
|
|
||||||
|
SUDOERS_FILE="/etc/sudoers.d/${USERNAME}-proxmox"
|
||||||
|
CONTENT="${USERNAME} ALL=(root) NOPASSWD: ${PVESH}, ${QM}, ${PCT}"
|
||||||
|
|
||||||
|
write_if_changed "$SUDOERS_FILE" "$CONTENT"
|
||||||
|
|
||||||
|
# visudo -c validates the file we just wrote before we walk away.
|
||||||
|
if visudo -c -f "$SUDOERS_FILE" >/dev/null 2>&1; then
|
||||||
|
chmod 0440 "$SUDOERS_FILE"
|
||||||
|
echo "Sudoers rule for ${USERNAME} is valid and in place."
|
||||||
|
echo " ${CONTENT}"
|
||||||
|
else
|
||||||
|
echo "ERROR: sudoers validation failed -- removing bad file." >&2
|
||||||
|
rm -f "$SUDOERS_FILE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
Reference in New Issue
Block a user