# 生产备份需要独立的备份凭据吗？

只有当损坏生产环境的事故无法同时删除副本时，备份才真正是恢复副本。检查自动化任务背后的凭据时，这个道理就没那么显而易见了。在许多系统中，同一个令牌可以读取实时数据、写入备份、列出旧备份、为了保留策略删除备份、修改目标，还能启动恢复。把这个令牌交给自主代理后，一次错误或遭入侵的 API 调用，就可能把生产中断变成恢复失败。

解决办法不是用更复杂的措辞写一份更长的权限策略，而是为实时数据和恢复数据划分不同的操作边界。负责操作生产环境的凭据不应删除恢复副本。负责写入备份的凭据不应修改其保留策略。恢复操作应有独立的审批，因为它会把敏感数据重新带回活动环境。每个边界都应让错误请求在产生后果之前失败。

这是设计问题，不是供应商问题。无论副本存放在对象存储、托管备份保险库、快照、物理设备，还是第二个云账户中，这种模式都适用。存储不可变性很重要，管理权限分离也很重要。但如果代理的日常工作身份仍能使用周围的破坏性控制措施，两者都无法真正发挥作用。

## 如果一个身份可以删除备份副本，它们就不算真正分离

恢复副本必须能够承受你预期的生产故障模式，其中也包括高权限凭据被滥用。如果同一个代理身份既能调用 `delete production database`，又能调用 `delete recovery vault`，你拥有的只是重复数据，而不是隔离的恢复能力。

团队经常因为生产环境和备份使用不同的存储桶、文件夹、区域或资源名称，就称其为分离。这只是存储布局，不是访问隔离。拥有广泛权限的单一主体，只需几次请求就能跨过所有这些边界。

测试很简单：拿生产代理可以使用的凭据，询问它在不需要其他人员、其他身份或物理上独立的控制平面的情况下能做什么。如果它可以执行以下任一操作，就对恢复系统拥有过多影响力：

- 永久删除恢复点或对象版本。
- 缩短保留期限、绕过保留策略或移除保留锁定。
- 停用复制或重定向未来副本。
- 更改加密访问权限，导致恢复失败。
- 删除备份保险库、项目、账户或存储容器。

棘手之处在于，代理可能从未收到过明确的删除备份指令。模型可能选择权限过宽的清理命令，工具封装层可能把听起来无害的操作映射到破坏性端点，遭入侵的代码仓库也可能诱导代理使用它现有的任何凭据。保护措施必须在请求错误时仍然有效，而不能只在提示合理时有效。

需要控制两种不同的影响范围。第一种是数据平面损害，代理修改或删除业务数据。第二种是恢复平面损害，代理删除副本、关闭访问副本的路径，或让副本无法解密。大多数团队会投入精力保护前者，却把后者留在同一个管理员角色中。

这种决定通常源于便利。保留策略清理需要删除过期备份的权限，所以备份任务获得了广泛的删除权限。恢复测试需要高权限角色，所以同一个集成也获得了它。工程师希望 CI 中只保存一个密钥，于是这个角色不断聚集各种权限。每个捷径都可以理解，但合在一起，就让日常自动化凭据掌控了恢复的最后一道防线。

## 写入备份和管理备份生命周期是两项不同的工作

备份写入者需要一条范围狭窄且可重复的路径。保留策略管理员需要修改或删除副本的权限。恢复操作员需要读取选定副本，并将其引入受控目标的权限。把这三类工作当成一项工作，备份身份就会变得危险。

可以将操作分成四类：

1. **捕获**读取指定的生产数据源，并创建新的恢复工件。
2. **存放**将工件写入一个明确的目标，同时设置所需的保留属性。
3. **恢复**读取选定工件，并且只能将其恢复到允许的目标。
4. **管理**修改保留期限、保留锁定、保险库设置、复制、加密访问权限或删除规则。

捕获和存放通常可以无人值守。恢复通常需要新的审批，因为它可能把大量敏感信息移入新的运行环境。管理操作应完全置于代理的日常路径之外，除非是范围严格限定、并且经过单独审批的紧急流程。

不要把清理和捕获混为一谈。自动过期很有用，但这不意味着写入者必须永久拥有删除权限。优先使用由恢复系统或单独的保留策略角色管理的生命周期规则。如果平台强制写入者删除自己的旧副本，只授予它在短期专用暂存区内操作的权限。将完成的副本复制到受保护目标，并确保该写入者无法删除或修改这些副本。

下面是一个常见的故障。数据库代理每小时执行一次导出。它的角色可以写入 `recovery/incoming/`、列出该前缀并删除旧文件。几个月后，存储团队把目标改成了 `recovery/`。原来的前缀限制消失，代理现在可以删除当前恢复数据。任务仍然显示成功，直到有人需要使用副本时，问题才会暴露。

