24.3 SOP、Runbook 与变更治理
一份只有命令的文档,会让操作更快,却不一定更安全:
ssh node
run command
wait
run next command它没有回答:
- 这是哪种故障或变更?
- 当前事实符合文档前提吗?
- 操作者有权改变哪个目标?
- 影响哪些用户和数据?
- 哪一步必须停?
- 命令超时后是失败、成功还是未知?
- 如何证明结果,而不是只看 exit code?
- 应当 rollback 还是 roll forward?
- 哪些证据可以保留,哪些 secret 不能导出?
可执行文档必须同时是动作合同、停止合同和证据合同。
24.3.1 日常操作、故障处置与恢复演练
四类文档解决不同不确定性
| 文档 | 环境 | 不确定性 | 主要形态 |
|---|---|---|---|
| SOP | 日常、重复 | 输入和结果基本已知 | 线性步骤 |
| Incident Runbook | 已有症状 | 原因和状态未知 | 分支与决策点 |
| Recovery Drill | 受控演练 | 恢复路径能否工作未知 | 假设、计时、验收 |
| Change Plan | 一次变更 | 版本、目标、窗口特定 | 精确 artifact 与批准 |
同一个动作可以出现在不同文档中,但语境不同。
例如 credential rotation:
routine SOP
planned age-based dual-version rotation
incident runbook
suspected disclosure; old identity cannot be re-enabled
drill
prove clients, pool and revoke path can rotate without secret export
change plan
rotate pg36_shop production identity at a named time and target不能把 routine SOP 原样用于凭据泄露事故,因为 rollback 到旧 secret 在事故中 不是安全选择。
SOP:稳定输入下的可重复流程
一份合格 SOP 至少包含:
identity
id / owner / version / review date
scope
exact supported environments and versions
authority
who may run / who approves / what role is used
trigger
scheduled or event condition
preconditions
facts that must be true
procedure
bounded, idempotent phases
stop conditions
facts that prohibit continuing
verification
technical and service postconditions
rollback-or-roll-forward
decision boundary and procedure
evidence
what to capture, redact, hash, retainSOP 中最重要的句子往往是:
STOP if ...而不是最长的命令。
Runbook:从症状出发,而不是假设根因
告警是:
PG36ShopAvailabilityFastBurnRunbook 不应开头就执行 failover。合理顺序:
1 establish user impact and current window
2 freeze concurrent risky changes
3 reconcile unknown order outcomes
4 check recent release/config/access/topology events
5 inspect application -> entry -> pool -> PostgreSQL
6 choose the smallest safe intervention
7 verify user SLI and data control
8 preserve decision and evidence若先看到 replica lag 就 promote,可能:
- 切错根因;
- 扩大 write gap;
- 引入 split-brain 风险;
- 让原本健康的 write path 中断;
- 丢失调查证据。
Runbook 应提供 decision tree:
user availability burns?
no -> diagnose component, ticket/capacity path
yes -> correctness at risk?
yes -> freeze affected writes, data/security path
no -> entry path failing?
yes -> route/pool diagnosis
no -> transaction/lock/load diagnosis它不能穷举所有根因,但必须约束高风险捷径。
Recovery Drill:证明“能恢复”
backup SOP 和 restore drill 不同:
backup SOP
run backup
repository receives objects
check reports healthy
restore drill
select a recovery objective
prove backup + required WAL coverage
restore into isolation
start in recovery
reach target
promote only inside isolation
verify application invariants
stop recovered postmaster演练要在开始前固定 success criteria。若恢复后才决定“只要能连上就算成功”, 结果会向已有事实偏移。
本章的 SOP-BACKUP-RESTORE 要求:
- source cluster 和 repository 明确;
- recovery target 固定;
- destination 无 production listener;
- 验证 query 与预期先冻结;
- WAL 缺失、identity 模糊或 isolation 失败立即停止;
- 时间只记为沙箱 observation,不称 production RTO。
Drill 不应依赖临场英雄主义
有效演练测试:
- 文档是否完整;
- 权限是否可用;
- secret 是否能安全获得;
- 工具版本是否兼容;
- 依赖是否存在;
- 验收是否机器可判;
- 证据是否完整;
- 交接是否能继续。
只让原作者凭记忆完成,证明的是个人能力,不是组织恢复能力。可在后续轮次让 另一位合格 operator 按文档执行,原作者只观察和记录歧义。
Change Plan:把抽象 SOP 绑定到一次动作
SOP 可以写:
planned switchover procedureChange Plan 必须写:
change_id CHG-...
service pg36_shop
environment production
cluster exact cluster identity
current leader fact captured at T0
candidate exact member
artifact hash reviewed command/config version
window exact start/end
requester durable identity
approver different durable identity
executor different durable identity
stop lines current values and thresholds
rollback/forward decision
observation SLI + probe + component facts“按切换 SOP 执行”不能替代这些单次事实。
版本和环境必须受支持
文档应写:
tested:
Pigsty v4.4.0
PostgreSQL 18.4
Patroni 4.1.3
PgBouncer 1.25.2
not implied:
all earlier/later versions
cloud-managed PostgreSQL
a different DCS
session pool mode命令、输出字段和行为会随版本改变。升级计划必须同时检查 SOP 与 validator。
日常、故障和演练的证据粒度不同
| 类型 | 关键证据 |
|---|---|
| routine | target、输入版本、执行结果、postcondition |
| incident | timeline、user impact、decision、unknown outcome |
| drill | hypothesis、predefined success、timing、exception |
| change | request/approve/execute identity、artifact hash、closeout |
不能因为 incident 需要更多证据,就把所有 routine 日志永久保存;也不能因 routine 简洁,在安全事故中只留一个 shell exit code。
24.3.2 申请、评审、执行、验证与回退
完整生命周期
本章使用十一阶段:
request
-> classify risk and authority
-> freeze preconditions and stop lines
-> preview and test
-> approve
-> execute
-> observe
-> verify
-> rollback or roll forward
-> retain evidence
-> close and review“批准”不是生命周期的起点,也不是结束。
1. Request:先说明目的,不要从命令开始
请求至少回答:
why
user/business/reliability/security need
what
desired state, not just command
where
exact service/environment/cluster/object
when
proposed window and dependency
impact
users/data/capacity/recovery/security
success
measurable postconditions反例:
please run ALTER TABLE tonight合格:
expand pg36_shop order schema with nullable external_ref;
old and new app versions remain compatible;
no table rewrite; lock wait stops after 2 s;
roll back by disabling new writer before semantic cutover.2. Classify:按实际影响,不按团队习惯
本章风险级别:
L0:只读
- 查询统计视图;
- 渲染配置 diff;
- 验证已有 evidence;
- 不改变数据库、pool、topology、credential 或 route。
L0 仍要绑定目标,避免拿错误环境的证据做结论。
L1:有界、可逆、低影响
- 增加 dashboard;
- 发布 disabled alert;
- sandbox 中增加窄权限 NOLOGIN role。
需要 preview、verification 和 rollback。
L2:material state
- credential rotation;
- online schema expansion;
- pool limit;
- role/permission;
- 生产参数 reload;
- 业务路由变化。
需要独立批准、停止线、完整证据。
L3:destructive/topology/recovery
- failover;
- restore/promotion;
- data deletion;
- cluster reset;
- 大范围不可逆迁移。
需要最强 target binding、双人控制、延迟确认或等价门禁。
风险由 blast radius、可逆性、未知结果与数据后果共同决定,不是“SQL 只有 一行所以低风险”。
3. Freeze preconditions:审批的是事实快照
preflight 可以包括:
target identity
current leader/timeline
replica state
backup and WAL coverage
disk and capacity headroom
blocking sessions
error-budget state
current release
config hash
credential and authority每个事实要有:
- source;
- captured_at;
- freshness limit;
- expected value;
- stop behavior。
批准后到执行前可能发生变化。执行器必须重新采集关键事实:
approved leader = pg-a
current leader = pg-b
=> stop, do not reinterpret the plan4. Preview and test:使用相同 artifact
好的 pipeline:
render artifact
-> hash
-> test same hash
-> approve same hash
-> execute same hash不要测试一套手写 SQL、执行另一套临时编辑内容。
preview 可能包括:
- Pigsty inventory projection 和 diff;
- SQL parse/plan;
- lock/rewrite analysis;
- restore dry-run facts;
- target list;
- expected state transition;
- synthetic data replay;
- rollback simulation。
preview 不能证明生产一定成功,但能拒绝明显不符合合同的输入。
5. Approve:批准目标、动作、窗口,不是空白授权
批准记录要绑定:
change id
artifact hash
exact target
risk class
blast radius
start/end
preconditions
stop lines
operator identity“同意处理”或聊天表情不能作为 L3 授权。
6. Execute:每一步都应可观察
执行器:
- 使用个人 durable identity;
- 不共享 root/DBA 密码;
- 不把 secret 放在 shell 参数;
- 记录 phase start/end;
- 每一阶段检查 stop condition;
- 不并行执行计划外动作;
- 超时后先分类结果。
脚本的 set -e 只能在命令非零时停止。它不能判断:
- command 返回 0 但目标错误;
- client timeout 后 server 已完成;
- failover command 成功但路由未刷新;
ALTER TABLE成功但 application 不兼容;- backup 成功但不可恢复。
7. Observe:动作期间看用户与组件
观察至少两条线:
service
availability / latency / freshness / correctness probe
component
topology / connections / locks / WAL / pool / host只看执行命令输出,会错过用户影响;只看 SLI,又无法及时识别安全停止线。
8. Verify:状态正确,而不是命令完成
postcondition 应与 request success 一一对应。
planned switchover:
one leader
expected timeline progression
streaming replicas
client entry routes current leader
acknowledged writes present
unknown outcomes reconciled
no duplicate tokenschema release:
old app works
new app works
constraint/reconciliation passes
lock/WAL within bounds
feature flag state correctcredential rotation:
new authentication works
old new-session authentication fails
existing sessions explicitly handled
pool declarations converge
secret absent from evidence9. Rollback or roll forward:不是所有状态都能倒回
rollback 适合:
- application feature flag;
- additive configuration;
- reversible grant;
- 在 semantic cutover 前保留旧结构。
roll forward 更适合:
- timeline 已推进的 failover;
- 已泄露 credential;
- 已有新版本写入的数据格式;
- 外部系统已消费的事件;
- commit outcome unknown。
PostgreSQL DDL 的边界
许多 PostgreSQL DDL 可以在 transaction 中回滚,但不能据此声称发布总可逆:
CREATE DATABASE等命令不能在 transaction block 内运行;CREATE INDEX CONCURRENTLY不能在 transaction block 内运行,失败还可能 留下INVALIDindex;- data backfill 已被新应用读取后,SQL rollback 不能撤回外部影响;
- table rewrite/WAL/replica lag 已经发生;
- application 与 schema 的兼容窗口可能关闭。
具体行为见 PostgreSQL CREATE INDEX 和第 11 章的安全模式变更。
回退计划要说明“在哪个决策点之前可回退”,而不是只写 ROLLBACK。
10. Retain evidence:保存证明,不保存秘密
每次变化至少形成 manifest:
source facts and hashes
target identity
request/approve/execute identities
phase timestamps
artifact hash
observations
verification
rollback-or-forward decision
exception
final decision不要保存:
- cleartext password;
- SCRAM verifier;
- private key;
- 完整 credential URI;
- 无边界 bind values;
- 不必要的客户行。
11. Close and review:关闭是一个结论
关单条件:
- service postcondition 通过;
- component postcondition 通过;
- unknown outcomes 为零或有明确 owner/deadline;
- 临时权限、route、pool/config 已恢复或正式纳管;
- evidence 完整;
- follow-up 有 owner 与 due date;
- budget/incident 状态更新。
“维护窗口结束”不能自动关闭失败的变更。
一个 change record
本章要求字段:
{
"change_id": "CHG-...",
"service_id": "pg36_shop",
"risk_class": "L2",
"exact_target": "environment/cluster/object",
"blast_radius": "declared users and data",
"requester_identity": "workforce://...",
"approver_identity": "workforce://...",
"executor_identity": "workforce://...",
"planned_start_and_end": ["...", "..."],
"preconditions": ["..."],
"stop_conditions": ["..."],
"execution_hash": "sha256:...",
"verification": ["..."],
"rollback_or_roll_forward": "...",
"decision": "accepted|rejected|accepted-with-exceptions",
"evidence_manifest": "evidence://..."
}真实系统还要验证三个 identity 不同且当时有效。
24.3.3 高风险动作的双人或延迟确认
双人控制解决什么
高风险动作容易同时发生三类错误:
intent error
本来不应做
target error
对错环境/集群/对象做
execution error
步骤、参数或时机错误独立批准人应使用独立证据检查意图与目标;执行器负责按批准 artifact 操作。 两人同时复制同一个错误命令,不构成有效独立控制。
NIST SP 800-53 Rev. 5.1 在 access restrictions for change 中描述 dual authorization:两名合格个人批准 和实施选定高风险变化,并对变化负责。组织还可轮换职责,降低串通风险。
本章将它转化为:
requester_may_approve false
approver_may_execute false
shared_accounts false
qualified approver true
target + blast radius required
machine preconditions required独立不只意味着用户名不同
无效:
- 同一人使用两个账号;
- 两人共享一个 password;
- approver 没有理解 PostgreSQL/Pigsty 风险;
- approver 只看 requester 的截图;
- 执行 artifact 在批准后被修改;
- 两人都受同一个未验证假设影响。
有效独立性包括:
- durable workforce identity;
- 不同职责;
- 足够专业能力;
- 能访问 source-of-truth;
- artifact hash;
- 能拒绝;
- 拒绝不会被绕过;
- 事后记录。
延迟确认解决冲动和误目标
destructive action 可要求 cooldown:
request generated
exact target + action + impact + hash
-> independent review
-> wait bounded interval
-> refresh target/preconditions
-> typed confirmation bound to same target/hash/window延迟让:
- 执行者有时间发现环境错误;
- 依赖 team 有时间反馈;
- 自动备份/导出有时间完成;
- 用户影响窗口再次确认。
它不适用于所有 incident。真正紧急时可以缩短 normal wait,但不能跳过 target、 authority、stop line 和 evidence。
confirmation token 必须绑定语义
差:
CONFIRM=YES较好:
target prod/eu-west/pg-shop
action promote reviewed recovery target
artifact sha256:...
window 2026-...
confirmation RECOVER_PG_SHOP_TO_...脚本还应从运行时重新解析 target identity,而不是完全信任环境变量字符串。
break-glass 不是无规则
break-glass 允许:
- 跳过正常排期;
- 获取时限高权身份;
- 执行恢复服务所需的最小动作。
它不允许:
- 不记录目标;
- 无止境保留高权;
- 关闭审计;
- 将 credential 发进聊天;
- 跳过事后 review;
- 使用后不轮换;
- 将未知结果当成功。
本章合同:
may_skip_normal_wait true
may_skip_target_and_evidence false
time_bounded_identity true
independent_after_review true
credential_rotation_after_use trueemergency change 仍要选择最小动作
事故中的压力会放大 scope:
one blocked query
-> restart all databasesRunbook 应给出干预阶梯:
observe
-> cancel one query
-> terminate one session
-> isolate one application path
-> controlled role change
-> restart component
-> recover/fail over每一级需要新的证据和 authority。不能因为已经进入 SEV-1,就自动获得所有 destructive action 的授权。
自动化能做什么
适合机器执行:
- 解析 inventory;
- 验证 mode/owner;
- 比较 target identity;
- 采集 leader/timeline/LSN;
- 计算 lock、WAL、budget;
- 检查 artifact hash;
- 拒绝非空 evidence directory;
- 执行 bounded probe;
- 核对 postcondition;
- 生成 manifest;
- 扫描 secret material。
仍需组织决定:
- 用户损失是否可接受;
- recovery point 是否符合业务;
- 是否暂停业务;
- 谁拥有 change authority;
- 合规/隐私边界;
- 何时允许例外。
自动化可以证明 guard 成立,不能发明授权。
guard 不是一串容易伪造的环境变量
高风险 runner 应结合:
declared target token
live target identity
inventory allowlist
environment classification
production traffic flag
data classification
approval record
artifact hash
private input mode
empty output directory只检查 NONPRODUCTION=true 不够;操作者可以错误设置。第 19–23 章的实验
runner 还会核对 host、cluster、topology 和 fixture identity。
超时与 unknown outcome
高风险 API/SQL 超时后:
do not retry yet
-> inspect durable state
-> classify:
completed
not started
partially applied
unknown
-> choose idempotent continuation or repair例子:
COMMITtimeout:查 idempotency token;- switchover timeout:查 Patroni leader/timeline;
- revoke timeout:从新 session 测认证与 role attributes;
- DDL timeout:查 catalog/lock/index validity;
- backup timeout:查 repository manifest,不凭 client exit 猜。
重试本身是一项 change,需要可幂等证明。
高风险 review 的三次停止机会
before approval
design or authority is wrong
immediately before execution
facts or target changed
during execution
stop threshold or unknown outcome reached批准人不能提前放弃后两次停止。机器 guard 也不能因为 approval 存在而忽略 live drift。
本章的 SOP 与变更政策
四个 SOP 覆盖:
backup and restore
planned switchover and failover
access and credential rotation
schema release每份都有 precondition、stop、verification、rollback/roll-forward 和 evidence。 validator 会拒绝:
- backup exit 0 作为全部恢复验证;
- L2/L3 同人自批自执行;
- break-glass 跳过 target/evidence;
- 沙箱运行被标为 production proof。
文档演练清单
- 文档类型是否正确,还是把 incident 写成线性 SOP?
- scope 和版本是否明确?
- trigger 与 authority 是否明确?
- exact target 能否由 live evidence 验证?
- precondition 是否带 freshness?
- 每个高风险 phase 前是否有 stop condition?
- 命令 timeout 后是否先核对 durable state?
- success 是否由 postcondition 定义?
- rollback 与 roll-forward 的决策点是否明确?
- external side effect 是否考虑?
- requester/approver/executor 是否真正独立?
- break-glass 是否有时限、审查和轮换?
- evidence 是否 secret-free?
- 另一个合格 operator 能否只凭文档完成?
- 文档、脚本、目标版本变化后是否重新演练?
下一节会把 SLO 与这些 Runbook 连接起来:一个告警若不能把值班人带到安全的 第一动作,就不应成为 page。
上一节:SLI、SLO 与错误预算 · 返回本章目录 · 下一节:观察与告警契约 · 查看全书目录 · 查看索引中心