4. 剧本工程基础
在 SOAR 平台中,剧本(Playbook)不是一段“点一下就跑”的脚本,而是一个可被反复触发、可观测、可恢复的自动化执行单元。它要面对的是真实的安全事件:告警可能重复到达、外部 API 可能超时、处置动作可能部分成功。因此,剧本工程的核心不是“把动作连起来”,而是围绕触发、契约、状态、错误、幂等五个维度建立可预期的执行行为。本节围绕这五个维度展开,并给出可直接参考的设计原则与示例。
一、触发方式:剧本如何被“叫醒”
触发方式决定了剧本的入口形态和参数来源。常见触发方式可分为四类:
- 事件驱动触发:由 SIEM、EDR、邮件网关等上游系统推送告警事件,剧本以事件为输入。例如“EDR 检测到 Mimikatz 行为”触发“主机隔离与取证”剧本。
- 定时触发:按 cron 表达式周期执行,适合巡检、情报同步、过期数据清理。例如每天 02:00 同步威胁情报 IOC 库。
- 手动触发:由分析师在工单或控制台点击执行,适合高风险处置(如全网账号禁用)保留人工确认。
- API/Webhook 触发:由外部系统通过 REST 调用或 Webhook 唤起,适合与工单系统、ChatOps 集成。
无论哪种触发方式,入口都应统一为“事件对象 + 上下文参数”。事件对象携带原始告警字段(如 alert_id、src_ip、hostname、severity),上下文参数携带执行环境信息(如 tenant_id、analyst、dry_run)。这样剧本内部逻辑不依赖具体触发通道,便于测试与复用。
二、输入输出契约:让剧本可被组合
契约是剧本与外界之间的“接口协议”。输入契约规定必填字段、类型、取值范围和默认值;输出契约规定剧本执行后必须返回的结果字段。没有契约的剧本无法被上层编排调用,也无法被下游剧本消费。
一个可参考的输入契约示例(YAML 描述):
input:
alert_id: {type: string, required: true}
src_ip: {type: ip, required: true}
hostname: {type: string, required: false, default: ""}
severity: {type: enum, values: [low, medium, high, critical]}
dry_run: {type: bool, default: false}
output:
status: {type: enum, values: [success, partial, failed, skipped]}
isolated: {type: bool}
evidence_id: {type: string}
message: {type: string}
契约的价值在于:调用方只需按契约传参,不必关心剧本内部实现;剧本升级时只要契约不变,调用方无需修改。设计契约时应遵循“最小必要”原则,避免把内部临时变量暴露为输出。
三、状态机模型:把执行过程显式化
剧本执行不是一条直线。它可能等待人工审批、可能重试、可能被取消。用状态机描述剧本生命周期,可以让“当前处于什么状态、下一步能去哪里”变得清晰。一个典型的状态集合包括:PENDING(已触发待执行)、RUNNING(执行中)、WAITING(等待外部条件,如审批或回调)、SUCCESS、PARTIAL、FAILED、CANCELLED。
状态迁移必须由明确事件驱动,例如:PENDING → RUNNING 由调度器触发;RUNNING → WAITING 由“需要人工审批”动作触发;WAITING → RUNNING 由审批通过事件触发;RUNNING → FAILED 由不可重试错误触发。把状态机画出来,能直接暴露“死状态”和“不可达状态”,这是剧本评审中最有价值的检查之一。
四、错误处理:区分“可重试”与“不可重试”
错误处理的第一步是分类。可重试错误包括网络超时、限流(HTTP 429)、临时性 5xx;不可重试错误包括参数校验失败、权限不足(403)、资源不存在(404)。对可重试错误应采用指数退避重试,例如首次等待 2 秒、第二次 4 秒、第三次 8 秒,最多 3 次;对不可重试错误应立即进入 FAILED 并记录原因。
第二步是“部分成功”的处理。一个剧本可能包含多个动作:隔离主机成功、但取证失败。此时不应简单标记为 FAILED,而应进入 PARTIAL,并在输出中明确哪些动作成功、哪些失败。这样分析师可以只补做失败动作,而不是重跑整个剧本。
第三步是补偿与回滚。对于已执行的破坏性动作(如禁用账号),应设计补偿动作(如恢复账号),并在剧本失败时按逆序执行。补偿动作本身也必须幂等。
五、幂等性设计原则
幂等性指同一操作执行一次与执行多次,对系统状态的影响相同。SOAR 剧本必须幂等,因为触发可能重复、重试可能发生、人工可能重复点击。实现幂等的常用手段:
- 幂等键:用
alert_id + action_name作为唯一键,执行前查询是否已执行过,若已执行则直接返回上次结果。 - 状态检查前置:执行“隔离主机”前先查询主机当前隔离状态,已隔离则跳过。
- 使用 upsert 语义:写工单、写标签时使用“存在则更新、不存在则创建”,而不是盲目插入。
- 避免副作用累积:如“发送通知”应带去重标记,避免同一事件发送多封邮件。