使用能在权限中表达意图的独立名称。`backup-writer`、`backup-retention-admin` 和 `restore-operator` 比一个名为 `backup-service` 的统一角色更清楚。清晰的名称不会强制执行访问控制，但会让审查者更难草率放行。

## 分离的凭据必须对应分离的权限

为同一个宽泛的管理员角色创建两把 API 密钥，没有任何实际帮助。只有当不同凭据对应的权限存在攻击者、损坏的脚本或代理无法合并的差异时，分离凭据才有意义。

先建立一张小型访问地图。写下每个数据源、目标、凭据和破坏性操作，也要包含云账户或订阅信息，而不仅是存储路径。这张地图应回答应用架构图经常遗漏的问题：

- 哪个身份创建副本？
- 哪个身份可以在计划过期前删除已有副本？
- 哪个身份可以缩短保留期限或调用绕过操作？
- 哪个身份可以修改复制、保险库锁定，或恢复所需的加密密钥？
- 哪个身份可以将数据恢复到能够连接生产环境的网络中？

如果三个或更多问题的答案都是同一个服务身份，那么在继续增加自动化之前，先分离这些操作。

一个实用的最低配置可以这样设计：

| 操作 | 身份 | 常驻权限 |
| --- | --- | --- |
| 导出实时数据库 | 生产备份写入者 | 只读取所需数据源，并创建带签名的导出文件 |
| 上传恢复工件 | 恢复存放写入者 | 在一个目标路径中创建新对象 |
| 应用保留策略并删除过期数据 | 保留策略管理员 | 只修改生命周期和保留控制 |
| 恢复选定工件 | 恢复操作员 | 读取选定副本，并写入受限恢复目标 |
| 修改保险库、复制或删除设置 | 恢复管理员 | 执行管理操作，并经过单独的人工审查 |

这些身份起初可以位于同一个供应商中，但必须拥有不同的角色、凭据和审批路径。更好的隔离方式是把受保护目标放在由不同管理团队控制的另一个账户中。更强的隔离还可以使用独立的身份提供商，或使用生产管理员无法静默修改的恢复环境。不要为了等待完美的账户结构，而推迟最初的分离。

如果生产超级管理员随时可以接管恢复管理员角色，独立账户仍然会失效。对于没有其他选择的小型组织，这也许可以接受，但要准确描述它：这是依靠约定实现的管理隔离。它弱于需要不同人员、硬件因素或外部审批才能跨越的边界。

## 不可变性只能阻止一类删除，不能阻止所有恢复失败

不可变存储可以在保留期间保护现有副本不被修改或删除。但它不能证明新副本会持续到达，不能证明副本包含正确数据，也不能证明加密密钥仍然可用，或操作员一定能恢复它们。它是一项重要控制，但不能独自承担整个恢复计划。

CISA 的 StopRansomware 指南建议组织将备份保持离线，并确保备份数据经过加密且不可变。这项建议很合理，因为攻击者进入生产环境后，通常也会继续攻击备份系统。但不要把这份指南理解为可以把保险库管理员凭据放进操作应用的同一个自动化流程。

Amazon S3 Object Lock 清楚地体现了这种区别。在合规模式下，受保护的对象版本在保留日期之前无法被任何用户覆盖或删除，包括账户根用户。在治理模式下，拥有 `s3:BypassGovernanceRetention` 的调用方可以通过明确发起绕过请求来覆盖保护。Amazon 的文档还指出，对于拥有该权限的调用方，控制台会自动加入相应的绕过标头。

治理模式很有用，尤其是在你还在了解能够承担多长保留期限时。但如果代理凭据拥有绕过权限，它就不再是硬边界。不要因为某个清理任务总是失败，就把 `s3:BypassGovernanceRetention` 交给代理。应改进生命周期设计。

合规保留也有成本：错误的保留期限可能让数据保存得比预期更久，而且无法缩短。应根据恢复要求、法律义务、数据敏感度、成本，以及发现入侵所需的时间来有意识地决定保留期限。照搬其他团队的统一设置不是计划。

版本化对象存储中还有一个陷阱。简单的删除请求可能创建删除标记，而不是永久删除旧对象版本。这样一来，操作员在浏览最新视图时可能会认为恢复已损坏，即使受保护版本仍然存在。恢复流程必须说明如何识别并取回所需版本。事故期间无法找到的不可删除对象，只能算受到部分保护。

## 将破坏性备份控制放到不同的审批之后

