Security Audit β Oak Techx Homelab¶
Date: 2026-06-07 (post-Session-10 marathon, performed while Kay slept) Auditor: Claude Opus 4.7 Scope: All deployed services + PVE host + iLO + network + TLS + secrets + backups + updates Method: Read-only probing across PVE, all LXCs, network paths, container configs. No state changes made during the audit.
Severity scale¶
| Symbol | Meaning |
|---|---|
| π΄ CRITICAL | Fix before next session β unauth-access or data-loss risk |
| π HIGH | Fix this week β exploitable under specific conditions |
| π‘ MEDIUM | Fix this month β hardening gap, defense-in-depth |
| π΅ LOW / HYGIENE | Track and clean opportunistically |
| β GOOD | Already secure, noted for completeness |
Executive summary¶
Overall posture: Solid foundation, weak host-level hardening. The application layer (Authelia SSO+MFA, Vaultwarden signups locked, Nextcloud + GitLab behind Traefik + LE certs, Cloudflare Tunnel for the single external surface) is well above homelab average. The exposure surface to the public internet is correctly limited to ONE hostname (cloud.iamkay.eu) via Cloudflare Tunnel. The weakness is on PVE host hardening and the unpatched PVE 8.1.5 running stale.
Top 5 fixes to prioritize:
- π΄ PVE 8.1.5 needs to update to 8.3+ (5+ months of security patches missing)
- π΄ SSH allows root password auth on PVE host + no fail2ban β brute-forceable if VLAN 10 ever leaks
- π΄ No off-site backup β single-site failure (theft, fire, ransomware) destroys homelab
- π GitLab + Nextcloud admin users have no enforced 2FA (Kay personally has it; not enforced for future users)
- π PVE root has no 2FA in pveum
1. PVE host (arochukwu, 10.0.10.5)¶
1.1 π΄ CRITICAL β PVE 5+ months behind, kernel stale¶
| Item | Current | Latest as of 2026-06-07 |
|---|---|---|
pve-manager |
8.1.5 (Jan 2024) | 8.3.x (May 2026) |
kernel |
6.5.13-3-pve | 6.8.x-pve |
Risk: Multiple CVEs in PVE 8.1 β 8.3 windows include LXC escape, container privilege escalation, web UI XSS. Currently exploitable only with PVE auth (PAM root), but reduces defense-in-depth.
Remediation:
# On PVE host, before next maintenance window:
apt update
apt full-upgrade -y
# Read changelog before reboot
reboot
1.2 π΄ CRITICAL β SSH root password auth + no fail2ban¶
PermitRootLogin yes
PasswordAuthentication (not explicitly set β defaults yes)
fail2ban NOT installed
Risk: If VLAN 10 ever leaks (compromised LXC, misconfigured switch, future Tailscale routing change), root SSH is brute-forceable. There's no rate limiting.
Remediation (do in this order on PVE host):
# 1. Install fail2ban first (so even if SSH config has issues, you have backup protection)
apt install fail2ban
# Default jail.local for sshd is sane; enable + start:
systemctl enable --now fail2ban
# 2. Tighten SSH config β these lines in /etc/ssh/sshd_config:
PermitRootLogin prohibit-password # only key auth as root
PasswordAuthentication no
PubkeyAuthentication yes
ChallengeResponseAuthentication no
X11Forwarding no
MaxAuthTries 3
# 3. Before restarting sshd, ensure your key still works:
# Open a SECOND ssh session and keep it alive β if the new config locks you out,
# the second session can fix it. Then:
systemctl restart sshd
# Verify second session still works before closing first session.
1.3 π΄ CRITICAL β pve-firewall disabled, no unattended-upgrades¶
Risk: No host-level filtering of ingress to PVE; no automated patching.
Remediation:
# 1. Enable unattended-upgrades for security patches only
apt install unattended-upgrades apt-listchanges
dpkg-reconfigure -plow unattended-upgrades
# Edit /etc/apt/apt.conf.d/50unattended-upgrades to include "Debian-Security" updates
# 2. pve-firewall β leave OFF until you write rules first;
# turning it ON with empty rules will work fine (defaults allow), but
# for actual hardening:
# /etc/pve/firewall/cluster.fw β enable + REJECT default IN
# /etc/pve/nodes/arochukwu/host.fw β allow VLAN 10 + VLAN 40
# Document rules before enabling. Deferred until you have time to test.
1.4 π HIGH β rpcbind exposed on 0.0.0.0:111 (DDoS amplification vector)¶
PVE host doesn't run an NFS server. rpcbind is listening on all interfaces.
Remediation:
# Bind rpcbind to localhost only via /etc/default/rpcbind:
echo 'OPTIONS="-w -h 127.0.0.1"' > /etc/default/rpcbind
systemctl restart rpcbind
1.5 π HIGH β node_exporter on 0.0.0.0:9100 (system metrics exposed)¶
Prometheus exporter for PVE host metrics is listening on all interfaces. Exposes kernel version, hardware, mountpoints, etc. β useful for fingerprinting attackers.
Remediation: Bind to VLAN 10 only via --web.listen-address=10.0.10.5:9100 in /etc/default/prometheus-node-exporter, then restart.
1.6 π HIGH β PVE root user has no 2FA¶
pveum user list shows root@pam, tfa-locked-until empty. PVE web UI accepts root login with only the PAM (Linux root) password. Even though you have a strong password, there's no second factor.
Remediation: Web UI β Datacenter β Permissions β Two Factor β Add for root@pam (TOTP). Use the same authenticator app that has your Authelia + Nextcloud entries.
1.7 π‘ MEDIUM β Stale apt sources file¶
pve-enterprise.list.dpkg-old exists β dangling old apt config file. Harmless but clutter.
Remediation: rm /etc/apt/sources.list.d/pve-enterprise.list.dpkg-old (after confirming nothing references it).
1.8 π‘ MEDIUM β RSA SSH key in authorized_keys¶
/root/.ssh/authorized_keys has 3 keys; one is ssh-rsa. ed25519 is preferred.
Remediation: Identify the ssh-rsa key (probably win11 comment), regenerate as ed25519, replace.
1.9 β GOOD on PVE host¶
- Only
root@pamuser (no leftover defaults) /etc/pve/storage.cfg,datacenter.cfg,user.cfghave correct perms (-rw-r----- root:www-data)- chrony NTP active, system time accurate
- Postfix bound to loopback only (
127.0.0.1:25) - prometheus-node-exporter behind
pve-firewallpolicy when enabled - PVE web UI requires authentication
2. iLO 3 (172.16.1.3)¶
(Limited probing β most checks require iLO console; reusing findings from reference_ilo3_v194_quirks.md)
2.1 π΄ CRITICAL β TLS 1.0 only (iLO 3 firmware ceiling)¶
iLO 3 v1.94 (final firmware, 2020-12-06) supports only TLS 1.0. Browsers, OpenSSL 3.0, Windows Schannel all reject it by default. Firefox requires manual about:config toggle.
Risk: Active MITM on VLAN 40 can downgrade and observe iLO admin sessions. Practical risk is low (VLAN 40 is restricted), but the protocol itself is broken.
Remediation: There is no fix β HP discontinued iLO 3 firmware support. Mitigation: ensure iLO is on isolated VLAN 40 (β done Session 7), require MGMT VPN to access iLO from outside, and treat any iLO web UI session as untrusted.
2.2 π HIGH β DSA-1024 SSH key for iLO kay user¶
iLO 3 only accepts DSA keys (RSA paste fails). DSA-1024 is cryptographically weak by modern standards.
Risk: Theoretical key recovery via accumulated TLS observations. Practical risk: very low on isolated VLAN 40.
Remediation: Same as 2.1 β accept the firmware ceiling. Track for replacement at iLO swap (would require new hardware).
2.3 π HIGH β IPMI/UDP 623 open on VLAN 40¶
IPMI-over-LAN was enabled in Session 3 for ipmitool access. Anyone on VLAN 40 (currently: laptop, iLO itself, PVE vmbr0.40) can attempt RMCP+ auth. Brute-force protected by iLO's own throttle, but the protocol family has had historical vulnerabilities.
Risk: If VLAN 40 ever has untrusted devices, iLO can be probed.
Remediation: Add pfSense rule: drop UDP/623 ingress from anything NOT in {laptop static IP, PVE 172.16.1.5}. Allow MGMT laptop + PVE only. Test ipmitool still works after rule.
2.4 β GOOD on iLO¶
- iLO Advanced license active
kayadmin user, defaultAdministratorslot renamed- FIPS Mode NOT enabled (per CLAUDE.md Β§0 rule β would wipe config)
- iLO on isolated VLAN 40 since Session 7
- pfSense blocks VLAN 10 β MGMT (Session 7)
3. Network & firewall¶
3.1 π HIGH β pfSense rules not audited¶
Only pfSense itself can show the full rule table; I can't probe it from PVE. Recommendation: log into pfSense, export full rule set, review for: - WAN exposure (anything other than CF Tunnel egress?) - Default-deny on all LANβWAN paths except whitelisted ports - Block bogons enabled - pfBlockerNG / IDS configured
3.2 β GOOD β Cross-VLAN segregation enforced¶
- VLAN 10 (SERVERS) β VLAN 40 (MGMT): blocked by pfSense rule (Session 7, verified six ways)
- VLAN 10 β VLAN 1: blocked
- VLAN 10 β internet: allowed (egress)
- VLAN 40 β VLAN 40 intra-VLAN: open (laptop β iLO β host vmbr0.40, no pfSense in path)
3.3 β GOOD β Per-LXC port exposure mapped¶
Each LXC's listening ports identified β no surprises. All services on intended ports (e.g. Authelia 9091, Pi-hole 53+8081, Traefik 80+443).
3.4 β GOOD β Cloudflare Tunnel egress is exclusively to Cloudflare-owned IPs¶
cloudflared talks only to 198.41.* (Cloudflare's Argo Tunnel IP block). No unexpected egress.
3.5 π‘ MEDIUM β Public DNS leaks domain structure¶
hm.iamkay.eu apex resolves publicly to Cloudflare IPs (no hostname configured on the tunnel for the apex, so requests would 1014). Reveals that hm.iamkay.eu is the internal domain. Minor info disclosure β attackers know your naming scheme. Not directly exploitable.
Remediation: Optional β use a different internal-only TLD (e.g. .lan or unregistered). Defer; reorganizing DNS naming is high-effort, low-impact.
4. TLS posture¶
4.1 β GOOD β All certs valid LE, auto-renewing¶
13 hostnames covered by 2 certs (*.hm.iamkay.eu wildcard + cloud.iamkay.eu apex sibling). Expiries 2026-08-13 (cloud.iamkay.eu) and 2026-09-03 (wildcard). DNS-01 via Cloudflare token, auto-renews ~30 days before expiry.
4.2 β GOOD β TLS 1.0 rejected at Traefik¶
openssl s_client -tls1 is rejected with protocol version alert. Minimum TLS 1.2 enforced (Traefik defaults).
4.3 β GOOD β TLS 1.3 active on Cloudflare-fronted endpoint¶
cloud.iamkay.eu negotiates TLSv1.3 with TLS_AES_256_GCM_SHA384. Browser-trusted cert chain.
4.4 π HIGH β vault.hm.iamkay.eu missing HSTS header¶
cloud.iamkay.eu HSTS: max-age=15552000; includeSubDomains β
cloud.hm.iamkay.eu HSTS: max-age=15552000; includeSubDomains β
vault.hm.iamkay.eu HSTS: NOT SET β
Risk: Initial HTTPS connection vulnerable to TLS-stripping if attacker has on-path access. For Vaultwarden β your password vault β HSTS is essential.
Remediation: Add HSTS middleware to Traefik's vault.yml dynamic config. Same pattern as Nextcloud's nextcloud-headers. Will set on next session.
4.5 π‘ MEDIUM β Other internal services may also lack HSTS¶
Same audit could apply to traefik dashboard, grafana, kuma, gitlab, pbs, homenas, dns, home, arochukwu, pi-hole admin. Most rely on Authelia gating which mitigates but doesn't fix HSTS specifically.
Remediation: Create a global Traefik middleware security-headers@file with HSTS + standard security headers, attach to every router. One-time write of ~20 lines.
5. Application services¶
5.1 β GOOD β Vaultwarden (LXC 252)¶
- β
Signups disabled (
signups_allowed: false) - β Invitations disabled
- β Admin token argon2id-hashed (m=65536, t=3, p=4)
- β Domain config matches Traefik route
- β
Daily PBS backup of
/opt/vaultwarden/data/
5.2 π HIGH β Vaultwarden emergency access enabled¶
emergency_access_allowed: true β feature lets designated contacts request access to your vault after a delay (in case of incapacitation). Without contacts configured, the setting is moot. Worth disabling if not using.
Remediation: Vaultwarden admin panel (vault.hm.iamkay.eu/admin) β Settings β Domain β toggle off emergency_access_allowed (unless setting up an emergency contact).
5.3 π‘ MEDIUM β Vaultwarden require_device_email: false¶
Anyone with valid credentials can log in from a new device without email verification of the new device. Slightly weakens device-binding.
Remediation: Enable require_device_email in admin panel β but requires SMTP first. Defer until family-cloud SMTP setup.
5.4 β GOOD β Authelia (LXC 254)¶
- β
Default policy
deny - β Regulation: 3 retries / 2 min find / 5 min ban β production-tight
- β Session: 5 min inactive / 1 h max / 1 month remember
- β TOTP enforced for protected routes
- β Argon2id password hashing
- β File-based user DB (small N β appropriate for 1-5 users)
- π‘ SMTP deferred β bypasses email verification today
5.5 π HIGH β Nextcloud 2FA not enforced for any group¶
occ twofactorauth:enforce returns "Two-factor authentication is not enforced". Kay personally enabled TOTP tonight, but it's not required.
Risk: When family users are added, they'll skip 2FA by default. Family-cloud security depends on every user having MFA.
Remediation: Once family users are onboarded:
pct exec 258 -- docker exec -u www-data nextcloud-app php occ twofactorauth:enforce --on --group=admin --group=family
5.6 β GOOD β Nextcloud baseline¶
- β
overwriteprotocol: https - β
trusted_proxiesset to10.0.10.10/32(Traefik) - β Brute-force protection enabled (Nextcloud default)
- β App passwords required for sync clients
- β External Storage configured for NFS β keeps data off LXC rootfs
- β Not behind Authelia (correct β sync clients break with ForwardAuth)
5.7 β GOOD β GitLab (LXC 257)¶
- β
Signup disabled (
signup_enabled: false) - β
Only 2 users (admin
root+kay) - β Password auth for web UI enabled (with PAT for API)
5.8 π HIGH β GitLab 2FA not required¶
require_two_factor_authentication: false. Same risk pattern as Nextcloud β admin actions don't require second factor.
Remediation: GitLab Admin β Settings β General β Sign-in restrictions β enable "Two-factor authentication" for "All users" (after kay enrolls his own TOTP). Allow grace period (e.g. 1 day). Apply.
5.9 β GOOD β Pi-hole (LXC 253)¶
- β DNSSEC validation enabled
- β Admin UI behind Authelia (verified middleware in pihole.yml)
- β Adlist active (StevenBlack, 83,600 domains)
- β Only DNS port 53 exposed to VLAN 10
5.10 π‘ MEDIUM β cloudflared tunnel token in Docker env¶
LXC 259's docker inspect shows TUNNEL_TOKEN=eyJh... in container Config.Env. Anyone with root on LXC 259 can read it. Acceptable for the threat model (root on LXC 259 = total compromise anyway), but Docker secret file mount would be hygiene-better.
Remediation: Optional β mount as /run/secrets/cf-tunnel-token via docker-compose secrets: section instead of env. ~5 min change.
5.11 β GOOD β PBS (VM 200) and OMV (VM 189)¶
- β
PBS web requires auth (returned
authentication failedto unauth probe) - β OMV SSH requires public key (denied unauth probe)
- β Both run on isolated VLAN 10
- β Daily PBS backup job verified (created Session 9)
6. Secrets & credentials posture¶
6.1 π HIGH β 11 on-disk credential files still in /root/*-build/¶
(Already flagged in tonight's session.) Tomorrow's cleanup:
/root/authelia-build/lxc-254-root.password
/root/gitlab-build/gitlab-root.password
/root/gitlab-build/lxc-257-root.password
/root/monitoring-build/grafana-admin.password
/root/monitoring-build/lxc-256-root.password
/root/pihole-build/lxc-253-root.password
/root/tailscale-build/lxc-255-root.password
/root/traefik-build/cloudflare.token
/root/traefik-build/lxc-251-root.password
/root/traefik-build/traefik-dashboard.password
/root/vaultwarden-build/lxc-252-root.password
Risk: Anyone with root on PVE can read these. Currently low risk (only root has the PVE box), but defense-in-depth would be to vault and delete.
Remediation: Verify each is in Vaultwarden, then rm all 11. Tracker entry already in TODO.
6.2 π HIGH β iPhone CalDAV app password not vaulted¶
The 72-char app password generated via occ user:add-app-password kay was shown in chat but not saved to Vaultwarden as a separate entry. If you ever need to revoke or rotate it, you'll need the original to find which session it backs.
Remediation: Save now as "Nextcloud - iPhone CalDAV app password" in Vaultwarden.
6.3 π‘ MEDIUM β Cloudflare API token has zone-edit scope on the apex¶
/etc/traefik/cloudflare.token has DNS edit permissions on iamkay.eu. If LXC 251 is compromised, attacker can edit DNS for the entire zone (e.g. point cloud.iamkay.eu at their own server to phish credentials).
Remediation: Cloudflare token can be scoped narrower. Today's scope is broader than necessary. Future cleanup: rotate token with only Zone:DNS:Edit for iamkay.eu + Zone:Zone:Read. Already at this level; verify periodically.
6.4 β GOOD β secrets isolation¶
- Vaultwarden admin token: argon2id-hashed in config.json
- Authelia user password: argon2id-hashed in users_database.yml
- LXC root passwords: random 32-char base64
- PostgreSQL password: in
.envmode 600, root-only readable - Cloudflare API token: 0600 traefik:traefik
7. Backup posture¶
7.1 π΄ CRITICAL β No off-site backup¶
Path D family-cloud data is now LIVE. PBS backs up daily to apple-tank datastore on the same physical machine. Single failure (fire, theft, ransomware encrypting the host) destroys both production and backup.
Remediation: Implement Cloudflare R2 or Backblaze B2 cold-storage sync. Already deferred in architecture decisions ("decision deferred to before D.1 ships data" β D.1 just shipped, decision is overdue). Pick one and configure within 1 week: - Cloudflare R2: $0.015/GB/mo storage, free egress to anywhere, S3-compatible - Backblaze B2: $0.006/GB/mo, $0.01/GB egress, simpler
For ~50 GB of family data: ~$0.30-$0.75/mo. Worth it.
7.2 β GOOD β Daily PBS job configured + restore drill passed¶
- Schedule
02:00daily - All VMs except 200 (PBS itself) backed up
- GFS retention: 3 last + 7 daily + 4 weekly + 12 monthly + 2 yearly
- Restore drill Session 8 succeeded (filesystem inspection)
7.3 π‘ MEDIUM β PBS restore drill caveat unresolved¶
Session 8 noted PBS web UI hung during restore validation; SSH to PBS started rejecting connections. Workaround: chunk-handler resource tuning on PBS VM. Not blocking β backups + restore both work, just the UI bounce is annoying.
Remediation: Bump PBS VM memory 4 GB β 6 GB; tune chunk-handler concurrency.
7.4 π‘ MEDIUM β apple-tank is removable datastore¶
When the Apple HDD is unplugged (intentional or by accident), PBS reports the datastore offline. Cron job for backups will fail silently unless email alerts are configured.
Remediation: Configure PBS notification email (already pointed at [email protected] in the job's mailto). Verify email arrives when next backup fails (test by unplugging dock).
8. Update / patch posture¶
8.1 π΄ CRITICAL β PVE 8.1.5 stale (covered in Β§1.1)¶
8.2 π HIGH β Container images may be stale¶
nextcloud:fpm-alpineβ was pulled with:latesttag, current 33.0.5.1, may have minor updatesvaultwarden/server:latestβ 1.36.0pihole/pihole:latestβ 6.6.2gitlab/gitlab-ce:latestβ 18.x current
:latest tag means next docker-compose pull && up -d brings updates. Untracked when updates land.
Remediation: Set Watchtower or Renovate for container update notifications. For now, monthly manual: cd /opt/<service> && docker-compose pull && docker-compose up -d. Set a reminder.
8.3 π HIGH β P410i firmware 3.66 still pre-update¶
Blocks BBWC enable (write-through mode active). SPP G7.1.3 + 2017.10.1 ISOs staged at /var/lib/vz/template/iso/. Flash deferred to second chassis-open. Until then: write-back disabled, data integrity not at risk but write performance suboptimal.
Remediation: Already on the queue per CLAUDE.md Section 11 #19. Bundle into next chassis-open (~July with HBA install).
8.4 π‘ MEDIUM β BIOS P67 (2011) on G7 with stale microcode¶
Spectre/Meltdown microcode missing. Modern kernel mitigations cover most cases.
Remediation: Bundle with the SPP G7.1.3 flash at next chassis-open. Lower priority than firmware.
9. Identity inventory¶
9.1 Account count per service¶
| Service | Admin | Users | Notes |
|---|---|---|---|
| PVE web | root@pam (1) |
0 | No 2FA |
| iLO | kay (1) |
0 | Password + DSA key auth |
| Vaultwarden | kay (1) via auth |
0 family yet | Admin token argon2id |
| Authelia | kay (1) |
0 family yet | TOTP enrolled |
| Nextcloud | kay admin (1) |
0 family yet | TOTP enabled (you) |
| GitLab | root, kay (2) |
0 | Neither has 2FA enforced |
| Pi-hole admin | shared admin password | β | Behind Authelia |
| PBS | shared admin | β | Default + auth |
| OMV | root + SMB users | β | SSH key only |
| Tailscale | captkay.github (1) |
+ Kay's iPhone + laptop already on tailnet |
9.2 π‘ MEDIUM β GitLab has a root user separate from kay¶
GitLab's default root admin account is still present (with the random password from build). When you add family/team members, the gitlab root is an unused attack surface.
Remediation: Either disable gitlab root after promoting kay to admin role, OR keep root for emergency-access and lock with strong + unique password (already random, fine).
10. Operational hygiene¶
10.1 π‘ MEDIUM β Empty stub dirs on tanks (deferred per CLAUDE.md Β§0)¶
r-tank/mac-store/, r-tank/proxmox/vms/, s-tank/proxmox/ct-k8s-datastore/, /windows-store/, /R-tank/, s-tank/recovery/ β cleanup pending per-target confirmation. Not a security issue, cosmetic.
10.2 β GOOD β Audit trail is preserved¶
/root/cleanup-20260606-*.logβ OMV cleanup forensic/root/config.xml.backup-pre-cleanup-*β OMV config pre-cleanup/etc/network/interfaces.backup-*β multiple network backups- PVE web UI task log β all admin actions logged
- Authelia auth log retained in SQLite
10.3 π‘ MEDIUM β No SIEM / centralized auth log analysis¶
Authelia, Nextcloud, GitLab, PVE, OMV all log auth events to local files. Loki ships container logs (Session 9), but auth log analysis isn't automated. A brute-force across multiple services wouldn't be detected today.
Remediation: Phase 3.5 monitoring stack already has Loki. Build Grafana dashboard with auth-event queries across services. Add Uptime Kuma alert on >N auth failures per minute. Defer until you want to spend an evening on it.
11. Cloudflare external surface¶
11.1 β
GOOD β Single external endpoint (cloud.iamkay.eu)¶
Only cloud.iamkay.eu exposed via Cloudflare Tunnel. Cloudflare provides:
- TLS 1.3 edge termination β
- HTTP/2 + HTTP/3 β
- DDoS protection at edge β
- Bot detection (default ON) β
- Universal SSL cert β (separate from your LE cert which is for origin)
- Country firewall (configurable, not currently restrictive) β see 11.2
11.2 π‘ MEDIUM β No geo / Access policy on cloud.iamkay.eu¶
Nextcloud is accessible from any country, any IP. Family-cloud users are 3-5 people, mostly NL β could whitelist EU only or set up Cloudflare Access for authenticated-tunnel-only access for admin endpoints.
Remediation: - For end-users (family): leave open β they may travel - For admin endpoints (if exposed externally later β they aren't today): use Cloudflare Access policies (email-based MFA + device cert) instead of direct exposure - Add Cloudflare WAF rules for known attack patterns (free tier includes managed rulesets)
11.3 β GOOD β DNS attack surface¶
Only cloud.iamkay.eu has a public DNS record (proxied through Cloudflare). All *.hm.iamkay.eu are internal only (resolved by Pi-hole). No DNS leak of internal hostnames.
12. Priority action list¶
π΄ This weekend (before next session)¶
- PVE 8.1.5 β 8.3 upgrade + reboot (~30 min including reboot)
- SSH hardening on PVE host (key-only, fail2ban, MaxAuthTries) (~15 min)
- Off-site backup decision (R2 vs B2) + config (~1 hour to spin up R2/B2 + sync job for
apple-tankweekly) - Enable PVE root 2FA (~3 min β web UI toggle + scan QR)
- Vault iPhone CalDAV app password (~2 min β copy/paste into Vaultwarden)
π This week¶
- Enforce 2FA in Nextcloud + GitLab for all admin users
- Add HSTS middleware to Traefik (global
security-headers@file, attach to all routers) - Disable Vaultwarden emergency access if not used
- Bind rpcbind + node_exporter to specific IPs
- Lock down IPMI/623 via pfSense rule (only laptop + PVE)
- Verify the 11 leftover credential files are in Vaultwarden, then nuke them
π‘ This month¶
- Enable pve-firewall with rules (after writing them carefully)
- Configure unattended-upgrades on PVE + each LXC
- Watchtower or monthly manual container update pass
- SIEM: Grafana dashboard with Loki-driven auth-event queries
- PVE root SSH key audit β replace RSA with ed25519
- PBS chunk-handler tuning
- Cloudflare WAF managed rules + geo policy review
- Stale apt files cleanup
π΅ Hygiene (opportunistic)¶
- Empty stub dir cleanup on tanks (when chassis-open or new build)
- Rotate Pi-hole admin password annually
- Cloudflare API token rotation cadence (every 6 months)
- Bring Vaultwarden + Authelia + Nextcloud client-app passwords into a rotation cadence
13. Summary scoreboard¶
| Category | Score | Trend |
|---|---|---|
| External exposure | A | Excellent β single endpoint, TLS 1.3, no port forwards |
| Application-layer auth | B+ | Authelia SSO+MFA solid, but app-level 2FA not enforced |
| TLS posture | A- | LE wildcards renewing; missing HSTS on vault |
| Network segmentation | A- | VLANs working; pfSense rules need audit |
| Host hardening (PVE) | C- | Stale, no fail2ban, no 2FA |
| iLO posture | D | TLS 1.0 only, DSA keys, firmware ceiling β accept and isolate |
| Backup posture | C | Daily local works, no off-site (urgent) |
| Patch posture | C- | 5+ months behind |
| Secrets management | B+ | Vaultwarden + hashed; 11 stash files to clean |
| Identity inventory | B | Few accounts, but 2FA not enforced where it should be |
Overall: B- β solid where you've focused (application layer, external surface), gaps where time hasn't been spent yet (host hardening, off-site backup, patches). Top 5 list at Β§12 closes the worst gaps in ~3 hours of focused work.
End of audit. Findings actionable; remediations have concrete commands. Off-site backup is the single most impactful next move β once Path D family data is real (it is, as of tonight), the data needs an off-site copy that survives single-site failure.