8.0 KiB
Custom Variables
Status: Confirmed
1. Purpose
提供一个由 Admin 通过 UI 管理、由自定义 Playbook 和 Agentic Module 在后端运行时读取的字符串变量仓库。它类似受控的数据库版环境变量,但不会修改真实 os.environ,也不影响 Django 全局配置。
典型用途:
- 外部系统 base URL。
- API token、username/password。
- tenant/project ID。
- 自定义 JSON 字符串。
- Module 或 Playbook 的运行参数。
2. Scope
Consumers
BasePlaybook.get_variable(key)BaseModule.get_variable(key)
Not consumers
- Agent API。
- CLI 或插件。
- 前端运行时。
- Django template。
- 其他任意后端模块。
- 系统 Runtime Settings。
Excluded
- 写入真实进程环境变量。
- 全局配置覆盖。
- per-Playbook/per-Module scope。
- 变量继承或 override。
- value 类型系统。
.env导入导出。- REQUIRED_VARIABLES 声明。
- Secret 加密、版本历史或自动泄露防护。
3. Data model
建议模型 CustomVariable:
| Field | Type | Rules |
|---|---|---|
| id | UUID | primary key |
| key | CharField(128) | unique, immutable |
| value | TextField | non-empty, max 65,536 UTF-8 bytes |
| is_secret | Boolean | controls API masking only |
| description | TextField | optional |
| enabled | Boolean | default true |
| created_at | DateTime | auto |
| updated_at | DateTime | auto |
Key validation
Regex:
[A-Z][A-Z0-9_]{0,127}
- 全局唯一。
- 大小写敏感,但合法输入只有大写。
- 创建后不可改名。
- 修改 key 的 PATCH/PUT 返回 validation error。
Value validation
- 必须至少一个字符。
- 以 UTF-8 bytes 计算,最多 65,536 bytes。
- 可包含换行。
- 不支持 binary。
- 不做 trim;空格可能是有意值,但零长度禁止。
- 更新 Secret 时省略 value 表示保留旧值。
- 显式
""始终拒绝。
4. Storage security
已确认:
- Secret 和非 Secret 均以 PostgreSQL 明文保存。
- 数据库管理员、数据库泄露和未加密备份可以读取 Secret。
is_secret只控制 API/UI 显示与审计,不提供 cryptographic protection。- 用户文档必须明确该限制。
不得在 AuditLog、普通 API response、异常文本或日志中复制 value。
5. Runtime API
Base class helper:
def get_variable(self, key):
...
返回:
- Enabled 且存在:原始
str。 - 不存在:
None。 - Disabled:
None。 - 已删除:
None。
行为:
- 每次调用都查询 PostgreSQL。
- 不做 per-run、per-message 或 Worker 全局缓存。
- Admin 在 Playbook/Module 运行中修改、Disabled 或删除变量,下一次读取立即看到变化。
- 不抛 missing variable 异常。
- 不支持 default 参数作为平台约定;自定义代码自行使用
or或显式 None 处理。 - 不返回 is_secret/description 等 metadata。
- 不记录 read audit 或 usage relation。
建议共享 service 位于 apps.settings.custom_variables 或等价窄模块,BasePlaybook/BaseModule 只做代理,避免重复 ORM 代码。
6. Permissions
| Action | Admin | User | Viewer | Playbook/Module Worker |
|---|---|---|---|---|
| List metadata | Yes | No | No | No |
| Read non-secret value via Admin API | Yes | No | No | N/A |
| Reveal secret | Yes | No | No | N/A |
| Create/update/delete | Yes | No | No | No |
| get_variable runtime | No direct API | No direct API | No direct API | Yes |
Worker 读取不根据发起 Playbook 的用户角色过滤。User 发起的 Playbook 仍可读取所有 Custom Variables,因此 Admin 必须只安装可信自定义代码。
7. Admin API
建议资源:
/api/settings/custom-variables/
List/retrieve default representation
非 Secret:
{
"id": "...",
"key": "EDR_BASE_URL",
"value": "https://edr.internal.example",
"is_secret": false,
"description": "Production EDR API",
"enabled": true
}
Secret:
{
"id": "...",
"key": "EDR_API_TOKEN",
"value": "",
"value_configured": true,
"is_secret": true,
"description": "Production EDR token",
"enabled": true
}
Reveal
POST /api/settings/custom-variables/{id}/reveal/
- 仅 active Admin session。
- 不要求重新输入本地或 LDAP 密码。
- 返回一次明文 value。
- 每次请求写 AuditLog。
- 不应支持 bulk reveal。
- response 应使用 no-store cache headers。
Update
- key 不可改。
- Secret update 未包含 value:保留旧值。
- Secret→non-secret:API 需要显式确认字段,例如
confirm_secret_exposure=true。 - 没有确认返回 400。
- non-secret→secret 正常允许。
- 所有 changes 审计不包含 value。
Delete
- 允许硬删除。
- UI 必须二次确认。
- API 不负责扫描 Python 代码引用。
- 删除后运行时返回 None。
- 删除 AuditLog 保存 key、description、is_secret、enabled,不保存 value。
8. Audit
写 AuditLog:
- create
- update
- enable/disable(作为 update)
- reveal
- delete
不写:
- get_variable runtime read。
- Admin 普通 list/retrieve。
Secret 和非 Secret value 均不得进入 changes。可使用:
{
"changes": {
"value": {"from": "***", "to": "***"},
"enabled": {"from": true, "to": false}
},
"metadata": {
"key": "EDR_API_TOKEN",
"value_changed": true
}
}
不保留旧 value,不支持 rollback。
9. Frontend
位置:System Settings 中新增 Custom Variables。
List
- Key。
- Description。
- Secret 标记。
- Enabled。
- Value configured。
- Updated time。
- Edit/Delete actions。
- Secret 默认不可见。
Create/edit modal
- Key 创建时可编辑,编辑时只读。
- Value 使用 multiline input;Secret 使用 password input。
- is_secret switch。
- enabled switch。
- description。
- value byte limit 提示。
- 编辑 Secret 时 value 留空表示不修改,UI 必须明确说明。
Reveal
- Secret 行显示 Reveal。
- active Admin session 直接调用。
- 明文只显示在临时 Modal。
- Modal 关闭后从前端 state 清除。
- 不复制到列表 state、URL、localStorage 或 console。
Secret downgrade
从 Secret 改为普通变量时显示额外确认:
This value will become visible in normal Admin API responses and UI.
10. Interaction with custom code
示例:
class Playbook(BasePlaybook):
def run(self):
base_url = self.get_variable("EDR_BASE_URL")
token = self.get_variable("EDR_API_TOKEN")
if not base_url or not token:
raise ValueError("EDR custom variables are not configured.")
自定义代码责任:
- 检查 None。
- 解析 JSON/boolean/number。
- 不把 Secret 写入 log、Stage summary、remark、Enrichment 或异常。
- 为 HTTP 调用设置 timeout、TLS、proxy、重试和幂等。
平台不静态分析 key,也不展示“变量被哪些脚本使用”。
11. Migration and backup
- 新表 migration,无旧数据迁移。
- v0.5.2 现有 LLM/SIEM/LDAP/TI Secret 不自动复制到 Custom Variables。
- 备份/恢复自然包含明文 value。
- Compose 文档需提醒保护数据库备份。
12. Acceptance criteria
- 只有 Admin 能访问资源和 Reveal。
- key regex、唯一和不可改名规则生效。
- 空 value 和超过 65,536 bytes 被拒绝。
- Secret 默认 response 不含明文。
- Admin Reveal 返回明文并写不含 value 的审计。
- Secret→普通无确认被拒绝。
- Playbook 和 Module 每次读取当前数据库值。
- Disabled/missing/deleted 返回 None。
- Agent API、CLI 和普通用户没有读取端点。
- CRUD AuditLog 永不包含 old/new value。
- 删除无需引用检查且立即影响运行时读取。
13. Known tradeoffs
- PostgreSQL 和备份保存明文 Secret。
- active Admin session 无需重新认证即可 Reveal。
- User 发起的可信 Playbook 可以间接使用全部 Secret。
- 平台无法阻止恶意或错误自定义代码泄露 Secret。
- 每次 ORM 查询增加少量开销,这是为即时一致性接受的成本。