Files
knowledge-base/2 - Projects/PVE Security Scanner.md
Yaojia Wang ad79665527 Sync
2026-03-14 20:23:32 +01:00

9.4 KiB
Raw Permalink Blame History

created, type, status, deadline, tags
created type status deadline tags
2026-03-08 project active
homelab
security
proxmox
networking

PVE Security Scanner

Goal

在 Proxmox VE 上搭建一台专用的内网安全扫描 VM用于定期进行网络安全评估、漏洞扫描和合规检查。

Architecture

+------------------+
|   PVE Host       |
|  +--------------+|     PVE Firewall (Layer 1)
|  | Scanner VM   ||     - IN: only admin IPs -> SSH/9392
|  | Ubuntu 24.04 ||     - OUT: internal nets + update_targets IPSET
|  | 4C / 8G / 80G||
|  +--------------+|
|        |         |
+--------|--------+
         | vmbr0 (bridge)
         |
   ======|==================== Internal Network (192.168.68.0/24)
   |     |     |     |
  [Host] [Host] [Host] [Switch/Router]

VM Specs

Resource Value
Hostname network-scanner
IP 192.168.68.84
OS Ubuntu 24.04 (cloud-init)
Kernel 6.8.0-101-generic
CPU 4 cores (host type)
RAM 8 GB
Disk 80 GB
Network vmbr0 bridge, 192.168.68.0/24
SSH User kai (1Password managed key)
Admin User scanner-admin

Security Architecture (Defense in Depth)

Layer 1: PVE Firewall (Hypervisor)

在 Proxmox 层面限制 VM 网络访问,即使 VM 被攻陷也无法绕过。

Direction Rule Purpose
IN Admin IPs -> TCP 22 SSH 管理
IN Admin IPs -> TCP 443, 9392 OpenVAS Web UI
IN Internal nets -> ICMP Ping
OUT -> Internal nets (all) 扫描内网
OUT -> update_targets IPSET TCP 80/443 漏洞库更新、包管理
OUT -> UDP 53/123 DNS / NTP
Default DROP 其他全部拒绝

Config: /etc/pve/firewall/200.fw

Admin IPs 默认 192.168.68.0/24(整个内网段),可通过 SCANNER_ADMIN_IPS 环境变量覆盖。

Layer 2: nftables (VM Internal)

VM 内部使用 nftables 做第二层防护,包含动态封禁功能。

Key features:

  • blocked_ips set: 动态 IP 封禁(带超时自动解封)
  • ssh_bruteforce set: SSH 暴力破解自动检测3次/分钟触发15分钟封禁
  • Output policy DROP: 出站默认拒绝,仅白名单放行
  • 所有 DROP 事件记录日志
  • Docker 接口使用 iifname "docker*" / iifname "br-*" 通配(不要求接口预先存在)

管理命令:

# 查看规则
nft list ruleset

# 手动封禁 IP1小时
nft add element inet firewall blocked_ips { 1.2.3.4 timeout 1h }

# 查看被封禁的 IP
nft list set inet firewall blocked_ips

# 重载规则
systemctl restart nftables

Config: /etc/nftables.conf

Layer 3: SSH Hardening

Setting Value
Authentication Public key only (1Password)
Root login Disabled
Max auth tries 10
Ciphers chacha20-poly1305, aes256-gcm
KEX sntrup761x25519, curve25519
Fail2ban 3 failures -> 1h ban (nftables backend)
AllowUsers scanner-admin kai
Forwarding DisableForwarding yes
Banner /etc/issue.net

Config: /etc/ssh/sshd_config.d/99-scanner-hardening.conf

Layer 4: System Hardening

Kernel (sysctl):

  • IP forwarding disabled
  • ICMP redirects ignored
  • SYN flood protection (syncookies)
  • Reverse path filtering (anti-spoofing)
  • Martian packet logging
  • ASLR enabled, ptrace restricted

Auditing:

  • auditd: 监控 /etc, auth, sudo, network, cron, scanner config 变更
  • AIDE: 文件完整性检查 (daily 3am)
  • Lynis: 安全审计 (weekly Sunday 2am)
  • Core dumps disabled

Config: /etc/sysctl.d/99-security-scanner.conf, /etc/audit/rules.d/scanner-audit.rules

Installed Tools

Tool Purpose Usage
OpenVAS/Greenbone 全面漏洞管理平台 Web UI https://192.168.68.84 (nginx -> gsad)
Nmap 网络发现、端口扫描 nmap -sV --script=safe <target>
Nuclei 快速漏洞扫描 (模板驱动, SHA256 校验) nuclei -u <url>
httpx HTTP 探测、服务识别 (SHA256 校验) httpx -l hosts.txt
Nikto Web 服务器扫描 nikto -h <url>
testssl.sh TLS/SSL 安全检测 testssl <host:port>
NetExec SMB/RDP/WinRM 评估 netexec smb <target>

Scanning Workflow

Quick Scan (Automated)

/opt/scans/scripts/quick-scan.sh 192.168.68.0/24

Steps:

  1. Host discovery (nmap -sn)
  2. Port scan top 1000 (nmap -sV --script=safe)
  3. HTTP service detection (httpx)
  4. Vulnerability scan (nuclei medium/high/critical)

Results saved to /opt/scans/results/<timestamp>/

Full Scan (OpenVAS)

  1. Start containers: cd /opt/greenbone && docker compose up -d
  2. Wait for feed sync (first time: 30-60 min)
  3. Access Web UI: https://192.168.68.84 (self-signed cert, accept warning)
  4. Create Target -> Create Task -> Run Scan
  5. Export report (PDF/CSV)

