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
136 lines
4.1 KiB
Bash
136 lines
4.1 KiB
Bash
#!/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."
|