kenlacroix/palisade
GitHub: kenlacroix/palisade
一款攻击面监控工具,通过仅在主机本地运行扫描的拉取式 agent 与 FastAPI 控制面,为自托管和 AI 基础设施提供保护数据隐私的 CVE 检测与安全态势管理。
Stars: 0 | Forks: 0
# Palisade
**针对自托管和 AI 基础设施服务的攻击面监控。**
[](https://github.com/kenlacroix/palisade/actions/workflows/ci.yml)
[](https://github.com/kenlacroix/palisade/releases)
[](agent/)
[](control-plane/)
[](web/)
[](LICENSE)
**[trypalisade.dev](https://trypalisade.dev)** · [在线演示](https://app.trypalisade.dev) · [快速开始](#quickstart-zero-infra-sqlite) · [架构](#architecture) · [设计决策](docs/design-decisions.md)

**仅拉取** 的 agent 注册一次,在本地发现监听服务,并在本地运行 CVE 检测 —— **只有标准化后的 findings 会离开主机**。
FastAPI control plane 提供签名的检测目录,接收 findings,评估安全态势(包含真实的 30 天趋势),针对新增/复发的 findings 发出警报,并利用 LLM 从 CVE 公告中生成新检测草案。
- **Agent 留在主机,数据不外泄** — 发现和扫描均在本地运行;主机的原始攻击面永远不会外泄。
- **签名的检测目录** — agent 在运行*任何*检测之前,会验证 Ed25519 签名的 bundle;验证失败则默认拒绝。
- **版本感知匹配** — 检测基于服务*和*版本范围触发,因此 `litellm <1.40.2` 会跳过 `1.41.0`。
- **态势、趋势与警报** — 真实的 30 天安全态势评分,并带有针对新增和复发 findings 的频道/规则告警。
- **AI 介入** — 根据 CVE 公告起草检测草案,并在请求路径之外对 findings 进行分类。
- **原生多租户** — 用户、组织、会话认证、RBAC,以及 Postgres 基于 `org_id` 的行级隔离。
## 架构
| 组件 | 路径 | 技术栈 |
|-----------|------|-------|
| **Control plane** | `control-plane/` | FastAPI + SQLAlchemy + Alembic(默认 sqlite,compose 中为 Postgres) |
| **Agent** | `agent/` | Go 1.22,仅依赖标准库,运行在每个受监控的主机上 |
| **Web UI** | `web/` | React + TypeScript + Vite + Tailwind |
| **Detections** | `detections/` | 根据 `detection.schema.json` 验证的 YAML 规格 |
完整循环:agent **注册 (enroll)** → **心跳 (heartbeat)** → control plane 下发 **发现 (discover)** 任务 → agent 上报 **资产 (assets)** → 心跳下发 **扫描 (scan)** 任务(通过服务 **和** 版本范围匹配检测) → agent 拉取 **签名的目录 bundle**,进行验证并在主机上运行检测 → 上报 **findings** → control plane 对 **安全态势** 进行评分,评估 **告警规则**(在后台传递匹配的告警),并(可选地)通过 **AI** 在请求路径之外对每个 finding 进行分类。
Web UI 是多租户的:登录(演示中为 `demo@palisade.local` / `palisade`),所有 `/v1` 读取端点都将限定于您当前活跃的组织,并具备基于角色的访问权限(owner/admin/member/viewer)。
## 一键体验
在您自己的环境中查看整个产品运行的最快方式。它会启动 control plane、Web UI、Postgres 以及一个自动注册并扫描内置故意暴露漏洞目标的 agent —— 构建于一个预置的组织之上,因此每个屏幕(Dashboard、Assets、Findings、Detections、Alerts)在加载瞬间即有数据填充。
```
make demo # docker compose: api + web + postgres + agent + target
# 打开 http://localhost:8080 — 使用 demo@palisade.local / palisade 登录
make demo-down # tear down (removes volumes for a clean re-run)
```
在大约 20-40 秒内,agent 会完成注册、发现目标,并出现一个真实的严重 finding(`litellm-proxy-preauth-sqli`,CVE-2026-42208)与预置数据并列 —— 完整的 **注册 → 发现 → 扫描 → finding → 态势** 循环,端到端,无需手动步骤。
有两个标志位驱动演示(由 `make demo` 自动设置):
| 变量 | 效果 |
|-----|--------|
| `PALISADE_SEED_DEMO=1` | 在引导时为演示组织填充逼真的资产、findings、30 天安全态势趋势、告警和审计历史(幂等)。 |
| `PALISADE_DEMO_MODE=1` | 使公开演示对已登录用户变为 **只读**(agent 摄取仍可写入);在 UI 中展示“在线演示”横幅。 |
两者默认关闭,因此除非您主动开启,开发和自托管生产环境的行为将与之前完全一致。要在不使用 Docker 的情况下填充本地 sqlite 运行,请在启动 control plane 之前设置 `PALISADE_SEED_DEMO=1`。
要监控您 **自己** 的主机而不是内置目标:在 UI 中生成一个注册 token(**Add agent**),然后在该主机上运行 agent 二进制文件(`palisade enroll --token
--server ` → `palisade run`)。
## 界面展示
使用了 `PALISADE_SEED_DEMO=1`(每个屏幕均已填充)和 `PALISADE_DEMO_MODE=1`(只读的“在线演示”横幅)的门户。
| | |
|---|---|
| **Dashboard** — 安全态势评分、30 天趋势、需关注项 | **Finding 详情** — 证据、指纹、修复建议、参考 |
| [](docs/screenshots/01-dashboard.png) | [](docs/screenshots/02-finding-detail.png) |
| **Assets** — 发现的服务、版本、暴露情况、findings | **Detections** — 带有 CVSS 和租户命中数的签名 CVE 目录 |
| [](docs/screenshots/03-assets.png) | [](docs/screenshots/04-detections.png) |
| **Alerts** — 频道、规则、免打扰时段、历史记录 | |
| [](docs/screenshots/05-alerts.png) | |
## 快速开始(零基础设施,sqlite)
需要 Go 1.22+、Python 3.12、Node 18+。
```
# 1. control plane
make venv # create control-plane/.venv + install deps
make migrate # apply migrations (sqlite:///./palisade.db)
cd control-plane && PALISADE_ENROLL_TOKENS=PLS-DEMO \
./.venv/bin/uvicorn app.main:app --reload # http://127.0.0.1:8000/docs
# 2. web UI(单独的终端)— vite 将 /v1 代理到 control plane
cd web && npm install && npm run dev # http://127.0.0.1:5173
```
或者在 Docker 中运行整个技术栈(FastAPI + Postgres):
```
cd control-plane && cp .env.example .env && docker compose up --build
```
## 端到端演示
`DEMO.md` 演练了完整的本地主机循环:启动 control plane,在 4000 端口暴露一个模拟易受攻击的 LiteLLM 目标,注册并运行 agent,通过读取 API 观察真实的严重 finding(`litellm-proxy-preauth-sqli`,CVE-2026-42208)出现,然后将其静音并观察态势如何恢复。
```
make smoke # enroll → discover → assets → scan → findings → posture (temp DB)
```
## 签名的目录 bundle
Control plane 通过规范清单使用 Ed25519 对检测 bundle 进行签名;agent 重建相同的清单,并在运行 **任何** 检测之前根据锁定的公钥对其进行验证 —— 确保不受信任通道上的完整性。`.env.example` 中提供了一对演示密钥。
```
# control plane:启用使用 demo key 进行签名
cd control-plane
PALISADE_SIGNING_KEY=70kJtI1NajTd1yQXFHVRuBVQfc6P2CAtRroaLCmYYbY= \
./.venv/bin/uvicorn app.main:app --reload
```
Agent 锁定了匹配的公钥(可通过 `PALISADE_CATALOG_PUBKEY` 覆盖);内置的默认值与演示种子相匹配。验证策略:
- 空签名 → 拒绝扫描;
- `"stub"`(未设置签名密钥) → 在开发模式下继续并给出警告;
- 其他 → 进行验证,如果失败则拒绝运行检测。
生成您自己的密钥对:
```
cd control-plane && ./.venv/bin/python -c "import os,base64;from app import _ed25519 as e;s=os.urandom(32);print('PALISADE_SIGNING_KEY=',base64.b64encode(s).decode());print('pubkey =',base64.b64encode(e.publickey(s)).decode())"
```
将打印出的 seed 设为 control plane 的 `PALISADE_SIGNING_KEY`,并将 pubkey 设为 agent 的 `PALISADE_CATALOG_PUBKEY`。
## 起草 → 审查 → 接受(闭环)
在 **Detections** 屏幕中,**+ New from CVE URL** 会利用 LLM 根据公告起草检测(需要在 control plane 上设置 `ANTHROPIC_API_KEY`;否则端点返回 503)。审查草案,然后点击 **Accept & ship** 将其持久化 —— 这会增加目录版本号,以便 agent 在下次拉取 bundle 时获取它。等效的 API 调用(需要 admin+ 会话 bearer token;有关 `$TOKEN` 详情请参见 DEMO.md):
```
curl -s -X POST http://127.0.0.1:8000/v1/detections \
-H "Authorization: Bearer $TOKEN" -H 'content-type: application/json' -d '{
"id":"acme-rce","title":"ACME RCE","cve":"CVE-2026-9999","severity":"high",
"category":"web","engine":"nuclei","match":{"service":"acme","versions":"<2.0.0"},
"http":[{"method":"GET","path":"/x","matchers":[{"type":"status","status":[200]}]}],
"remediation":"upgrade to >=2.0.0","references":["https://example.com"],"cvss":7.5
}' # -> {"id":"acme-rce","version":}
```
## 版本感知的扫描匹配
检测通过服务 **和** 版本范围来定位资产。`match.versions` 接受逗号/空格分隔的约束条件(`<1.40.2`,`>=11.1.4 <15.2.3`);一个针对 `litellm <1.40.2` 的检测会在 `1.39.0` 上触发,但不会在 `1.41.0` 上触发。未知/缺失的资产版本会 **放行**(依然进行扫描),因此漏洞永远不会被默默跳过。
## AI 分类
设置 `ANTHROPIC_API_KEY` 后,新的 findings 会在摄取后被评分(`triage_priority` / `triage_score` / `triage_rationale`,展示在 finding 读取 API 中)。这是尽最大努力执行的,并在摄取请求路径之外的后台任务中运行 —— 它永远不会阻塞或导致摄取失败,如果没有设置密钥则不执行任何操作。`PALISADE_TRIAGE_MODEL` 可覆盖模型(默认为 `claude-haiku-4-5-20251001`)。
## 告警
从 **Alerts** 屏幕或 API 定义 **频道**(telegram / 电子邮件 / webhook)和 **规则**(`min_severity` + `on_events` `[new|regressed]` → 频道)。在摄取 finding 时,匹配的规则会触发,告警会在后台任务中传递;告警历史记录将被保留并展示在 `GET /v1/alerts`。频道密钥在读取时会被隐藏。
```
BASE=http://127.0.0.1:8000; UAUTH="Authorization: Bearer $TOKEN" # see DEMO.md for $TOKEN
# webhook channel + 一条在任何 high+ 新增/回归 finding 上触发的规则
CH=$(curl -s -X POST $BASE/v1/alert-channels -H "$UAUTH" -H 'content-type: application/json' \
-d '{"type":"webhook","name":"local","config":{"url":"http://127.0.0.1:9000/hook"}}' \
| python3 -c "import sys,json;print(json.load(sys.stdin)['id'])")
curl -s -X POST $BASE/v1/alert-rules -H "$UAUTH" -H 'content-type: application/json' \
-d "{\"name\":\"high+\",\"min_severity\":\"high\",\"on_events\":[\"new\",\"regressed\"],\"channel_id\":\"$CH\"}"
```
## 测试
```
make test # Go agent tests + smoke + detection validation
cd control-plane && ./.venv/bin/python -m app.api_test # new endpoint coverage (signed path)
cd control-plane && ./.venv/bin/python -m app.smoke_test # full loop (unsigned path)
cd agent && go test ./... # agent unit tests incl. manifest verify
```
`pytest` 是可选的;两个 Python 测试模块都通过 `python -m` 作为普通脚本运行。
## 配置
所有配置项均位于 `control-plane/app/config.py` 中,从环境变量读取 —— 有关完整的配置表,请参见 `control-plane/.env.example` 和 `control-plane/README.md`。
关键变量:
| 变量 | 默认值 | 备注 |
|-----|---------|-------|
| `DATABASE_URL` | `sqlite:///./palisade.db` | Compose 会设置 Postgres URL。 |
| `PALISADE_ENROLL_TOKENS` | `PLS-DEMO` | 逗号分隔、一次性使用的注册 token(每个 token 生成一个 agent 加入该 token 对应的组织)。 |
| `PALISADE_DEMO_USER_EMAIL` | `demo@palisade.local` | 在引导时植入的演示组织 owner。 |
| `PALISADE_DEMO_USER_PASSWORD` | `palisade` | 演示用户密码。 |
| `PALISADE_SESSION_TTL_S` | `604800` (7天) | Web UI bearer-session 的生命周期(秒)。 |
| `PALISADE_SIGNING_KEY` | 未设置(演示密钥) | 用于 bundle 签名的 Ed25519 seed(base64)。未设置时会使用 **公开的** 演示密钥进行签名并发出警告 —— 在生产环境中请务必设置此项。 |
| `PALISADE_CATALOG_PUBKEY` | 演示密钥 | Agent 端锁定的 bundle 公钥(base64);必须与签名密钥匹配。 |
| `PALISADE_ALLOW_UNSIGNED` | 未设置 | Agent 的开发环境逃生舱 —— 如果设置,将运行未签名/`stub` 的 bundle 而不是拒绝。在生产环境中绝对不能设置。 |
| `ANTHROPIC_API_KEY` | 未设置 | 启用 AI 起草 + finding 分类。 |
| `PALISADE_DETECTIONS_DIR` | 仓库的 `detections/` 目录 | 植入检测 YAML 的来源。 |
## 状态
已实现:注册/心跳/扫描循环,**Ed25519 签名的目录 bundle**(agent 在运行任何检测前会进行验证,失败即终止;`detections/README.md` 涵盖了密钥生成/轮换),版本感知匹配,AI 起草及接受循环,CVSS,后台 AI 分类,包含真实 30 天趋势的安全态势评分,多租户(用户/会话/组织 + RBAC,一次性注册 token,基于 `org_id` 的 Postgres 行级安全),告警(频道/规则/历史记录),agent **mTLS**(注册时从内部 CA 颁客户端证书;在 TLS 终结代理处验证,并将 bearer `agent_secret` 作为纯文本演示的备选方案),以及一个 `SECURITY DEFINER` 路径,确保在 Postgres 的 RLS 下跨租户目录聚合(`tenants_hit` / `tenants_total`)数据正确,一个持久的 **Arq + Redis** 队列/worker 用于 AI 分类和告警传递(当未设置 `REDIS_URL` 时,使用进程内的 `BackgroundTasks` 作为备选),以及一个可插拔的 **`module`** 检测引擎(agent 中编译好的 `spec_ref` 注册表;第一个模块是 Next.js middleware 绕过,CVE-2025-29927),**基于每个组织的静态证据加密**(AES-256-GCM,基于按组织封装的数据密钥,migration 0005),以及 **基于规则的告警免打扰时段**(推迟传递,在窗口关闭时释放,migration 0007)。尚未构建(参见 `SPEC.md`):生产运维层 —— IaC、实时部署、公开状态页面、可观测性仪表盘和运维手册。
## License
[Apache License 2.0](LICENSE) — © 2026 Kenneth Lacroix.
由 [Kenneth Lacroix](https://kennethlacroix.me) 构建 · [trypalisade.dev](https://trypalisade.dev)
标签:AI基础设施安全, AV绕过, FastAPI, Go, React, Ruby工具, Syscalls, 安全态势管理, 实时处理, 插件系统, 攻击面监控, 无线安全, 日志审计, 测试用例, 请求拦截