日常创建备份应该平淡无奇。新的代理会话可能需要批准使用备份写入凭据，但只要捕获和存放调用被限制在预期的数据源和目标内，就不应要求人员逐次关注。人们很快会习惯批准重复提示，而不再阅读内容。

删除恢复副本、缩短保留期限、更改复制目标、停用保险库锁定、导出解密材料，或恢复到能够连接生产环境的网络，这些破坏性或不可逆操作应采用不同处理方式。它们应停下来等待新的、明确的审批。审批内容应使用通俗语言说明请求的操作，并标明凭据、目标和影响。

不好的审批：`Allow backup operation?`

有用的审批：`Allow backup-retention-admin to remove 14 expired recovery points from archive-vault? This action cannot be reversed for copies not under immutable retention.`

措辞很重要，因为它能让审查者拒绝技术上已获授权、但在运维上错误的请求。当生产代理突然请求修改恢复保险库时，异常应该在任何人还没来得及解读 IAM 操作名称之前就显现出来。

审批不能替代权限控制。审查者可能批准错误的请求，尤其是在凌晨两点、告警已经占满屏幕的时候。权限边界必须让普通写入者无法执行危险操作，审批只处理那些仍然有意保留、确实可能执行的少数操作。

当编程代理需要调用备份 API 或运行基于 SSH 的备份任务时，Sallyport 可以采用这种模式：将凭据保存在应用保险库中，普通会话只能使用写入凭据，并将恢复管理凭据设为每次使用都需审批。代理获得的是操作结果，而不是秘密本身。

这种安排也适用于长时间运行的代理。不要批准一次进程，就假定它之后的每个操作都值得同样的信任。新进程应建立自己的会话。即使进程已经拥有日常备份访问权限，敏感凭据也应要求每次调用都获得同意。

## 策略片段应该让错误调用根本无法成功

测试那些你绝不希望成功的请求，可以让权限审查清楚得多。下面的示例展示一种 S3 风格的存放角色。它只能在指定前缀下放置新对象，没有 `DeleteObject`、保留策略绕过、存储桶策略管理权限，也不能读取归档。

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "WriteNewRecoveryArtifacts",
      "Effect": "Allow",
      "Action": ["s3:PutObject"],
      "Resource": "arn:aws:s3:::recovery-archive-prod/incoming/database/*"
    },
    {
      "Sid": "DenyRecoveryAdministration",
      "Effect": "Deny",
      "Action": [
        "s3:DeleteObject",
        "s3:DeleteObjectVersion",
        "s3:BypassGovernanceRetention",
        "s3:PutObjectRetention",
        "s3:PutObjectLegalHold",
        "s3:PutBucketPolicy",
        "s3:DeleteBucket"
      ],
      "Resource": "*"
    }
  ]
}
```

这是一个结构示例，不要直接复制到生产策略中。真实部署可能需要加密标头、分段上传操作、存储桶限制，或为复制服务设置单独角色。重点是，任何读者都不应猜测这个身份能否删除恢复工件，答案应该清楚可见。

每次修改权限后都要运行反向测试。启用存放凭据后，删除操作应失败，并且日志能够记录失败原因：

```sh
aws s3api delete-object \\
  --bucket recovery-archive-prod \\
  --key incoming/database/2026-07-22/backup.sql.zst
