feat: initial setup for PVE security scanner VM

Scripts for deploying a hardened internal network security scanner on Proxmox VE:
- PVE-level firewall and VM creation
- System hardening (sysctl, auditd, AIDE)
- nftables firewall with dynamic IP blocking
- SSH hardening with fail2ban
- Security tools (OpenVAS, Nmap, Nuclei, httpx, Nikto, testssl, NetExec)
- Monitoring, logging, and Docker autostart
This commit is contained in:
Yaojia Wang
2026-03-08 20:21:29 +01:00
commit 5e49b977ab
10 changed files with 1511 additions and 0 deletions

135
pve/firewall.sh Normal file
View File

@@ -0,0 +1,135 @@
#!/bin/bash
# =============================================================================
# PVE-Level Firewall for Security Scanner VM
# Run this on the Proxmox host
# Applies firewall rules at the hypervisor level (defense in depth)
# =============================================================================
set -euo pipefail
VMID=200
# --- Configuration (MUST be changed before running) ---
# Admin IPs allowed to access the scanner (comma-separated)
ADMIN_IPS="${SCANNER_ADMIN_IPS:-}"
# Internal subnets the scanner is allowed to reach
INTERNAL_NETS="${SCANNER_INTERNAL_NETS:-10.0.0.0/8,172.16.0.0/12,192.168.0.0/16}"
# --- Guard: require ADMIN_IPS to be set ---
if [[ -z "${ADMIN_IPS}" ]]; then
echo "[ERROR] SCANNER_ADMIN_IPS environment variable is not set." >&2
echo " Example: export SCANNER_ADMIN_IPS='192.168.68.100,192.168.68.101'" >&2
exit 1
fi
# =============================================================================
# Enable PVE firewall for the VM
# =============================================================================
echo "[+] Enabling PVE firewall for VM ${VMID}..."
# Create firewall config directory
mkdir -p "/etc/pve/firewall"
# --- VM-level firewall rules ---
cat > "/etc/pve/firewall/${VMID}.fw" << 'FWEOF'
[OPTIONS]
enable: 1
policy_in: DROP
policy_out: ACCEPT
dhcp: 0
macfilter: 0
log_level_in: info
log_level_out: warning
[IPSET admin_ips]
# Add your admin workstation IPs here
192.168.1.100
192.168.1.101
[IPSET internal_nets]
# Internal subnets the scanner can reach
10.0.0.0/8
172.16.0.0/12
192.168.0.0/16
[IPSET update_targets]
# External hosts for vulnerability database updates
# Greenbone feed servers
feed.community.greenbone.net
# Debian/Ubuntu repos
deb.debian.org
security.debian.org
# Docker Hub
registry-1.docker.io
production.cloudflare.docker.com
auth.docker.io
# GitHub (for Nuclei templates)
github.com
objects.githubusercontent.com
# =============================================================================
# INBOUND RULES - Only admin access
# =============================================================================
[RULES]
# Allow SSH from admin IPs only
IN ACCEPT -source +admin_ips -p tcp -dport 22 -log info
# Allow OpenVAS Web UI (9392) from admin IPs only
IN ACCEPT -source +admin_ips -p tcp -dport 9392 -log info
# Allow ICMP ping from internal networks
IN ACCEPT -source +internal_nets -p icmp
# Allow established/related connections back in
IN ACCEPT -match conntrack --ctstate RELATED,ESTABLISHED
# Log and drop everything else (handled by policy_in: DROP)
# =============================================================================
# OUTBOUND RULES - Restricted
# =============================================================================
# Allow DNS resolution
OUT ACCEPT -p udp -dport 53
OUT ACCEPT -p tcp -dport 53
# Allow NTP
OUT ACCEPT -p udp -dport 123
# Allow scanning to internal networks (all ports)
OUT ACCEPT -dest +internal_nets
# Allow HTTPS/HTTP only to update targets (vuln DB, packages, docker)
OUT ACCEPT -dest +update_targets -p tcp -dport 443 -log info
OUT ACCEPT -dest +update_targets -p tcp -dport 80
# Allow established connections
OUT ACCEPT -match conntrack --ctstate RELATED,ESTABLISHED
# Drop all other outbound
OUT DROP -log warning
FWEOF
echo "[+] PVE firewall rules written to /etc/pve/firewall/${VMID}.fw"
# --- Enable datacenter-level firewall if not already ---
echo "[+] Enabling datacenter-level firewall..."
pvesh set /cluster/firewall/options --enable 1 2>/dev/null || {
echo "[!] pvesh failed, checking cluster.fw manually..."
if ! grep -q "enable: 1" /etc/pve/firewall/cluster.fw 2>/dev/null; then
mkdir -p /etc/pve/firewall
if [[ -f /etc/pve/firewall/cluster.fw ]]; then
sed -i 's/^enable: 0/enable: 1/' /etc/pve/firewall/cluster.fw
else
cat > /etc/pve/firewall/cluster.fw << 'EOF'
[OPTIONS]
enable: 1
policy_in: ACCEPT
policy_out: ACCEPT
EOF
fi
fi
}
echo "[+] PVE firewall configured. Verify with: pvesh get /nodes/$(hostname)/qemu/${VMID}/firewall/rules"
echo "[!] IMPORTANT: Update admin_ips and internal_nets to match your network."