Targeted Scans

# TLS/SSL audit
testssl 192.168.68.10:443

# Web server scan
nikto -h https://192.168.68.10

# SMB assessment
netexec smb 192.168.68.0/24

# Full port scan single host
nmap -sV --script=safe -p- -T4 192.168.68.10

Monitoring

Check Schedule Tool
Disk usage Every 6h /opt/scans/scripts/check-disk.sh
OpenVAS health Every 30min /opt/scans/scripts/check-openvas.sh
File integrity Daily 3am AIDE
Security audit Weekly Sun 2am Lynis
Old results cleanup Weekly Sun 4am find (maxdepth 1, >90 days, logged)
Nuclei templates Weekly Mon 5am nuclei -update-templates
Daily summary Daily Logwatch

Logs: /var/log/scanner/

Deployment

Method: Cloud-Init Template Clone

  1. PVE Web UI -> 选中 Cloud-Init 模板 -> 右键 Clone (Full Clone)
  2. Cloud-Init 标签设置: user kai, SSH key (1Password), IP 192.168.68.84/24
  3. Hardware: 4C / 8G / 80G disk

Copy Scripts to VM

scp -r C:/Users/yaoji/git/pve-security-scanner/vm kai@192.168.68.84:/tmp/scanner-setup

Execute (in order)

# 设置环境变量
export SCANNER_ADMIN_IPS='192.168.68.0/24'
export SCANNER_DNS_SERVERS='192.168.68.1'

# 一键执行(或逐个执行)
sudo -E bash /tmp/scanner-setup/setup.sh

# 或逐个:
sudo -E bash /tmp/scanner-setup/01-system-harden.sh
sudo -E bash /tmp/scanner-setup/02-firewall.sh
sudo -E bash /tmp/scanner-setup/04-install-tools.sh   # Docker 先装
sudo usermod -aG docker scanner-admin                  # 补加 docker 组
sudo -E bash /tmp/scanner-setup/03-ssh-harden.sh       # 再跑 SSH
sudo -E bash /tmp/scanner-setup/05-monitoring.sh
sudo -E bash /tmp/scanner-setup/06-docker-autostart.sh

# OpenVAS 密码
cd /opt/greenbone && docker compose up -d
docker compose exec -u gvmd gvmd gvmd --user=admin --new-password=<PASSWORD>

# 重启
sudo shutdown -r now

Post-Deployment Checklist

  • VM created from cloud-init template
  • SSH key configured (1Password, ed25519)
  • System hardening (01) applied
  • nftables firewall (02) applied - ADMIN_IPS = 192.168.68.0/24
  • Docker installed (Ubuntu source fix applied)
  • SSH hardening (03) applied - AllowUsers scanner-admin kai, MaxAuthTries 10
  • Security tools (04) installed
  • Monitoring (05) configured
  • Docker autostart (06) enabled - systemd greenbone-openvas.service
  • OpenVAS Web UI accessible - https://192.168.68.84 (nginx port 443+9392)
  • Feed sync complete (in progress, ~30-60 min)
  • First quick scan completed
  • lynis audit system score verified

Deployment Notes

Issues Encountered

  1. Docker source wrong distro: 脚本原写 Debian 源,实际系统是 Ubuntu 24.04 (noble)。已修复为自动检测 ${ID} (debian/ubuntu)
  2. nftables rate limit 不能用 define: define SSH_RATE_LIMIT = 5/minute 语法错误nftables 不支持 define 变量做 rate limit改为内联值
  3. iif "docker0" 要求接口已存在: Docker 未安装时 docker0 不存在导致报错,改为 iifname "docker*" 通配
  4. 03-ssh-harden.sh docker 组不存在: 需先运行 04 安装 Docker再运行 03 创建用户
  5. SSH sshd.service not found: Ubuntu 用 ssh.service,已修复为 ssh 2>/dev/null || sshd
  6. AllowUsers 只有 scanner-admin: cloud-init 用户 kai 被拒绝登录,已加入 AllowUsers
  7. MaxAuthTries 3 太小: 1Password 管理多个 key 逐个尝试会超限,改为 10
  8. ADMIN_IPS 设成 VM 自身 IP: 导致工作站无法 SSH改为整网段 192.168.68.0/24
  9. Greenbone 镜像名变更: greenbone/xxx 已迁移到 registry.community.greenbone.net/community/xxx,架构改为 nginx + gsad + gsa 分离
  10. nginx 9392 端口重定向到 443: 需同时暴露 443 端口docker-compose 已加 0.0.0.0:443:443

01 -> 02 -> 04 (Docker) -> 03 (SSH, needs docker group) -> 05 -> 06

Scripts Location

Repo: https://git.colacoder.com/kai/pve-security-scanner

pve-security-scanner/
├── pve/
│   ├── create-vm.sh          # VM creation (idempotent)
│   └── firewall.sh           # PVE-level firewall (env var guard)
├── vm/
│   ├── setup.sh              # One-click ordered execution
│   ├── 01-system-harden.sh   # OS hardening
│   ├── 02-firewall.sh        # nftables rules
│   ├── 03-ssh-harden.sh      # SSH + fail2ban
│   ├── 04-install-tools.sh   # Security tools (auto-detect distro)
│   ├── 05-monitoring.sh      # Logging + cron
│   └── 06-docker-autostart.sh # OpenVAS systemd service
└── README.md