This repository has been archived on 2026-08-17. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
beatzaplentyandClaude Sonnet 4.6 2909db5d04 restructure: move proxmox/ into subfolder, add pihole/ section
All existing content moved from repo root into proxmox/ to make room
for other Debian machine configs. Adds pihole/ with:

- config/pihole.toml — snapshot of current Pi-hole v6 config
- config/dnsmasq.d/99-ipxe-chainload.conf — custom PXE DHCP rules
  (EFI/BIOS iPXE chainload, fixed tag-specificity bug for UEFI boot)
- pull-config.sh <source-host> <dest-dir> — pull live config to disk
- apply-config.sh <source-dir> <dest-host> — push config to a Pi-hole

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XRzqNDrbnYR22ZgZj1Bg3s
2026-07-23 12:16:35 +10:00

6.0 KiB

Security Hardening

Stage 1 (see 00-overview.md) — applies to any Proxmox host, independent of cluster plans. Proxmox has no sudo out of the box — everything defaults to root. That's the install default, not the recommended end state. Two layers to harden separately.

Checklist / script mapping

Run scripts/bootstrap.sh for everything except the admin user (needs a username decision) and 2FA enrollment (must be done interactively via the web UI — there's no safe way to script TOTP secret generation over SSH). Then run scripts/audit.sh to verify. Order matters (matches bootstrap.sh):

# Item Script Manual step required?
1 Remove enterprise repos, switch to no-subscription switch-to-no-subscription-repo.sh no
2 Linux admin user with SSH key + sudo access setup-linux-admin-user.sh <user> <pubkey> yes — choose a username and provide your SSH public key. Run this before SSH hardening or pass ADMIN_USER/ADMIN_SSH_KEY to bootstrap.sh so it runs automatically at the right point
3 Passwordless sudo for pvesh/qm/pct setup-admin-sudo.sh <username> yes — same username as step 2
4 SSH: key-only root login + fail2ban harden-ssh.sh no — step 2 ensures authorized_keys are in place first
5 Unattended security upgrades, no auto-reboot setup-unattended-upgrades.sh no
6 PVE firewall, default-deny, mgmt-only SSH/8006 deploy-firewall.sh needs MGMT_CIDR set
7 Disable subscription nag (cosmetic) disable-subscription-nag.sh no
8 Named PVE admin user, Administrator role create-admin-user.sh <username> yes — pick the username, change the generated password on first login
9 2FA/TOTP on that user and root@pam yes — web UI only: Datacenter → Permissions → Two Factor, or user menu → TFA
10 Verify everything above audit.sh no

Linux/SSH layer

  • A named Linux system user (created by setup-linux-admin-user.sh) with an SSH authorized key and sudo group membership is the primary SSH login account. Root SSH is locked to key-only after harden-ssh.sh runs; the Linux admin user is how you get shell access day-to-day without using root.
  • setup-admin-sudo.sh adds a narrower, password-free sudoers rule for the Proxmox management tools (pvesh, qm, pct) specifically — needed for non-interactive automation scripts that SSH in and run these tools without a TTY.
  • PermitRootLogin prohibit-password in sshd_config — root can only log in via SSH key, never password. Kills most brute-force attempts.
  • fail2ban jail for SSH on top of that.
  • Restrict SSH to the management VLAN/trusted IPs via the Proxmox firewall (see 03-networking.md) rather than exposing broadly.

PVE/web layer (the one that actually matters day-to-day)

  • Keep root@pam for emergencies only.
  • Create a named user (e.g. wayne@pve) with the Administrator role for routine cluster management — create-admin-user.sh does this, or Datacenter → Permissions → Users manually.
  • Enable 2FA (TOTP or hardware key) on both that account and root@pam: Datacenter → Permissions → Realms/Users.
  • For API integrations (monitoring, automation, Terraform, etc.), issue scoped API tokens with least-privilege roles (e.g. PVEAuditor or a custom role) — never hand out root credentials.

Firewall

Default-deny at datacenter/node level, whitelist only what's needed (see 03-networking.md for the specifics). Template in config/pve-firewall/cluster.fw.example, applied by scripts/deploy-firewall.sh.

ICMP echo (ping) is explicitly allowed from the management network, alongside SSH/8006 — not required for anything to function, but without it policy_in: DROP silently eats ping while SSH/web UI keep working. That split (ping dead, everything else fine) reads exactly like a real outage mid-troubleshooting; see 06-pve-test-wifi-network.md for a case this caused genuine confusion after a network change. If you ever debug "can't ping but can SSH", check this firewall before assuming the network itself is broken.

This file is cluster-wide, not per-node: cluster.fw lives in /etc/pve/firewall/ — shared via pmxcfs across every node in a cluster. A node that joins a cluster inherits whatever's already there, and (per docs/05-node-roles.md) keeps its own local copy after leaving. Don't assume a node's firewall state matches what deploy-firewall.sh was last run with directly against it — check pve-firewall status / /etc/pve/firewall/cluster.fw on the actual node.

Repos and updates

Fresh installs point at the enterprise repo, which fails on apt update without a subscription. scripts/switch-to-no-subscription-repo.sh removes the enterprise sources entirely (renamed .disabled, not just commented out) and switches to the no-subscription repo — handles both the legacy .list format and the deb822 .sources format current installers write. Keep the host patched — hypervisor CVEs are high-value targets; scripts/setup-unattended-upgrades.sh automates security patches (deliberately no auto-reboot on a hypervisor — check /var/run/reboot-required and reboot during a planned window).

The web UI's "No valid subscription" popup and dashboard indicator are cosmetic upsell, not a security control, but with no subscription they'll nag on every login — scripts/disable-subscription-nag.sh patches proxmox-widget-toolkit's JS to suppress them, and installs an apt Post-Invoke hook that reapplies the patch automatically after every apt/dpkg run, since a proxmox-widget-toolkit package upgrade overwrites the patched file.

Misc

  • Management interface on a network you trust, not the same broadcast domain as guest VM traffic.
  • If the web UI is ever needed outside the LAN, put it behind a VPN — don't port-forward 8006 directly.

Further reading / not yet automated here

  • CIS Benchmark for Proxmox VE
  • Community PVE hardening guides (kernel parameters, audit logging, storage encryption)