303 lines
9.4 KiB
Markdown
303 lines
9.4 KiB
Markdown
---
|
||
created: "2026-03-08"
|
||
type: project
|
||
status: active
|
||
deadline: ""
|
||
tags:
|
||
- 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-*"` 通配(不要求接口预先存在)
|
||
|
||
**管理命令:**
|
||
|
||
```bash
|
||
# 查看规则
|
||
nft list ruleset
|
||
|
||
# 手动封禁 IP(1小时)
|
||
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)
|
||
|
||
```bash
|
||
/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
|
||
|
||
```bash
|
||
# 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
|
||
|
||
```bash
|
||
scp -r C:/Users/yaoji/git/pve-security-scanner/vm kai@192.168.68.84:/tmp/scanner-setup
|
||
```
|
||
|
||
### Execute (in order)
|
||
|
||
```bash
|
||
# 设置环境变量
|
||
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
|
||
|
||
- [x] VM created from cloud-init template
|
||
- [x] SSH key configured (1Password, ed25519)
|
||
- [x] System hardening (01) applied
|
||
- [x] nftables firewall (02) applied - ADMIN_IPS = 192.168.68.0/24
|
||
- [x] Docker installed (Ubuntu source fix applied)
|
||
- [x] SSH hardening (03) applied - AllowUsers scanner-admin kai, MaxAuthTries 10
|
||
- [x] Security tools (04) installed
|
||
- [x] Monitoring (05) configured
|
||
- [x] Docker autostart (06) enabled - systemd greenbone-openvas.service
|
||
- [x] 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`
|
||
|
||
### Recommended Execution Order (revised)
|
||
|
||
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
|
||
```
|
||
|
||
## Related
|
||
|
||
- [[Proxmox VE]]
|
||
- [[Home Network]]
|
||
- [[Security Best Practices]]
|