# Migration Assistant 代理保险库需要冷启动

当自主代理可以访问 API 和 SSH 主机时，Mac 传输就不是一次无害的搬家。它会创建一台新机器、一条新的硬件安全边界、一组新的运行进程，也带来一个新的时刻：有人必须决定哪些权限仍然值得保留。如果代理只是因为桌面看起来熟悉就重新获得外部访问权限，那么迁移漏掉了最关键的一步。

Migration Assistant 可以从另一台 Mac、PC 或备份中传输文档、应用、用户账户和设置。这有助于你尽快恢复工作，但它并不表示源机器上的所有安全属性都应该保留下来。Apple 明确说明，Secure Enclave 密钥以及标记为 `ThisDeviceOnly` 的钥匙串项目不会迁移到另一台设备。

安全的操作原则很简单：迁移有助于调查和重建的内容，然后在任何代理使用凭据或打开远程会话前，要求新的证明。传输后打不开的保险库，可能正是在履行你赋予它的职责。

## 迁移后的 Mac 是新的终端

新 Mac 可能拥有相同的用户名、相同的主目录路径、相同的应用，以及相同的项目副本。但这些事实都不能让它成为同一个安全终端。处理器、Secure Enclave、生物识别注册、磁盘加密环境、已安装的系统状态、网络连接方式和本地进程历史都已经改变。

团队经常做出错误的比较。他们会问目标机器上是否有相同的文件，却应该问：目标机器能否证明自己拥有相同的权限，同时不复制那些原本只应留在本地的权限？当保险库使用设备绑定保护时，这两个目标彼此冲突。

Apple 的安全文档清楚地划出了界线。Secure Enclave 私钥是在 enclave 内部创建的，不能导入已有私钥，也只能由创建它的 enclave 使用。Apple 还说明，使用 `kSecAttrAccessibleWhenUnlockedThisDeviceOnly` 的钥匙串项目不会迁移到新设备。

匆忙更换笔记本电脑时，这种行为可能让人觉得不方便。但它阻止了复制的应用容器、备份或迁移数据变成可随处携带的外部访问令牌。不要通过把密钥导出到备忘录文件、环境变量、Shell 历史或普通密码管理器条目的方式绕过失败。这样做会用一个可以传播得远超旧笔记本的文件，替代原本有意设置的硬件边界。

在使用 Migration Assistant 前，先确定切换规则：

- 在目标机通过测试前，旧 Mac 仍是现有访问权限的权威来源。
- 新 Mac 启动时应阻止代理运行，或断开其与生产凭据的连接。
- 迁移过来的文件是待检查的证据，不是可以行动的许可。
- 每个审批和每个凭据绑定都需要一个明确的预期结果。

即使大部分应用数据都复制成功，这仍然是一次受控的重新注册。把它称作传输，并不会减少安全工作。

## 四种状态会以不同方式失败

应用数据、审批、审计记录和凭据绑定经常存放在相近的位置，但不应被视为同一个东西。它们回答的是不同问题，迁移对每一类状态也可能产生不同结果。

**应用数据**是普通的本地状态：偏好设置、端点定义、标签、非机密元数据，以及可能存在的加密保险库数据。它可能完整迁移。它的存在只能说明复制操作找到了这些内容。

**审批**是针对特定代理进程、具有时间范围的决定。它回答的是：「这个进程可以在本次运行期间执行操作吗？」迁移后，即使本地数据库中仍能看到旧审批，它也不应授权新 Mac 上的进程。新进程拥有新的父进程链、新的可执行文件位置、新的环境，签名状态也可能发生变化。

**审计记录**是对已发生事件的证据。如果迁移保留了相关加密文件，它们可以并且应该继续存在。但它们必须保留顺序和完整性属性，不能只是还能在日志视图中显示。

**凭据绑定**回答的是：目标硬件能否使用包裹机密的加密保护。加密数据块可能被复制，但本地解包能力未必会随之转移。这是许多谨慎的工程师也容易混淆的区别：有密文，不等于有凭据使用权。

在传输前，把这四种状态写入迁移工作表。不要只记录「保险库已迁移」这种模糊结果，而要分别记录每种状态：