```

健康的结果类似这样：

```text
An error occurred (AccessDenied) when calling the DeleteObject operation:
User is not authorized to perform: s3:DeleteObject on resource:
arn:aws:s3:::recovery-archive-prod/incoming/database/2026-07-22/backup.sql.zst
```

然后测试该角色应该执行的操作。上传一个无害的金丝雀工件，确认其保留设置符合预期，并确认代理之后无法修改这些设置。没有通过反向测试的权限设计仍然只是图纸。

不要为了“紧急情况”把保留策略管理员凭据放在写入凭据旁边。紧急情况最容易让人承受不住压力，转而使用宽泛的秘密。将该凭据保存在独立存储中，并要求单独的审批路径或第二名操作员。

## 即使删除被阻止，恢复仍可能泄露数据

团队通常把恢复描述成安全的数据流向。它确实比删除备份安全，但仍然是一项高权限操作。将客户数据库恢复到临时开发环境，可能暴露生产秘密、个人数据、支付记录或内部令牌。将镜像恢复到与生产互通的网络中，也可能引入过期凭据和不安全服务。

恢复操作需要适合被恢复系统的约束。至少应指定源恢复点、目标账户或项目、目标网络和预期访问组。如果平台支持恢复沙箱，就使用它。如果不支持，就建立一个默认无法连接生产环境、并设有出站控制的受限目标。

恢复审批还应与备份审批分开，因为恢复操作员可能需要读取受保护数据，而备份写入者不应拥有这种权限。读取权限可能比写入权限更敏感。导出任务可以生成加密数据，却从未接触明文。恢复任务则通常会将明文实际呈现出来。

一次好的恢复演练不应只回答“命令是否执行完成”。还应检查：

- 选定的时间点是否符合事故场景。
- 是否能使用预期的恢复身份解密工件。
- 应用是否以隔离配置启动。
- 预期记录和架构是否出现。
- 临时恢复环境是否被销毁，或是否按照独立的访问规则保留。

不要只针对昨天最容易恢复的副本进行演练。选择更早的恢复点、不同的数据源，以及必须有意识地选择对象版本或加密密钥的情况。困难的恢复最能告诉你，运行手册描述的是否是真实情况。

## 故障路径通常从一个无害请求开始

设想一个能够访问生产数据库和云服务商 CLI 的编程代理。它收到请求，要在测试环境积累了旧导出文件后降低存储成本。代理列出一个宽泛的存储前缀，找出大对象并提交删除命令。工程师本意是清理暂存文件，但由于通配符方便，这个凭据同时触及了暂存区和归档区。

如果归档使用普通版本控制，这个命令可能添加删除标记，让当前副本从普通列表中消失。如果归档使用治理保留，而凭据又包含绕过权限，请求可能直接删除对象版本。如果使用合规保留，删除请求会失败，这正是你希望看到的失败方式。

现在只改变凭据设计。代理可以使用测试路径的暂存清理凭据，也可以使用只允许写入新归档的存放凭据。两套凭据都不能列出或删除受保护的恢复对象。请求会在变成事故之前失败。之后，恢复管理员可以通过单独审批检查成本问题，并决定是否需要调整生命周期规则。

这就是宽泛存储凭据比看上去更糟的原因。命令本身可能很普通，破坏性结果来自一个跨越了任务根本不需要跨越的边界的身份。

同时保存允许和拒绝的恢复操作审计记录。被拒绝的记录证明控制措施确实触发了，被允许的记录则说明哪个进程使用了哪个凭据、触碰了什么内容，以及发生在什么时候。Sallyport 的会话日志和活动日志可以提供这两个层次的证据，`sp audit verify` 还能在离线、无法访问保险库的情况下检查哈希链。事故之后，这一点很有用，因为一份写着“成功”的备份报告无法解释可疑的管理请求。

## 备份报告应展示权限，而不只是成功与否

大多数备份面板会回答任务是否完成，以及复制了多少数据。再增加一个视图：哪个权限执行了更改、尝试了什么操作，以及系统是否接受了操作。当所有报告都把授权压缩成绿色或红色的任务标记时，恢复安全问题很容易悄无声息地发生。

每次备份运行都记录数据源标识符、目标标识符、工件版本或恢复点 ID、凭据类别、保留状态和结果。对于每次被拒绝的操作，记录足够调查的上下文，但不要保存秘密或敏感载荷。记录应能区分完整备份与上传失败、常规生命周期过期与手动删除，以及被阻止的破坏性调用与需要审查的权限缺失。

不要仅仅为了让代理生成详细报告，就授予它对恢复存储的广泛读取权限。许多供应商提供元数据端点、清单报告或范围更窄的状态调用。如果代理必须读取清单，就单独写入一份只包含标识符、校验和、捕获时间和保留状态的清单，不要生成客户数据目录。

每周可以询问四个问题：

1. 每个预期数据源是否都创建了可恢复工件？
2. 是否有身份尝试修改保留、删除或复制设置？
3. 当前写入凭据能否访问恢复管理操作？
4. 恢复演练是否证明选定的旧副本可以在隔离环境中启动应用？

如果团队无法从记录中回答这些问题，就先改进记录，再假定备份设计有效。

## 在进一步自动化之前，先建立边界

从代理或 CI 任务已经持有的凭据开始。删除它删除恢复副本、绕过保留策略、修改保留锁定、修改复制、调整保险库设置以及管理恢复账户的能力。然后创建一个存放身份，只允许它在应该写入的地方写入。这个改变就能关闭一条常见路径，避免错误指令演变为不可逆损害。

接下来，将生命周期和保留控制移到独立的管理身份中。为组织能够承担的恢复窗口设置不可变保留。将恢复放入受限目标，并要求在敏感数据重新出现在正常运行环境之外之前进行明确审批。最后，运行一次同时尝试预期备份和禁止删除的演练。

当代理可以创建恢复副本，却没有摧毁恢复副本的权限时，你的备份设计才真正适合代理。在此之前，自动化只会让同一个错误发生得更快。
