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 由不可重试错误触发。把状态机画出来,能直接暴露“死状态”和“不可达状态”,这是剧本评审中最有价值的检查之一。

剧本执行状态机(含错误处理与幂等入口) PENDING RUNNING WAITING SUCCESS PARTIAL FAILED CANCELLED 幂等键检查 alert_id + action 调度 需审批 审批通过 部分动作失败 不可重试错误 取消 重复触发 可重试错误(退避)

四、错误处理:区分“可重试”与“不可重试”

错误处理的第一步是分类。可重试错误包括网络超时、限流(HTTP 429)、临时性 5xx;不可重试错误包括参数校验失败、权限不足(403)、资源不存在(404)。对可重试错误应采用指数退避重试,例如首次等待 2 秒、第二次 4 秒、第三次 8 秒,最多 3 次;对不可重试错误应立即进入 FAILED 并记录原因。

第二步是“部分成功”的处理。一个剧本可能包含多个动作:隔离主机成功、但取证失败。此时不应简单标记为 FAILED,而应进入 PARTIAL,并在输出中明确哪些动作成功、哪些失败。这样分析师可以只补做失败动作,而不是重跑整个剧本。

第三步是补偿与回滚。对于已执行的破坏性动作(如禁用账号),应设计补偿动作(如恢复账号),并在剧本失败时按逆序执行。补偿动作本身也必须幂等。

五、幂等性设计原则

幂等性指同一操作执行一次与执行多次,对系统状态的影响相同。SOAR 剧本必须幂等,因为触发可能重复、重试可能发生、人工可能重复点击。实现幂等的常用手段:

  • 幂等键:用 alert_id + action_name 作为唯一键,执行前查询是否已执行过,若已执行则直接返回上次结果。
  • 状态检查前置:执行“隔离主机”前先查询主机当前隔离状态,已隔离则跳过。
  • 使用 upsert 语义:写工单、写标签时使用“存在则更新、不存在则创建”,而不是盲目插入。
  • 避免副作用累积:如“发送通知”应带去重标记,避免同一事件发送多封邮件。
设计检查清单:① 触发入口是否统一为事件+上下文?② 输入输出契约是否明确必填与类型?③ 状态机是否覆盖 WAITING、PARTIAL、CANCELLED?④ 错误是否区分可重试与不可重试?⑤ 每个破坏性动作是否有幂等键或状态前置检查?⑥ 失败时是否有补偿路径?