| 状态 | 成功表现 | 失败表现 | 切换决定 |
| --- | --- | --- | --- |
| 应用数据 | 预期设置和非机密元数据都在 | 配置缺失或出现意外改变 | 在测试访问前恢复或重建设置 |
| 审批 | 新代理进程再次发起请求 | 因旧记录而直接执行操作 | 在任何外部调用前停止并调查 |
| 审计记录 | 历史条目存在，完整性验证成功 | 条目缺失、顺序改变或验证失败 | 保留两份记录，不要删除源记录 |
| 凭据绑定 | 目标机要求自己的本地解锁，然后按设计运行 | 没有预期的本地门控，密钥却悄悄变得可用 | 在解释清楚前，将其视为安全缺陷 |

最棘手的情况是部分成功。应用能启动，设置显示出来，旧审计历史也在，但保险库无法解锁。这不是迁移失败，而是迁移保留了证据和配置，同时拒绝转移设备绑定的权限。接受这个结果，然后重新注册凭据。

## 在复制任何内容前冻结代理访问

不要从 Migration Assistant 开始。先确保在你还不确定哪台 Mac 持有权限时，没有代理能够发出请求。

第一步，停止源 Mac 上正在运行的代理。如果代理由终端复用器、编辑器扩展、后台任务或类似 CI 的本地启动器管理，请停止每个入口。关闭启动它们的终端会话。窗口退出并不能证明子进程已经结束。

第二步，在应用外记录源状态。记录日期和时间、源 Mac 的序列号或内部资产标识、用户账户、当时运行的代理进程，以及代理可以联系的远程系统名称。不要把密钥写入这份记录。你需要的是能解释后续证据的时间线，而不是另一份保险库。

第三步，在第一次受控测试前，让目标机断开重要网络。这可能意味着在初始设置阶段移除生产 VPN 配置、拒绝某条防火墙规则，或者在本地检查完成前让新 Mac 完全离线。无法访问外部 API 的笔记本电脑，不会因为旧授权被接受而意外证明什么。

第四步，决定谁有权接受新的审批。这一点比团队承认的更加重要。迁移常常发生在有人设置新机器、恢复备份或修复受损笔记本的同时。点击审批卡片的人应该知道要审批的是哪个代理二进制文件，以及它为什么需要这项能力。

可以使用这样的简短交接记录：

```text
Migration ID: MA-2026-07-22-A
Source endpoint: old Mac asset ID
Destination endpoint: new Mac asset ID
External access state: disabled
Source agent runs: stopped
Source sessions revoked: pending destination verification
First permitted test: disposable read-only API action
Decision owner: named operator
```

其中的日期只是格式示例，不是什么特殊标识符。重要的是，你之后能把源端审计记录的末尾、目标端的第一次审批，以及第一次成功操作关联到同一条切换记录。

## 应用文件可以移动，信任却不会随之移动

分两轮检查应用状态：先检查完整性，再检查权限。不要把两者混在一起。完整性告诉你需要恢复什么，权限则告诉你哪些内容必须拒绝或重建。

传输完成后，在目标机仍无法访问生产服务时启动应用。确认可见配置合理：端点名称、标签、非机密路由信息，以及预期的本地日志视图。趁源 Mac 还在，将这些内容与源机进行比较。如果缺少某个端点，就有意识地重建它。如果出现没人认识的端点，先移除它并查明来源。

然后检查任何可能触发自动操作的状态。例如自动启动的代理集成、会启动连接器的 Shell 配置文件条目、编辑器任务、启动代理、保存的命令模板，以及会重新打开旧会话的应用偏好设置。迁移可能保留对文本编辑器无害、但对能够调用生产 API 的代理很危险的便利设置。

Apple 表示，Migration Assistant 会传输应用、账户、文档和设置。正因为范围如此广，你才需要进行这次检查，不能假定只有个人文件被迁移。

不要把目录存在作为通过条件。安全设计可能会有意迁移加密保险库文件，却把解包材料留在源机。看起来空的保险库也可能是正确结果，因为应用选择不复制本地安全状态。唯一有用的问题是：结果是否符合你预期的设计。

对于 Sallyport，保险库在应用内部加密，保险库门是绝对的。在支持相应硬件路径的 Mac 上，这道门使用 Secure Enclave 和 Touch ID，锁定时所有操作都会被拒绝。因此，复制的保险库数据并不能证明目标机可以使用源 Mac 的权限。

