netzbegruenung/salt-security-agent

GitHub: netzbegruenung/salt-security-agent

LLM 驱动的 SaltStack 环境安全扫描代理,定时巡检 minion 运行状态并利用大语言模型进行威胁分析与配置比对。

Stars: 0 | Forks: 0

# Salt Security Agent 一个由 LLM 驱动的安全扫描代理,专为 Saltstack 管理的环境设计。该代理会 定期选择 Salt minion,通过 Salt CLI 获取其正在运行的进程列表, 并执行由 LLM 驱动的调查,该调查可以检查 minion 上的文件系统路径, 并将其与 Salt 仓库进行比对。 ## 架构 ``` Celery Beat ──► dispatch_scans (task) │ ▼ pick_next_minion (Redis sorted set) │ ▼ scan_minion (task, runs on worker) │ ├─ get_processes ──► salt cmd.run 'ps aux' (container PIDs filtered) │ └─ run_agent (LLM tool-calling loop) │ ├─ ls_minion(path) → salt cmd.run 'ls -la ' ├─ list_repo_files(path) → os.scandir(repo_path / path) └─ read_repo_file(path) → open(repo_path / path) ``` - **Broker 与状态**:Redis - **调度**:Celery Beat 每分钟触发一次 `dispatch_scans`;每次触发会扫描 上次扫描时间早于配置的 `scan_period` 的最旧的 minion。Worker 并发限制控制着并行扫描的数量。 - **Minion 选择**:Redis 有序集合 (`salt:scanned`) 跟踪上次扫描的时间戳。 会选择上次扫描时间早于扫描周期的、最旧被扫描的 minion; 从未被扫描过的 minion 始终符合条件。 - **LLM 通信**:通过 `httpx` 发起原始 HTTP 请求,连接到任何兼容 OpenAI 的 chat completions endpoint。 ## 环境要求 - Python 3.11+ - Redis - Salt master(需要提供可用的 `salt` 和 `salt-key` CLI) - 一个兼容 OpenAI 的 LLM API endpoint ## 安装 ``` pip install -e . ``` ## 配置 复制并编辑 `config.toml`: ``` [scanning] parallel_hosts = 3 # Celery worker concurrency scan_period = "daily" # how often each minion is scanned: hourly, daily, weekly, monthly # report_directory = "/var/lib/salt-security-agent/reports" # 可选;参见 Reports 部分 [llm] url = "https://api.openai.com/v1" access_token = "sk-..." model = "gpt-4o" threat_model_path = "threat_models/default_threat_model.md" task_path = "tasks/default_task.md" [salt] repo_path = "/srv/salt" # Absolute path to the Salt state repository on the master [celery] broker_url = "redis://localhost:6379/0" result_backend = "redis://localhost:6379/0" # 可选。如果存在,agent 的 send_alert tool 发出的警报也会 # 通过使用经过身份验证的 SMTP 通过电子邮件发送。省略整个部分以禁用。 [smtp] host = "smtp.example.com" port = 587 username = "alerts@example.com" password = "changeme" from_address = "alerts@example.com" to_address = "soc@example.com" use_starttls = true # STARTTLS; set false for implicit TLS / SMTPS (typically port 465) ``` ### 威胁模型与任务 - **`threat_model_path`** — 描述需要寻找哪些内容的 Markdown 文件。默认文件位于 `threat_models/default_threat_model.md`。 - **`task_path`** — 包含提供给代理的分步指令的 Markdown 文件。 默认文件位于 `tasks/default_task.md`。 如果这两个路径不是绝对路径,将相对于当前工作目录进行解析。 #### 针对 Minion 的覆盖配置 在每次扫描之前,代理会在配置的目录中查找特定于 minion 的文件, 如果存在则使用它。解析顺序如下: 1. **精确匹配** — `/.md`。 2. **通配符匹配** — 任何 `/.md`,其中文件名主干中的 `_` 充当 `*` 通配符。例如,`keycloak_.md` 匹配 minion `keycloak01.example.com` (模式为 `keycloak*`)。如果多个通配符文件匹配,则主干最长 的文件胜出(最为具体)。 3. **默认值** — `/default.md`。 在上述配置下,名为 `web-01.example.com` 的 minion 将依次匹配 `threat_models/web-01.example.com.md`,接着是类似 `threat_models/web_.md` (`web*`)的任何通配符文件,最后是 `threat_models/default.md`。相同的解析规则也适用于 `tasks/`。 ### 报告 默认情况下,扫描报告会输出到 worker 的标准输出 (stdout)。设置 `scanning.report_directory` 以将其持久化到磁盘上。每份报告会写入到 `{report_directory}/{isodate}/{minion_id}`(例如:`/var/lib/salt-security-agent/reports/2026-06-07/web-01`)。 父目录会自动创建;如果在同一天重新运行扫描,将覆盖该 minion 的 上一次报告。 ## 用法 启动 Celery worker(负责处理实际的扫描任务): ``` salt-security-agent worker ``` 启动 Celery Beat 调度器(按配置的速率分发扫描任务): ``` salt-security-agent beat ``` 在两个独立的终端中运行它们(或者使用诸如 systemd 或 supervisord 之类的进程管理工具)。 `examples/systemd/` 目录下提供了 systemd 单元示例。 可选标志: ``` salt-security-agent worker --config /etc/salt-security-agent/config.toml --loglevel DEBUG salt-security-agent beat --config /etc/salt-security-agent/config.toml --loglevel INFO ``` ## 文件结构 ``` salt-security-agent/ ├── config.toml # Main configuration ├── pyproject.toml ├── tasks/ │ └── default_task.md # Default agent task instructions ├── threat_models/ │ └── default_threat_model.md # Default threat model └── agent/ ├── cli.py # Entry point (click) ├── config.py # Config loading (tomllib + dataclasses) ├── celery_app.py # Celery app + Beat schedule ├── tasks.py # Celery tasks ├── scheduler.py # Minion picker (Redis) ├── llm_agent.py # LLM tool-calling loop (httpx) └── tools/ ├── salt_tools.py # ls_minion, get_processes └── repo_tools.py # list_repo_files, read_repo_file ``` ## Minion 选择的工作原理 所有已接受的 minion 都是通过 `salt-key -L --out=json` 发现的。Redis 将每个 minion 上次扫描的 Unix 时间戳存储在有序集合中。`dispatch_scans` 每分钟运行一次,并且会: 1. 排除当前正在扫描的 minion(`salt:in_progress`)。 2. 过滤出*已逾期*的 minion —— 即上次扫描早于 `scan_period`,或者 从未被扫描过。 3. 从逾期集合中挑选出时间戳最旧的一个;如果没有逾期的 minion, 则此次触发不执行任何操作。 4. 将选定的 minion 添加到 `salt:in_progress` 中,并设置 1 小时的 TTL(如果 worker 崩溃则自动释放)。 5. 扫描成功后,更新时间戳并释放锁。 在有 N 个 minion 的情况下,这自然会产生大约 N 次扫描/每个扫描周期,并均匀分布在 整个周期内。突发容量受 `parallel_hosts`(worker 并发数)的限制。
标签:Celery, HTTP工具, Petitpotam, Redis, Saltstack, 安全巡检, 搜索引擎查询, 无线安全, 网络安全审计, 运行时操纵, 逆向工具