SirGCMHatoRey/UniSOC-Sentinel
GitHub: SirGCMHatoRey/UniSOC-Sentinel
专为 UniFi 网络构建的生产级容器化 SIEM 平台,提供日志采集、解析、威胁检测、告警与可视化等全链路安全监控能力。
Stars: 0 | Forks: 0
# UniSOC Sentinel — 企业级 UniFi SIEM 平台
一个专为 UniFi 网络构建的生产级安全信息和事件管理 (SIEM) 平台。UniSOC Sentinel 从 UniFi 硬件采集 syslog 数据,对事件进行标准化和丰富,通过可配置的告警规则检测威胁,并通过统一的仪表板展示所有信息。
## 目录
1. [概述](#overview)
2. [架构](#architecture)
3. [前置条件](#prerequisites)
4. [快速开始](#quick-start)
5. [UniFi 配置](#unifi-configuration)
6. [配置参考](#configuration-reference)
7. [TLS 选项](#tls-options)
8. [备份与恢复](#backup-and-restore)
9. [监控](#monitoring)
10. [故障排除](#troubleshooting)
11. [安全说明](#security-notes)
## 概述
UniSOC Sentinel 是一个自托管的、容器化的 SIEM 技术栈,由专门构建的微服务组成。每个服务具有单一职责,并通过定义好的 Redis streams 和 REST API 进行通信。整个技术栈通过 Docker Compose 运行,旨在部署在单台主机上(最低要求 4 GB RAM,2 vCPUs),并支持可选的多节点扩展。
**核心功能:**
- 通过 UDP 514 端口实时从 UniFi 控制器和设备采集 syslog
- 采用 ECS 标准化的日志解析,支持 GeoIP 丰富化与威胁情报查询
- 基于规则的告警,支持去重、限流和邮件推送
- 由 OpenSearch 支持的全文日志搜索
- 用于仪表板集成的 REST API 和实时 WebSocket 数据流
- 用于操作可视化的 Prometheus 指标和 Grafana 仪表板
- 基于 JWT 认证的多角色用户管理(admin / analyst / viewer)
## 架构
```
┌─────────────────────────────────────────────────────────────────────┐
│ UniFi Network │
│ Controller / APs / Switches / Gateways │
└───────────────────────────┬─────────────────────────────────────────┘
│ UDP 514 (syslog)
▼
┌─────────────────────────────────────────────────────────────────────┐
│ syslog-ingestion │
│ Receives raw syslog frames → publishes to Redis stream │
│ Stream: siem:raw_logs │
└───────────────────────────┬─────────────────────────────────────────┘
│ Redis XADD
▼
┌─────────────────────────────────────────────────────────────────────┐
│ parser-pipeline │
│ Reads siem:raw_logs (consumer group: siem-parsers) │
│ Normalises → ECS fields │
│ Enriches → GeoIP, threat-intel feeds │
│ Indexes → OpenSearch (siem-logs-YYYY.MM.DD) │
│ Publishes → siem:parsed_logs │
└──────────────┬────────────────────────────┬────────────────────────┘
│ Redis XADD │ HTTP bulk index
▼ ▼
┌──────────────────────────┐ ┌──────────────────────────────────────┐
│ alerting-engine │ │ OpenSearch │
│ Reads siem:parsed_logs │ │ Indices: siem-logs-*, siem-alerts │
│ (group: siem-alerting) │ │ Full-text search + aggregations │
│ Evaluates alert rules │ └──────────────────┬───────────────────┘
│ Deduplicates via Redis │ │ REST /api/v1/
│ Stores → PostgreSQL │ │
│ Publishes alert events │ │
│ → siem:alert_notific. │ │
└────────┬─────────────────┘ │
│ Redis PUBLISH │
▼ │
┌──────────────────────────┐ │
│ email-notifier │ │
│ Subscribes to │ │
│ siem:alert_notifications│ │
│ Sends SMTP emails │ │
└──────────────────────────┘ │
│
┌─────────────────────────────────────────────────▼───────────────────┐
│ siem-core (FastAPI) │
│ REST API prefix: /api/v1/ │
│ WebSocket: /ws/live (pub: siem:live_stream) │
│ Auth: JWT + API keys DB: PostgreSQL │
└───────────────────────────┬─────────────────────────────────────────┘
│ HTTP upstream
▼
┌─────────────────────────────────────────────────────────────────────┐
│ reverse-proxy (nginx) │
│ /api/ → siem-core:8000 /ws/ → siem-core:8000 │
│ /grafana/ → grafana:3000 / → dashboard-ui:3000 │
│ TLS termination (self-signed or Let's Encrypt) │
└──────────┬───────────────────────────────────────────────────────┬──┘
│ TCP 80 / 443 │
▼ ▼
Browser (Dashboard) Grafana UI
```
### 数据存储
| 存储 | 用途 | 默认端口 |
|-------------|------------------------------------------|:------------:|
| Redis | 日志流,发布/订阅,去重缓存 | 6379 |
| PostgreSQL | 用户、会话、API 密钥、告警、审计 | 5432 |
| OpenSearch | 日志索引 (siem-logs-*),告警索引 | 9200 |
### 监控技术栈
| 服务 | 角色 | 默认端口 |
|------------|-----------------------------------|:------------:|
| Prometheus | 从所有服务抓取 /metrics | 9090 |
| Grafana | 通过 /grafana/ 提供仪表板 | 3000 (内部) |
## 前置条件
| 要求 | 最低配置 | 备注 |
|---|---|---|
| Docker Engine | 24.0+ | `docker --version` |
| Docker Compose Plugin | v2.20+ | `docker compose version` |
| RAM | 4 GB | 生产环境建议 8 GB |
| CPU | 2 vCPUs | 建议 4+ |
| 磁盘 | 20 GB | 用于日志、指标和备份 |
| OS | Linux (amd64) | 建议 Ubuntu 22.04 LTS 或 Debian 12 |
| `openssl` | 任意版本 | 生成密钥所需 |
| `curl` / `bash` | 任意版本 | 运行脚本所需 |
## 快速开始
### 1. 克隆代码库
```
git clone https://github.com/your-org/unisoc-sentinel.git
cd unisoc-sentinel
```
### 2. 生成密钥
```
bash scripts/generate-secrets.sh
# 或
make generate-secrets
```
这会创建 `./secrets/` 目录,其中包含:
- `postgres_password` — PostgreSQL siem 用户密码
- `redis_password` — Redis 认证密码
- `opensearch_password` — OpenSearch admin 密码
- `smtp_password` — SMTP 认证(占位符,需手动修改)
- `jwt_secret` — 64 字节 JWT 签名密钥
### 3. 配置环境
```
# .env 已由 generate-secrets.sh 从 .env.example 复制
# 编辑与你的部署相关的值:
nano .env
```
至少需要检查并调整以下内容:
| 变量 | 需要执行的操作 |
|---|---|
| `DOMAIN` | 设置为服务器的 FQDN 或 IP |
| `TLS_MODE` | `self-signed`(测试环境)或 `letsencrypt`(生产环境) |
| `LETSENCRYPT_EMAIL` | 当 `TLS_MODE=letsencrypt` 时必填 |
| `OPENSEARCH_INITIAL_ADMIN_PASSWORD` | 修改默认值 |
| `SMTP_HOST`, `SMTP_USER`, `SMTP_PORT` | 用于邮件发送的设置 |
| `ALERT_RECIPIENTS` | 以逗号分隔的通知接收者 |
| `GRAFANA_ADMIN_PASSWORD` | 修改默认值 |
### 4. 构建并启动技术栈
```
# 构建自定义镜像并启动所有服务:
make build
make up
# 查看启动进度:
make logs
```
首次启动时,OpenSearch 最多可能需要 2 分钟才能变为健康状态。
### 5. 验证技术栈
```
make ps
```
所有服务应显示为 `healthy` 或 `running`。然后打开:
- 仪表板:`https:///`
- Grafana:`https:///grafana/`
- API 健康状态:`https:///api/v1/health`
默认管理员凭据:`admin` / `ChangeMe123!`
**请立即通过仪表板或 API 修改此密码。**
## UniFi 配置
将你的 UniFi 设备指向运行 UniSOC Sentinel 的主机以发送 syslog。
### UniFi Network Application (Controller)
1. 登录到 UniFi Network Application。
2. 导航至 **Settings → System → Advanced**。
3. 启用 **Remote Syslog Server**。
4. 将 **Server IP** 设置为 UniSOC Sentinel 主机的 IP 地址。
5. 将 **Port** 设置为 `514`。
6. 将 **Protocol** 设置为 `UDP`。
7. 点击 **Apply Changes**。
### 旧版 UniFi Security Gateway (USG)
通过 SSH 登录 USG 并运行:
```
configure
set system syslog host facility all level info
commit
save
exit
```
### UniFi Dream Machine (UDM / UDM-Pro / UDM-SE)
在 UniFi OS 设置中:
1. 导航至 **Console Settings → Notifications → Remote Syslog**。
2. 输入主机 IP 和端口 `514`。
### 防火墙注意事项
确保 UniFi 设备与主机之间的 UDP 514 端口已开放:
```
# Linux 示例 (ufw):
sudo ufw allow 514/udp comment "UniSOC Sentinel syslog"
```
## 配置参考
所有配置均通过 `.env` 文件完成。有关每个变量的完整文档,请参阅 `.env.example`。
### 关键变量
| 变量 | 默认值 | 描述 |
|---|---|---|
| `DOMAIN` | `localhost` | 用于 TLS 证书和 nginx 虚拟主机的公共 FQDN |
| `TLS_MODE` | `self-signed` | 证书模式:`self-signed` 或 `letsencrypt` |
| `OPENSEARCH_INITIAL_ADMIN_PASSWORD` | `ChangeMe_1234!` | OpenSearch admin 密码 |
| `LOG_LEVEL` | `INFO` | Python 服务的全局日志详细级别 |
| `CORS_ORIGINS` | `http://localhost,...` | API 允许的 CORS 源 |
### 扩展变量
| 变量 | 默认值 | 描述 |
|---|---|---|
| `SYSLOG_WORKERS` | `4` | syslog 采集服务中的异步 worker |
| `SYSLOG_BUFFER_SIZE` | `10000` | 传入数据帧的内存队列深度 |
| `PARSER_WORKERS` | `2` | 并发解析器协程 |
| `PARSER_BATCH_SIZE` | `100` | Redis XREADGROUP 批量大小 |
| `SIEM_CORE_WORKERS` | `4` | Uvicorn worker 进程 |
### 告警规则
告警规则定义在 `config/alert-rules/alert-rules.yml` 中。该文件以只读方式挂载到 `alerting-engine` 容器中。修改后,请重启告警引擎:
```
make restart SERVICE=alerting-engine
```
有关完整的规则 schema,请参阅 `config/alert-rules/alert-rules.yml`。
### 威胁情报源
订阅源配置位于 `config/threat-intel/feeds.yml`。解析器流水线会根据 `update_interval_hours` 自动刷新订阅源。
## TLS 选项
### 自签名(开发 / 实验)
在 `.env` 中设置 `TLS_MODE=self-signed`。`tls-manager` 服务会在首次启动时生成自签名证书,并将其存储在 `tls-certs` 卷中。浏览器会显示安全警告 —— 添加例外或信任该 CA。
### Let's Encrypt(生产)
要求:
- `DOMAIN` 必须公开解析为主机的 IP
- 端口 `80` 必须可从互联网访问(用于 ACME HTTP-01 验证)
- 在 `LETSENCRYPT_EMAIL` 中填写有效的电子邮箱地址
在 `.env` 中设置 `TLS_MODE=letsencrypt` 并启动技术栈。`tls-manager` 服务将自动获取并缓存证书。
证书续期由 `tls-manager` 服务在每次重启时处理。要手动触发续期:
```
docker compose restart tls-manager
docker compose restart reverse-proxy
```
## 备份与恢复
### 创建备份
```
make backup
```
备份内容:
- PostgreSQL 数据库(pg_dump,已压缩)
- OpenSearch 数据卷
- Redis RDB 快照
备份文件将写入 `./backups/YYYY-MM-DD_HH-MM-SS/` 目录,并保留最近七次的备份(更早的备份将被自动删除)。
### 计划自动备份
```
# 每天 02:00 运行备份
0 2 * * * cd /opt/unisoc-sentinel && bash scripts/backup.sh >> /var/log/sentinel-backup.log 2>&1
```
### 从备份恢复
```
bash scripts/restore.sh ./backups/2026-05-21_02-00-00
```
在覆盖任何数据之前,系统会提示您进行确认。
## 监控
### Prometheus
Prometheus 配置为从每个服务抓取 `/metrics`。
配置文件:`services/monitoring/prometheus/prometheus.yml`
直接访问 Prometheus(仅限内部访问,不公开暴露):
```
docker compose exec prometheus wget -qO- http://localhost:9090/api/v1/targets
```
### Grafana
通过 `https:///grafana/` 访问 Grafana。
默认凭据:通过 `GRAFANA_ADMIN_USER` / `GRAFANA_ADMIN_PASSWORD` 配置。
预构建的仪表板从 `services/monitoring/grafana/dashboards/` 加载。
数据源从 `services/monitoring/grafana/provisioning/` 配置。
## 故障排除
### 容器未启动 / 不健康
```
# 查看特定服务的日志:
make logs SERVICE=opensearch
# 检查最后 100 行:
docker compose logs --tail=100 opensearch
```
### OpenSearch 变为健康状态的时间过长
首次启动时,OpenSearch 生成 TLS 证书并初始化集群可能需要 60–90 秒。在诊断之前,请等待 `start_period` 结束。检查日志:
```
make logs SERVICE=opensearch
```
如果 `bootstrap.memory_lock` 失败,请增加主机的 `vm.max_map_count`:
```
sudo sysctl -w vm.max_map_count=262144
echo "vm.max_map_count=262144" | sudo tee -a /etc/sysctl.conf
```
### OpenSearch 中没有出现日志
1. 确认你的 UniFi 设备正在通过 UDP 514 向主机 IP 发送 syslog。
2. 验证 `syslog-ingestion` 是否健康:`make ps`。
3. 检查 Redis 连接情况:`make logs SERVICE=syslog-ingestion`。
4. 验证 `parser-pipeline` 是否正在消费:`make logs SERVICE=parser-pipeline`。
### 告警未发送
1. 检查 `alerting-engine` 日志:`make logs SERVICE=alerting-engine`。
2. 检查 `email-notifier` 日志:`make logs SERVICE=email-notifier`。
3. 验证 SMTP 凭据:`cat secrets/smtp_password`。
4. 测试 SMTP 连接:
```
docker compose exec email-notifier python -c \
"import smtplib; s = smtplib.SMTP('$SMTP_HOST', $SMTP_PORT); print(s.ehlo())"
```
### 重置一切并重新开始
```
make reset # WARNING: destroys all data
make generate-secrets
make build
make up
```
## 安全说明
1. **密钥** — 所有密码和密钥都存储在 `./secrets/` 文件中,绝不会存储在环境变量或 docker-compose.yml 中。`secrets/` 目录已通过 `.gitignore` 排除在 git 之外。权限设置为 `600`。
2. **非 root 容器** — 所有自定义服务均以 UID 1000(或相应的服务 UID)运行。通过 `no-new-privileges:true` 阻止权限提升。
3. **只读文件系统** — 在可行的情况下,容器以 `read_only: true` 运行,并将可写的 `/tmp` 挂载为 tmpfs。
4. **丢弃 Capabilities** — 自定义服务会丢弃所有的 Linux capabilities,仅重新添加严格需要的权限(例如 syslog 监听 514 端口所需的 `NET_BIND_SERVICE`)。
5. **网络隔离** — 所有服务均在内部的 `siem-internal` Docker 网络上通信。只有 `reverse-proxy` 和 `grafana` 连接到面向公网的 `siem-public` 网络。
6. **默认密码** — 在连接到生产网络之前,请修改 `OPENSEARCH_INITIAL_ADMIN_PASSWORD`、`GRAFANA_ADMIN_PASSWORD` 以及默认的 `admin` 数据库用户密码 (`ChangeMe123!`)。
7. **TLS** — 在生产环境中使用 `TLS_MODE=letsencrypt`。自签名模式仅适用于内部实验环境。
8. **审计日志** — 所有的 API 操作都会连同用户身份、IP 地址和时间戳写入 PostgreSQL 的 `audit_log` 表中。
标签:Docker Compose, UniFi, 安全运营, 扫描框架, 搜索引擎查询, 测试用例, 版权保护, 网络安全, 网络测绘, 自定义请求头, 逆向工具, 隐私保护