用精确的语言记录每个观察结果。写「加密状态存在，目标端安全门仍保持锁定」，不要写「迁移失败」。写「代理启动器在首次运行前已禁用」，不要写「应该已经停止」。这些细节能防止后续操作员把尚未完成的测试当成成功切换。

## 旧审批不能授权新进程

会话审批和凭据访问是两个独立的控制点。新 Mac 必须按正确顺序通过两者。保险库门决定是否有任何操作可能发生。会话授权决定这次特定的代理运行是否可以发起调用。单次调用要求则决定某个凭据是否每次使用都需要再次获得人工决定。

由于用户看到的只是某个操作成功或失败，这种区别很容易被混淆。迁移期间不要接受这种模糊性，要刻意测试。

只有在目标端保险库处于预期的锁定或解锁状态后，才能启动新的代理进程。让它使用无法修改生产系统的凭据请求一次无害操作。预期的会话结果应是新的审批请求。检查审批界面显示的进程身份和代码签名权限，只批准你实际启动的这次运行。

如果代理进程在目标机上没有新的授权事件就执行了操作，立即停止。不要庆幸传输节省了时间，而应找出授予权限的路径。可能是某个仍在运行的进程、恢复的会话数据库、绕过预期中间层启动的集成，或没有将审批与进程生命周期紧密绑定的审批模型。

Sallyport 的会话授权默认开启。新代理进程的第一次调用会显示审批卡片，并优先展示进程的代码签名权限。一次审批只在本次运行期间有效，进程退出后即失效。因此，新启动的目标端进程正是要求新决定的正确位置。

分别测试单次调用凭据。将一个无害测试凭据设置为每次使用都需要审批，然后在同一个已审批的代理运行中发起两次调用。你应该在每次使用该凭据时都看到一个决定，而会话决定不会因为同一进程继续运行就重复出现。这样可以确认你测试的是会话层还是单次调用层，而不是根据一个弹窗猜测。

一个合理的测试表不需要很大：

| 测试 | 预期观察结果 | 停止条件 |
| --- | --- | --- |
| 新代理运行中的第一次调用 | 出现新的会话审批 | 调用沿用旧审批直接执行 |
| 同一运行中的第二次调用 | 不再出现第二次会话审批 | 没有策略原因却再次出现会话提示 |
| 第一次使用每次审批的凭据 | 出现凭据专属决定 | 凭据被静默使用 |
| 第二次使用该凭据 | 再次出现凭据专属决定 | 第一次决定继续生效 |
| 代理退出并重启 | 再次出现新的会话审批 | 上一次运行仍然拥有权限 |

不要用生产部署来测试这些内容，因为你测试的不只是弹窗。你是在测试新终端是否正确识别进程生命周期和凭据策略。

## 审计历史需要验证，不能只看一眼

包含昨天条目的日志视图很有用，但它不能证明迁移后的记录仍然完整。迁移可能漏掉文件、复制旧快照、在更新过程中中断，或者让你看到缓存的索引。审计证据需要完整性测试。

在目标端执行第一次操作前，保留源 Mac 的状态。记录源端最后的时间戳，以及切换前后预期看到的会话和调用数量。然后比较目标端的历史视图。你要确认的是连续性，而不是屏幕位置或显示顺序完全相同。

Sallyport 从一条只写、加密、哈希链式审计日志中生成 Sessions 和 Activity 日志。它的验证器可以在离线状态下直接对密文检查链条，无需保险库密钥。这样，迁移测试就有了明确的通过或失败标准，而不是要求操作员凭肉眼查看旧操作列表。

如果条件允许，在迁移前先在源端运行验证器，然后在允许任何代理操作前，再在目标端运行一次。保存标准输出和退出代码，不要假定某种特定的消息格式：

```sh
sp audit verify > audit-verify.txt 2>&1
status=$?
printf 'sp audit verify exit=%s\n' "$status"
```

将 `audit-verify.txt` 与迁移记录一起保存，不要放在稍后可能消失的聊天线程中。退出代码为零只有在你同时标明它来自哪台终端以及生成时间时才有意义。如果验证器报告错误或返回非零状态，停止迁移流程。保留源端原样，复制诊断输出，调查传输过程，不要直接开始一份新日志来掩盖断点。

还要区分两件事：迁移后的审计历史证明旧终端记录了什么，目标端活动则证明切换后新终端做了什么。不要在脑中把两者合并。目标端的第一次调用应当易于定位，与新的会话授权关联，并且明显晚于源端最后一次调用。

