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
debian-configuration/docs/04-security-hardening.md
T
beatzaplenty 2cca6a7dc0 Stage 1 base config/hardening toolset, applied and verified on pve1
Splits the repo into Stage 1 (base host config/hardening, applies to any
node) and Stage 2 (future HA/Ceph cluster, deferred - pve1's mini-PC
hardware can't support the assumed split-disk/multi-NIC layout).

Adds the Stage 1 toolset: firewall deploy, named admin user creation,
unattended security upgrades, subscription-nag removal (with an apt hook
so the patch survives package updates), and a read-only audit script.
Fixes switch-to-no-subscription-repo.sh, which only handled the legacy
.list format and silently no-op'd against PVE 9's deb822 .sources files;
it now removes enterprise sources outright rather than commenting them
out. Shared logic (root check, idempotent file writes, backups) factored
into scripts/lib/common.sh.

Ran the full sequence against pve1 via scripts/bootstrap.sh +
create-admin-user.sh; scripts/audit.sh confirms all checks pass.
2026-07-21 05:44:50 +00:00

4.3 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 SSH: key-only root login + fail2ban harden-ssh.sh no (requires an authorized_keys already in place — script warns if missing)
3 Unattended security upgrades, no auto-reboot setup-unattended-upgrades.sh no
4 PVE firewall, default-deny, mgmt-only SSH/8006 deploy-firewall.sh needs MGMT_CIDR set
5 Disable subscription nag (cosmetic) disable-subscription-nag.sh no
6 Named PVE admin user, Administrator role create-admin-user.sh <username> yes — pick the username, change the generated password on first login
7 2FA/TOTP on that user and root@pam yes — web UI only: Datacenter → Permissions → Two Factor, or user menu → TFA
8 Verify everything above audit.sh no

Linux/SSH layer

  • 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.
  • A separate Linux sudo user isn't strictly required for day-to-day PVE admin (the PVE permission system below governs that), but worth adding if multiple people SSH into the box directly, for accountability.

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.

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)