Proxmox VE Management Access Hardening
Cakupan: Proxmox VE standalone node dengan management interface langsung menghadap jaringan publik. Tujuan: membatasi akses management Proxmox tanpa mengubah atau mengganggu firewall milik VM/tenant.
1. Tujuan
Section titled “1. Tujuan”Hardening ini ditujukan untuk kondisi ketika interface management Proxmox memiliki public IP dan tidak memungkinkan dipindahkan ke management LAN/private network.
Target akhirnya:
- SSH
TCP/22hanya dapat diakses dari source administrator yang diizinkan. - Proxmox Web UI/API
TCP/8006hanya dapat diakses dari source administrator yang diizinkan. - Port management yang tidak digunakan tidak dibuka ke Internet.
- Firewall VM/tenant tetap bekerja seperti sebelumnya.
- Perubahan dapat divalidasi sebelum diterapkan.
- Tersedia automatic rollback apabila akses management terputus.
2. Variabel / Placeholder
Section titled “2. Variabel / Placeholder”Gunakan variabel agar dokumentasi tidak berisi IP produksi.
<PVE_HOSTNAME> = hostname node Proxmox<PVE_PUBLIC_IP> = public IP management Proxmox
<ADMIN_NET_1> = subnet admin utama<ADMIN_NET_2> = subnet admin backup<ADMIN_NET_3> = subnet admin backup lainnya<ADMIN_SINGLE_IP> = single trusted admin IP /32
<NON_ADMIN_TEST_IP> = IP yang dipakai untuk simulasi source non-adminContoh menggunakan documentation-only IP:
<PVE_HOSTNAME> = pve01<PVE_PUBLIC_IP> = 198.51.100.10
<ADMIN_NET_1> = 203.0.113.16/28<ADMIN_NET_2> = 198.51.100.64/29<ADMIN_NET_3> = 192.0.2.128/29<ADMIN_SINGLE_IP> = 203.0.113.250/32
<NON_ADMIN_TEST_IP> = 192.0.2.10Untuk subnet, sebaiknya gunakan network address, bukan salah satu host address.
Contoh:
203.0.113.17/28dinormalisasi menjadi:
203.0.113.16/283. Prinsip Penting: Host Firewall dan VM Firewall Terpisah
Section titled “3. Prinsip Penting: Host Firewall dan VM Firewall Terpisah”Traffic yang menuju host Proxmox melewati jalur:
Internet | vINPUT | vPVEFW-INPUT | vPVEFW-HOST-INSedangkan traffic VM melewati:
Internet / Network | v FORWARD | vPVEFW-FWBR-IN / OUT | vtap<VMID>i0-IN / OUT | v VMKarena itu hardening management host harus dibatasi pada host-side firewall.
Jangan melakukan tindakan berikut apabila firewall VM dikelola tenant/user:
iptables -Fiptables-legacy -Fpve-firewall stopDatacenter Firewall enable: 0mengubah firewall=1 pada NIC VMmengubah /etc/pve/firewall/<VMID>.fw4. Audit Status Firewall
Section titled “4. Audit Status Firewall”Periksa status firewall:
pve-firewall statusContoh output:
Status: enabled/runningJika output seperti:
Status: disabled/stoppedjangan lanjut menggunakan prosedur yang mengasumsikan firewall guest sedang aktif.
5. Periksa Konfigurasi Datacenter Firewall
Section titled “5. Periksa Konfigurasi Datacenter Firewall”cat /etc/pve/firewall/cluster.fwContoh kondisi yang terlalu terbuka:
[OPTIONS]
enable: 1
[RULES]
IN Web(ACCEPT) -log nologIN SSH(ACCEPT) -log nologIN ACCEPT -p udp -dport 8006 -log nologIN ACCEPT -p tcp -dport 8006 -log nologKonfigurasi seperti di atas berarti SSH dan 8006/tcp dapat diakses tanpa pembatasan source.
6. Periksa Host Firewall
Section titled “6. Periksa Host Firewall”cat /etc/pve/nodes/$(hostname)/host.fwContoh:
[RULES]
IN ACCEPT -p icmp -log nologRule node seperti ICMP dapat tetap dipertahankan apabila memang dibutuhkan.
7. Pastikan Node Standalone atau Cluster
Section titled “7. Pastikan Node Standalone atau Cluster”pvecm statusContoh standalone node:
Error: Corosync config '/etc/pve/corosync.conf' does not exist - is this node part of a cluster?Ini menunjukkan node tidak tergabung dalam Corosync cluster.
Pada environment cluster, desain firewall harus mempertimbangkan kebutuhan antar-node seperti migration, corosync, storage, dan sebagainya.
8. Identifikasi Management Interface
Section titled “8. Identifikasi Management Interface”ip -4 -br addrContoh:
lo UNKNOWN 127.0.0.1/8vmbr0 UP 198.51.100.10/30Dalam contoh tersebut:
vmbr0 = management/public bridge198.51.100.10 = public management IPPeriksa juga konfigurasi jaringan:
cat /etc/network/interfacesContoh:
auto vmbr0iface vmbr0 inet static address 198.51.100.10/30 gateway 198.51.100.9 bridge-ports eno1 bridge-stp off bridge-fd 09. Audit IPv6
Section titled “9. Audit IPv6”ip -6 addr show scope globalJika kosong:
root@pve01:~#berarti host saat ini tidak memiliki global IPv6 address.
Jika ada global IPv6, hardening IPv6 harus dilakukan juga karena sshd atau pveproxy mungkin listen di IPv6.
10. Audit Service yang Listen
Section titled “10. Audit Service yang Listen”ss -lntupContoh:
tcp LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",...))tcp LISTEN 0 4096 *:8006 *:* users:(("pveproxy",...))tcp LISTEN 0 4096 *:3128 *:* users:(("spiceproxy",...))Service penting Proxmox biasanya:
TCP/22 SSHTCP/8006 Web UI / APITCP/3128 SPICE proxyJika tidak ada service yang listen pada 80/443, rule Web(ACCEPT) biasanya tidak diperlukan.
8006 menggunakan TCP, sehingga UDP/8006 tidak perlu dibuka.
11. Audit Active Host Firewall
Section titled “11. Audit Active Host Firewall”iptables-legacy -S PVEFW-HOST-INContoh rule terlalu terbuka:
-A PVEFW-HOST-IN -p tcp --dport 80 -j RETURN-A PVEFW-HOST-IN -p tcp --dport 443 -j RETURN-A PVEFW-HOST-IN -p tcp --dport 22 -j RETURN-A PVEFW-HOST-IN -p udp --dport 8006 -j RETURN-A PVEFW-HOST-IN -p tcp --dport 8006 -j RETURNPada Proxmox firewall legacy backend, RETURN di chain tersebut berfungsi sebagai jalur allow kembali menuju parent chain.
12. Pastikan Traffic VM Terpisah
Section titled “12. Pastikan Traffic VM Terpisah”Periksa:
iptables-legacy -S PVEFW-FORWARDContoh:
-N PVEFW-FORWARD-A PVEFW-FORWARD -m conntrack --ctstate INVALID -j DROP-A PVEFW-FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT-A PVEFW-FORWARD -m physdev --physdev-in fwln+ --physdev-is-bridged -j PVEFW-FWBR-IN-A PVEFW-FORWARD -m physdev --physdev-out fwln+ --physdev-is-bridged -j PVEFW-FWBR-OUTSedangkan host:
iptables-legacy -S PVEFW-INPUTContoh:
-N PVEFW-INPUT-A PVEFW-INPUT -j PVEFW-HOST-INIni menjadi salah satu validasi bahwa host management dan VM forwarding berada di chain berbeda.
13. Audit local_network
Section titled “13. Audit local_network”pve-firewall localnetContoh sebelum hardening:
local hostname: pve01local IP address: 198.51.100.10network auto detect: 198.51.100.8/30using detected local_network: 198.51.100.8/30Masalahnya, seluruh /30 tersebut dapat masuk ke built-in management network Proxmox.
Cek:
ipset list PVEFW-0-management-v4Contoh:
Name: PVEFW-0-management-v4Type: hash:netNumber of entries: 1
Members:198.51.100.8/30Untuk standalone public host, lebih aman override local_network menjadi IP host sendiri.
14. Buat Custom Administrator IPSet
Section titled “14. Buat Custom Administrator IPSet”Gunakan custom IPSet:
admin_sourcesContoh:
[IPSET admin_sources]
<ADMIN_NET_1><ADMIN_NET_2><ADMIN_NET_3><ADMIN_SINGLE_IP>Contoh terisi:
[IPSET admin_sources]
203.0.113.16/28198.51.100.64/29192.0.2.128/29203.0.113.250/32Hindari memakai special IPSet bernama management untuk general allowlist apabila kebutuhan hanya SSH dan GUI, karena Proxmox menggunakan management network untuk beberapa service internal lain juga.
15. Konfigurasi Target
Section titled “15. Konfigurasi Target”Target /etc/pve/firewall/cluster.fw:
[OPTIONS]
enable: 1
[ALIASES]
local_network <PVE_PUBLIC_IP>
[IPSET admin_sources]
<ADMIN_NET_1><ADMIN_NET_2><ADMIN_NET_3><ADMIN_SINGLE_IP>
[RULES]
IN SSH(ACCEPT) -source +admin_sources -log nologIN ACCEPT -source +admin_sources -p tcp -dport 8006 -log nologContoh:
[OPTIONS]
enable: 1
[ALIASES]
local_network 198.51.100.10
[IPSET admin_sources]
203.0.113.16/28198.51.100.64/29192.0.2.128/29203.0.113.250/32
[RULES]
IN SSH(ACCEPT) -source +admin_sources -log nologIN ACCEPT -source +admin_sources -p tcp -dport 8006 -log nolog16. Jangan Disable Firewall untuk Staging
Section titled “16. Jangan Disable Firewall untuk Staging”Jika firewall VM sudah aktif, jangan melakukan:
enable: 0sebagai metode staging.
Mematikan Datacenter Firewall dapat berdampak pada enforcement firewall VM.
Sebagai gantinya buat candidate di /root:
nano /root/cluster.fw.candidateatau:
cat > /root/cluster.fw.candidate <<'EOF'...EOFFile ini belum dibaca oleh Proxmox firewall.
17. Validasi Candidate: Parse dan Compile
Section titled “17. Validasi Candidate: Parse dan Compile”Gunakan parser Proxmox langsung:
perl -MPVE::Firewall -e ' my $f = "/root/cluster.fw.candidate";
my $conf = PVE::Firewall::load_clusterfw_conf($f);
die "PARSE FAILED\n" if !$conf;
print "PARSE OK\n";
my ($ruleset, $ipset_rules, $ipset_changes, $ebtables) = PVE::Firewall::compile($conf, undef, undef, undef);
print "COMPILE OK\n";'Hasil yang diharapkan:
PARSE OKCOMPILE OKJika muncul error, jangan apply candidate.
18. Buat Baseline Firewall VM
Section titled “18. Buat Baseline Firewall VM”Fingerprint semua file firewall VM:
find /etc/pve/firewall -maxdepth 1 -type f -regextype posix-extended \ -regex '.*/[0-9]+\.fw' -print0 \ | sort -z \ | xargs -0 sha256sum \ | sha256sumContoh:
=== GUEST FW CONFIG FINGERPRINT ===aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -Fingerprint NIC VM:
for id in $(qm list | awk 'NR>1 {print $1}' | sort -n); do echo "VM $id" qm config "$id" | grep -E '^net[0-9]+:'done | sha256sumContoh:
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -Simpan kedua hash tersebut.
Sesudah hardening, hash harus tetap sama.
19. Backup Firewall Sebelum Apply
Section titled “19. Backup Firewall Sebelum Apply”TS="$(date +%Y%m%d-%H%M%S)"BACKUP_DIR="/root/pve-fw-backup-$TS"
mkdir -p "$BACKUP_DIR"
cp /etc/pve/firewall/cluster.fw \ "$BACKUP_DIR/cluster.fw"
if [ -f /etc/pve/nodes/<PVE_HOSTNAME>/host.fw ]; then cp /etc/pve/nodes/<PVE_HOSTNAME>/host.fw \ "$BACKUP_DIR/host.fw"fiContoh hasil:
/root/pve-fw-backup-YYYYMMDD-HHMMSS/├── cluster.fw└── host.fwVerifikasi:
sha256sum \ /etc/pve/firewall/cluster.fw \ "$BACKUP_DIR/cluster.fw"Hasil yang diharapkan, kedua hash sama:
111111... /etc/pve/firewall/cluster.fw111111... /root/pve-fw-backup-YYYYMMDD-HHMMSS/cluster.fw20. Buat Rollback Script
Section titled “20. Buat Rollback Script”cat > /root/pve-fw-rollback.sh <<'EOF'#!/bin/bashset -e
cp /root/pve-fw-backup-<TIMESTAMP>/cluster.fw \ /etc/pve/firewall/cluster.fw
echo "Rollback config restored at $(date)"
sleep 15
echo "=== FIREWALL STATUS ==="pve-firewall status
echoecho "=== HOST RULES ==="iptables-legacy -S PVEFW-HOST-INEOF
chmod 700 /root/pve-fw-rollback.sh21. Arm Automatic Rollback
Section titled “21. Arm Automatic Rollback”Sebelum apply:
systemd-run \ --unit=pve-fw-rollback \ --on-active=10m \ --timer-property=AccuracySec=1s \ /root/pve-fw-rollback.shContoh:
Running timer as unit: pve-fw-rollback.timerWill run service as unit: pve-fw-rollback.serviceVerifikasi:
systemctl list-timers pve-fw-rollback.timer --no-pagerContoh:
NEXT LEFT UNITMon YYYY-MM-DD HH:MM:SS 9min pve-fw-rollback.timerJangan apply sebelum rollback timer terlihat aktif.
22. Apply Candidate
Section titled “22. Apply Candidate”Apply:
cp /root/cluster.fw.candidate \ /etc/pve/firewall/cluster.fwGunakan plain cp.
Menggunakan:
cp -ake /etc/pve dapat menghasilkan warning seperti:
cp: clearing permissions for '/etc/pve/firewall/cluster.fw': Operation not permittedkarena /etc/pve menggunakan Proxmox Cluster File System (pmxcfs).
Tunggu reload:
sleep 10Kemudian:
pve-firewall statusHasil yang diharapkan:
Status: enabled/running23. Verifikasi Host Rules Sesudah Apply
Section titled “23. Verifikasi Host Rules Sesudah Apply”iptables-legacy -S PVEFW-HOST-INBagian penting expected:
-A PVEFW-HOST-IN -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT-A PVEFW-HOST-IN -m set --match-set PVEFW-0-admin_sources-v4 src -p tcp --dport 22 -j RETURN-A PVEFW-HOST-IN -m set --match-set PVEFW-0-admin_sources-v4 src -p tcp --dport 8006 -j RETURN...-A PVEFW-HOST-IN -j PVEFW-Drop-A PVEFW-HOST-IN -j DROPRule berikut sudah tidak boleh ada:
-p tcp --dport 22 -j RETURNtanpa source restriction.
Begitu juga:
-p tcp --dport 8006 -j RETURNtanpa source restriction.
24. Verifikasi Administrator IPSet
Section titled “24. Verifikasi Administrator IPSet”ipset list PVEFW-0-admin_sources-v4Contoh:
Name: PVEFW-0-admin_sources-v4Type: hash:net
Number of entries: 4
Members:203.0.113.16/28198.51.100.64/29192.0.2.128/29203.0.113.250Jumlah dan isi harus sesuai dengan daftar administrator.
25. Verifikasi local_network
Section titled “25. Verifikasi local_network”pve-firewall localnetHasil yang diharapkan:
local hostname: pve01local IP address: 198.51.100.10network auto detect: 198.51.100.8/30using user defined local_network: 198.51.100.10Perhatikan:
using user defined local_networkbukan:
using detected local_network26. Simulasi SSH dari Non-Admin
Section titled “26. Simulasi SSH dari Non-Admin”pve-firewall simulate \ --from outside \ --to host \ --source <NON_ADMIN_TEST_IP> \ --dest <PVE_PUBLIC_IP> \ --protocol tcp \ --dport 22 \ --verbose 1 | tail -n 12Contoh:
Test packet: from : outside to : host proto : tcp source : 192.0.2.10 dest : 198.51.100.10 dport : 22
ACTION: DROPHasil yang diharapkan:
ACTION: DROP27. Simulasi SSH dari Admin
Section titled “27. Simulasi SSH dari Admin”pve-firewall simulate \ --from outside \ --to host \ --source <ADMIN_SINGLE_IP> \ --dest <PVE_PUBLIC_IP> \ --protocol tcp \ --dport 22 \ --verbose 1 | tail -n 12Contoh output:
Test packet: from : outside to : host proto : tcp source : 203.0.113.250 dest : 198.51.100.10 dport : 22
ACTION: ACCEPTHasil yang diharapkan:
ACTION: ACCEPT28. Simulasi GUI dari Non-Admin
Section titled “28. Simulasi GUI dari Non-Admin”pve-firewall simulate \ --from outside \ --to host \ --source <NON_ADMIN_TEST_IP> \ --dest <PVE_PUBLIC_IP> \ --protocol tcp \ --dport 8006 \ --verbose 1 | tail -n 12Hasil yang diharapkan:
Test packet: from : outside to : host proto : tcp source : 192.0.2.10 dest : 198.51.100.10 dport : 8006
ACTION: DROP29. Simulasi GUI dari Admin
Section titled “29. Simulasi GUI dari Admin”pve-firewall simulate \ --from outside \ --to host \ --source <ADMIN_SINGLE_IP> \ --dest <PVE_PUBLIC_IP> \ --protocol tcp \ --dport 8006 \ --verbose 1 | tail -n 12Hasil yang diharapkan:
Test packet: from : outside to : host proto : tcp source : 203.0.113.250 dest : 198.51.100.10 dport : 8006
ACTION: ACCEPT30. Test Fresh GUI Connection
Section titled “30. Test Fresh GUI Connection”Jangan hanya mengandalkan session browser yang sudah terbuka.
Koneksi lama dapat tetap hidup karena rule:
RELATED,ESTABLISHEDBuka browser incognito/private baru lalu akses:
https://<PVE_PUBLIC_IP>:8006Setelah berhasil, cek:
ss -tnp state established '( sport = :8006 )'Contoh:
Recv-Q Send-Q Local Address:Port Peer Address:Port0 0 198.51.100.10:8006 203.0.113.250:451230 0 198.51.100.10:8006 203.0.113.25:51290Pastikan Peer Address berasal dari salah satu <ADMIN_NET_X>.
31. Verifikasi Firewall VM Tidak Berubah
Section titled “31. Verifikasi Firewall VM Tidak Berubah”Jalankan ulang fingerprint firewall VM:
find /etc/pve/firewall -maxdepth 1 -type f -regextype posix-extended \ -regex '.*/[0-9]+\.fw' -print0 \ | sort -z \ | xargs -0 sha256sum \ | sha256sumContoh sebelum:
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -Contoh sesudah:
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -Harus sama.
Kemudian NIC:
for id in $(qm list | awk 'NR>1 {print $1}' | sort -n); do echo "VM $id" qm config "$id" | grep -E '^net[0-9]+:'done | sha256sumSebelum:
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -Sesudah:
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -Jika hash berubah, investigasi sebelum cancel rollback.
32. Cancel Automatic Rollback
Section titled “32. Cancel Automatic Rollback”Rollback baru boleh dicancel apabila seluruh checklist ini lolos:
[OK] Firewall enabled/running[OK] Non-admin -> TCP/22 = DROP[OK] Admin -> TCP/22 = ACCEPT[OK] Non-admin -> TCP/8006 = DROP[OK] Admin -> TCP/8006 = ACCEPT[OK] Fresh browser connection berhasil[OK] Guest firewall fingerprint sama[OK] Guest NIC fingerprint samaStop timer:
systemctl stop pve-fw-rollback.timerVerifikasi:
systemctl list-timers --all --no-pager \ | grep 'pve-fw-rollback' \ || echo 'No active rollback timers'Hasil yang diharapkan:
No active rollback timers33. Verifikasi Konfigurasi Akhir
Section titled “33. Verifikasi Konfigurasi Akhir”Bandingkan candidate dengan live config:
sha256sum \ /etc/pve/firewall/cluster.fw \ /root/cluster.fw.candidateHasil yang diharapkan:
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc /etc/pve/firewall/cluster.fwcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc /root/cluster.fw.candidateHash harus identik.
34. Bersihkan Transient Rollback Units
Section titled “34. Bersihkan Transient Rollback Units”Opsional:
systemctl reset-failed \ pve-fw-rollback.service \ pve-fw-rollback-apply.service \ pve-fw-rollback-verify.service \ pve-fw-rollback-finalcheck.service 2>/dev/null || trueKemudian:
systemctl list-units --all 'pve-fw-rollback*' --no-pagerContoh hasil bersih:
UNIT LOAD ACTIVE SUB DESCRIPTION
0 loaded units listed.Backup sebaiknya jangan langsung dihapus.
35. Kondisi Akhir di Proxmox Web GUI
Section titled “35. Kondisi Akhir di Proxmox Web GUI”Pada:
Datacenter└── Firewall └── Rulesrule yang terlihat cukup:
| On | Type | Action | Macro | Protocol | Source | D.Port |
|---|---|---|---|---|---|---|
| ✓ | in | ACCEPT | SSH | +admin_sources | ||
| ✓ | in | ACCEPT | tcp | +admin_sources | 8006 |
Sedangkan:
Datacenter└── Firewall └── IPSetberisi:
admin_sources├── <ADMIN_NET_1>├── <ADMIN_NET_2>├── <ADMIN_NET_3>└── <ADMIN_SINGLE_IP>Dan:
Datacenter└── Firewall └── Aliasmemiliki:
local_network = <PVE_PUBLIC_IP>36. SSH Hardening Lanjutan
Section titled “36. SSH Hardening Lanjutan”Setelah firewall allowlist stabil, audit SSH:
sshd -T | grep -E \'^(permitrootlogin|passwordauthentication|pubkeyauthentication|maxauthtries) 'Contoh kondisi awal:
maxauthtries 6permitrootlogin yespubkeyauthentication yespasswordauthentication yesTarget jangka panjang dapat berupa:
pubkeyauthentication yespasswordauthentication noUntuk PermitRootLogin, sesuaikan dengan operational model.
Jangan disable password authentication sebelum semua lokasi administrator telah diuji menggunakan public key.
37. Arsitektur Akhir
Section titled “37. Arsitektur Akhir” INTERNET | +--------------+--------------+ | | NON-ADMIN ADMIN | admin_sources | | TCP/22 DROP TCP/22 ACCEPT TCP/8006 DROP TCP/8006 ACCEPT | | +--------------+--------------+ | v +-------------+ | PVE HOST | | public mgmt | +-------------+ | +--------------+--------------+ | | v v HOST INPUT VM FORWARD PVEFW-HOST-IN PVEFW-FWBR-* | | | v admin-only access tap<VMID> | v VM Firewall | Tenant Managed | DO NOT MODIFYOperational Rule
Section titled “Operational Rule”Harden the Proxmox host without treating tenant VM firewall rules as part of the host hardening scope.
Management access harus bersifat explicit allowlist, sedangkan konfigurasi firewall VM/tenant harus dianggap sebagai domain terpisah yang tidak diubah selama proses hardening host.