## 重新注册凭据，不要提取凭据

常见的捷径是从旧 Mac 导出 API 令牌或 SSH 私钥，粘贴到新机器上，然后承诺以后再清理。它之所以流行，是因为见效快。但如果旧设计有意让代理无法接触凭据，并把本地使用绑定到受保护的保险库，这种做法就是错误的。

重新注册会把问题从「如何复制这个密钥」变成「谁应该向这个终端授予新的权限」。这是更健康的问题。你可能需要创建新的 API 令牌、注册新的 SSH 公钥，或从系统所有者那里获得新的凭据。这也会为旧 Mac 建立一个清晰的撤销点。

对于 HTTP 访问，如果远程服务允许，可以创建一个一次性、只读的测试凭据，只授予它访问一个无害资源的权限。让新获审批的代理请求该资源，检查返回结果和本地审计条目，然后按照服务的正常流程撤销测试凭据或等待它过期。

对于 SSH，使用专用测试账户或受限测试主机。第一次命令应当只观察状态，例如打印远程账户身份和当前工作目录。不要用推送代码、发布软件包、执行数据库命令或触发部署来证明第一次成功。这些操作会修改你正试图保护的系统，让排查变得更困难。

需要每次调用审批的凭据在这一阶段尤其有用。它会迫使人工观察外部使用究竟何时开始。目标端通过授权、审计和无害操作测试后，再按照正常的所有权流程重新注册生产凭据。只要远程系统支持这种区分，就应尽快撤销旧凭据或移除旧终端的授权。

不要把 SSH 密钥文件和应该属于新 Mac 的 SSH 身份混为一谈。复制的私钥可能确实可以完成身份验证，但这只能证明服务器接受了相同的加密材料，并不能说明迁移保留了你的本地安全模型。新终端、新身份注册、新审计轨迹。

## 第一次真实操作应该刻意无聊

第一次接近生产环境的操作，应当能告诉你整条链路是否正常，同时不制造清理工作。选择只读、范围限定在无害测试对象上，并且容易在远程日志和本地活动日志中找到的操作。

合适的选择包括读取测试 API 对象的元数据、列出专用的空 SSH 目录，或查询服务当前已认证的身份。不合适的选择包括创建云资源、轮换共享凭据、发布制品、修改代码库设置，以及对真实路径执行带 Shell 展开的命令。

执行一次操作，然后按发生顺序确认以下事项：

1. 请求前，目标端保险库处于预期状态。
2. 新代理进程获得了新的会话授权。
3. 如果单次调用凭据的设置要求审批，它确实请求了审批。
4. 远程系统记录了预期的无害操作。
5. 目标端活动记录与获授权的操作一致。

如果缺少任何一项观察结果，在弄清原因前不要重复操作。重复不透明的测试，通常只会产生一堆几乎相同的记录，却没有解释。一次干净的成功，比五次匆忙重试更有价值。

操作通过后，再一次只启用一个外部访问凭据。不要因为目标机终于可以使用，就在一个下午启用所有保存的端点。生产令牌、基础设施 SSH 身份和个人服务令牌的风险不同，也不应由同一个审批者处理。按照权限从低到高的顺序逐步启用。

## 在证据闭环前保留旧 Mac

不要因为目标端可以成功启动，就立即抹掉或置换源 Mac。让代理保持禁用，并保留源机，直到迁移记录完整，而且你能解释两端的证据。

闭环记录应包含：源端最后一次经过验证的审计状态、目标端第一次经过验证的审计状态、新审批测试的结果、重新注册的凭据、已撤销的凭据，以及授权生产访问的人员。这不是为了做表面上的文书工作，而是为了在日后回答一个问题：某项操作究竟来自旧机器、新机器，还是一次未计划的重叠运行。

接着撤销源端的活动会话。如果存在远程访问白名单，就从中移除源端。替换正常运行后，撤销源端专用令牌和 SSH 注册。最后确认旧终端即使重新联网，也无法仅凭重新上线恢复访问。

最重要的测试不是 Migration Assistant 传输了多少内容，而是目标端是否必须重新赢得外部权限。如果答案是肯定的，新 Mac 就从一条可以自洽的安全边界开始。如果答案是否定的，在准确解释传输过程中到底跨过去了什么、以及为什么之前，不要重新连接代理。
