使用 macOS MDM 部署本地代理网关
使用签名软件包、用户会话启动、更新环、本地保险库和安全退役流程,通过 macOS MDM 部署本地代理网关。

本地代理网关应像安全敏感的桌面应用一样部署,而不是像共享秘密分发系统一样部署。MDM 负责签名应用、应用版本、启动状态和移除操作。开发者负责将凭据放入本地保险库,并负责允许代理使用这些凭据的审批。
这不仅是管理上的整洁划分。当 IT 通过 MDM 推送 API 密钥时,管理平面、清单导出、部署脚本或配置描述文件一旦遭到入侵,都可能导致秘密泄露。当代理直接收到密钥时,每条日志、工具转录、Shell 历史记录和提示边界都会成为秘密的攻击面。网关的作用就是让凭据远离代理进程。部署时不要破坏这一设计。
对于一批受管理的 Mac,我会采用这样的运行模式:分发一个可验证的应用包,在正确的用户上下文中启动应用,让版本通过不同更新环逐步发布,让每位开发者在本地注册自己的凭据,并通过先移除访问权限、再擦除硬件的顺序退役设备。
MDM 应分发网关,而不是开发者的权限
MDM 应知道哪台 Mac 安装了获批应用,以及运行的是哪个版本。它不应成为个人 API 令牌、SSH 私钥或粘贴进来的凭据文件的保险库。
人们常常把两个不同的东西混在一起,因为它们都被称为“配置”。安装应用是设备群配置。授予某个人或某个代理调用生产 API 的权限,则是委派权限。前者属于 MDM,后者属于本地的、由用户控制并具有明确审批边界的保险库。
这一点会直接影响入职流程。MDM 工作流可以在开发者打开编辑器前安装网关。开发者首次运行时,仍必须创建或解锁自己的保险库,并只添加获授权使用的凭据。IT 可以记录获批的凭据类型和所需的服务账户,但不应收集秘密内容,之后再把它们推送出去。
这也让离职流程更可靠。移除受管理应用,并不会撤销几个月前被复制到配置文件中的云令牌。本地保险库允许用户直接移除凭据,服务所有者也可以在令牌来源处撤销它。这样就有两种相互独立的终止访问方式,而不是依赖一个脆弱的清理脚本。
对于 Sallyport,这种划分是有意设计的:应用会把 API 密钥和 SSH 密钥保存在加密的本地保险库中,并自行执行 HTTP 或 SSH 操作,而不是把凭据传给连接的代理。部署设计应保留这一特性。
合理的网关 MDM 记录只包含运行信息:
- 设备序列号或管理标识符
- 分配的部署环和应用版本
- 软件包收据和安装结果
- 主要支持负责人和例外期限
- 应用是必需、可选还是等待移除
不要把秘密名称、令牌值、私钥路径或审批历史加入清单字段。这些细节要么会暴露敏感上下文,要么会造成一种误解,让人以为 MDM 能够重建用户的工作访问权限。
软件包就是部署契约
签名的安装包是让设备群部署可重复的构件。在聊天中传来传去的磁盘映像、解压到 Downloads 的 zip 文件,或把应用包复制到 /Applications 的脚本,都不是部署契约。
Apple 的部署文档指出,通过设备管理安装的软件包必须带有设备能够验证的签名。文档还建议使用自包含应用,这样普通应用部署就不需要自定义安装脚本。这条建议很适合这里。脚本会增加失败路径,以令人困惑的权限运行,而且应用布局改变后往往还会长期存在。
每个发布版本都构建一个发布构件。为它设置带版本号的文件名,在发布记录中保留校验和,并要求所有更新环使用同一个软件包。更新环应该测试同一个构建版本的暴露范围,而不是为每个群组组装一个无法追溯的变体。
将软件包上传到 MDM 前,应在一台干净的测试 Mac 上同时验证软件包和已安装应用。以下命令可以作为最低限度的检查:
pkgutil --check-signature Sallyport.pkg
spctl -a -vv -t install Sallyport.pkg
第一条命令应识别出已签名的安装程序和有效的签名链。第二条命令应评估该软件包是否适合安装。部署后还要检查应用包:
codesign --verify --deep --strict --verbose=2 /Applications/Sallyport.app
spctl -a -vv /Applications/Sallyport.app
不要把 MDM 显示为绿色状态当作正确二进制文件已经可用的证明。MDM 可能会报告软件包已安装,但后续的登录项、后台助手、权限配置或用户会话要求仍可能阻止应用正常工作。软件包验证和功能测试回答的是不同问题。
让软件包保持简单。它应将应用安装到预期位置,避免在 postinstall 阶段下载第二个可执行文件,也不要写入凭据或每个用户的设置。如果软件包需要复杂的 postinstall 脚本才能让产品正常工作,就应该停下来检查应用设计或打包边界是否有问题。每次 macOS 升级和每次事件响应复盘,你都会为这段脚本付出代价。
已安装的应用应当能够像应用一样被移除,而不是需要一次取证式清理。Apple 指出,通过软件包放入 /Applications 的应用包可以由设备管理服务管理并单独移除。这也是避免把核心文件散落到任意目录中的原因之一。
在开发者会话中启动应用
需要本地审批或访问用户受保护保险库的网关,必须在已登录用户的上下文中运行。root 守护进程无法替代这个上下文。
团队在这里经常犯一个可预见的错误。他们看到“始终运行”,便选择 LaunchDaemon,因为它可以在登录前运行,并且用户退出登录后仍然存活。随后他们发现,守护进程无法真实地显示用户审批提示,无法使用预期的用户钥匙串或生物识别授权路径,而且获得了超出任务需要的权限。
Apple 清楚地划分了边界。登录项在用户登录时启动,并在该用户的会话中运行。LaunchAgent 也为已登录用户运行。LaunchDaemon 在系统级别运行,可以在登录前启动,并以 root 身份运行。Apple 还说明,对于应在用户会话期间保持活动状态的面向用户应用,登录项是合适的选择。
对于菜单栏网关,通常应选择受管理的登录项,或应用自身支持的登录项机制。它应在用户进入桌面后启动,并保持足够的可见性,让开发者知道它正在运行,用户退出登录时则停止。不要把安全边界隐藏在用户无法检查或退出的进程中。
如果 MDM 需要强制执行启动行为,应使用 Apple 的受管理登录项负载,而不是编写一个由脚本复制的 plist。com.apple.loginitems.managed 负载可以指定应用路径以及应用是否隐藏。Apple 的设备管理参考文档提供了负载结构,并支持在 macOS 上使用它。
下面是一个代表性负载。将标识符和路径替换为你自己发布的值,然后通过常用的描述文件工具生成 UUID。
<dict>
<key>PayloadType</key>
<string>com.apple.loginitems.managed</string>
<key>PayloadIdentifier</key>
<string>dev.example.agent-gateway.login-item</string>
<key>PayloadUUID</key>
<string>REPLACE-WITH-UUID</string>
<key>PayloadVersion</key>
<integer>1</integer>
<key>AutoLaunchedApplicationDictionary-managed</key>
<array>
<dict>
<key>Path</key>
<string>/Applications/Sallyport.app</string>
<key>Hide</key>
<false/>
</dict>
</array>
</dict>
它能避免一种平常却代价高昂的故障:软件包安装了,应用出现在 /Applications 中,开发者以为网关正在保护代理。实际上,应用登录后从未启动,因此 MCP shim 无法完成请求,或者用户根本看不到审批卡片。入职检查必须测试真实的用户登录,而不能只测试 MDM 代理下的安装。
LaunchDaemon 仍有合理用途,但不要让它进入保险库路径。只有当你能说明任务为什么必须在没有图形界面的会话中运行,以及为什么需要 root 权限时,才使用它。“我们想让它更可靠”不是答案。用户会话中的应用同样可以可靠运行,不必假装自己是机器服务。
更新环应测试真实的开发工作
当每个更新环都回答不同的运行问题时,更新环才有用。当它们变成一种永远礼貌地推迟更新的方式时,就失效了。
先建立一个小型内部环。让负责打包应用、维护 MDM 配置和排查开发者工作站问题的人员加入其中。他们的任务是发现安装失败、启动行为异常、意外的权限提示,以及从上一生产版本升级时的问题。
下一个环应包括使用不同工具和访问方式的开发者。加入通过代理使用 HTTP API 的人、使用 SSH 的人、经常切换网络的人,以及使用普通受管理账户而非本地管理员权限的人。你要寻找的是实际使用中的差异,而不是一群会原谅所有粗糙体验的爱好者。
生产环是版本成为默认版本的阶段。只针对明确原因保留一个小型紧急保留组,并指定负责人和到期日期。“这个人很忙”不是部署政策。它只会让不受支持的版本永久存在。
把发布当作状态机,而不是日历仪式:
- 在内部环安装签名软件包,并确认软件包和应用都通过评估。
- 让每位测试用户退出登录再重新登录,然后确认网关在其会话中启动。
- 通过代理路径执行无害的真实操作,如果这些通道在范围内,则分别执行一次 HTTP 请求和一次 SSH 命令。
- 在审查失败、支持工单和回滚需求后,将同一个软件包推进到试点环。
- 只有在上一版本的升级路径正常后,才推广到生产,而不是只验证全新安装。
不要把成功定义为“MDM 控制台显示已安装”。应将成功定义为一系列可观察事件:软件包收据存在,签名应用通过评估,应用在登录后启动,开发者可以解锁自己的保险库,代理能够连接本地 shim,并且获准的操作可以返回结果。
在发布前明确回滚方式。对于普通应用更新,回滚应意味着重新部署之前的签名软件包,恢复之前的必需版本分配,并检查旧应用能否安全读取本地状态。它不应意味着让开发者在文件夹之间拖动应用,同时由支持人员猜测他们安装了哪个构建版本。
Apple 的声明式应用和软件包管理可以在受支持的受监管 Mac 上将软件包定义为必需或可选,声明式应用管理会优先于重叠的安装命令。不要向同一个目标发送两种管理机制,然后希望设备选择你想要的那一种。在每个更新环中选择控制方法,并记录下来。
独立保险库会改变入职和恢复流程
每位开发者使用独立保险库,会让首次运行成为一次安全流程,而不是自动化缺陷。用户必须决定哪些凭据属于这台 Mac,设备也必须证明用户能够解锁这些凭据。
这正是重点。本地代理网关可以接收 Claude Code 或其他支持 MCP 的代理发来的请求,但代理不应收到明文凭据,也不应收到日后可以滥用的伪占位符。网关应执行 HTTP 或 SSH 操作,然后返回结果。
在 Sallyport 中,固定的决策阶梯很有用,因为它避免了让每个团队都必须学习和审计一套策略语言。锁定的保险库会拒绝所有操作。新的代理进程默认获得会话授权,标记为每次调用审批的凭据则会在每次使用时请求批准。这些控制解决的是不同问题,应训练开发者在不同情境下分别使用它们。
当笔记本无人看管或开发者完成工作后,使用保险库门控。使用会话授权来识别新启动的代理运行,然后再给予它较大的操作空间。对于每次使用都值得人工关注的凭据,例如生产管理令牌或敏感 SSH 身份,使用每次调用审批。
不要因为听起来更安全,就要求开发者把所有凭据都设置为每次调用审批。反复出现的提示会让人习惯于不阅读就批准。应把阻力放在错误请求会造成实际影响的地方,让普通的低风险开发凭据处于会话级边界之下。审批疲劳是设计失败,不是团队重视安全的证据。
恢复流程同样需要清晰的边界。IT 可以重新安装网关应用,并修复其受管理的启动状态。IT 不能也不应从 MDM 记录中恢复开发者保险库的内容。如果 Mac 被替换,开发者应通过源系统获取新凭据,或遵循组织批准的凭据迁移流程。这可能不方便,但仍比把设备群管理数据库当成生产令牌的备份保险库更安全。
部署前记录所有权表:
| 事件 | 开发者 | IT 或终端团队 | 服务所有者 |
|---|---|---|---|
| 新 Mac 设置 | 解锁保险库并添加获授权凭据 | 安装应用和登录配置 | 授予初始凭据 |
| 代理行为异常 | 撤销会话并锁定保险库 | 确认设备和应用状态 | 必要时撤销凭据 |
| 应用更新失败 | 报告可见行为和版本 | 修复软件包分配或回滚 | 通常无需操作 |
| 设备更换 | 获取新凭据或执行获批迁移 | 退役旧 Mac 并部署新设备 | 轮换或重新签发访问权限 |
这张表能避免发布过程中最糟糕的支持电话:开发者说“我的代理失去访问了”,终端支持说“应用已经安装”,服务所有者则以为别人已经恢复了某个秘密,而实际上从来没有人应该拥有它。
清单和操作证据回答的是不同问题
MDM 清单告诉你受管理应用是否到达设备。它无法说明安装后 AI 代理请求了什么、哪项权限获得了批准,或哪个 API 调用实际运行。
保留两类记录,并在需要时将它们关联起来。MDM 记录应提供硬件身份、管理状态、分配的应用版本、安装时间戳和移除状态。网关的审计轨迹应提供会话、单个操作和验证结果。如果把它们合并到一张表格中,你要么会向终端工作人员暴露过多运行细节,要么会让事件响应人员缺少所需证据。
Sallyport 会在 Sessions 日志中记录代理运行,在 Activity 日志中记录单个操作,两者都从同一份加密哈希链审计日志中生成。它的 sp audit verify 命令可以对密文离线检查哈希链,不需要保险库密钥。这意味着调查人员可以检查记录是否被篡改,而无需打开用户的秘密。
发生事件或进行发布复盘时,可以采用简单的收集流程:
sp audit verify
有用的结果应当先清楚显示通过或失败状态,然后显示检查范围,例如:
Audit chain: valid
Records checked: 184
First record: 2026-07-01T14:22:09Z
Last record: 2026-07-22T09:15:44Z
具体字段取决于已安装的命令版本,因此应将原始输出与应用版本和设备标识符一起保存。不要因为正在收集审计结果,就复制开发者的保险库内容、代理提示转录或无关的终端历史记录。
这种分离也能改善日常支持。如果 MDM 控制台显示预期版本,但开发者说某个操作被拒绝,应检查网关的本地状态和审批路径。如果审计记录显示某个操作已经执行,但 MDM 没有当前安装记录,应调查过期的设备记录、最近退役的 Mac 或未受管理的安装。每个系统都有明确的工作范围,让它把自己的工作做好。
设备退役应先处理访问,再擦除设备
当 Mac 易主、丢失或离开公司时,应在擦除设备或解除组织所有权之前结束它的访问关系。擦除可以清理磁盘,却不能证明云凭据、活动代理会话或设备分配已经得到正确处理。
对于正常的公司设备返还,应按以下顺序操作:
- 确认设备、最后一位分配用户、MDM 记录,以及设备是否仍在回连。
- 撤销活动网关会话,并让服务所有者轮换或撤销可能在其他地方仍然有效的凭据。
- 移除受管理应用;如果 Mac 仍在线并能接收命令,也可以将其标记为待移除。
- 按照保留规则保存最低限度的管理和审计证据。
- 通过组织批准的返还或重新分配流程擦除 Mac。
不要仅仅因为员工离职,就将 Mac 从 Apple Business Manager 中释放。释放是硬件所有权的决定,适用于已经出售、无法找回,或不再归组织控制的设备。Apple 警告说,释放操作无法通过通常的分配路径撤销,会阻止设备今后再次分配给 MDM,并且释放后必须擦除并恢复设备。Apple 还警告,不要释放送去维修的设备,因为替换设备可能无法回到 Apple Business Manager。
对于重新分配的公司 Mac,应保留组织注册状态,擦除设备,然后通过标准流程为下一位用户注册。对于采用用户注册模式的个人设备,应按照约定的政策移除管理,确认哪些受管理应用和设置会消失,并让开发者在交接前移除自己的凭据。Apple 指出,对于用户注册的设备,取消注册可能会移除受管理应用和内容,而个人应用和设置仍会保留。
丢失的 Mac 需要更快的处理分支。先撤销凭据和会话,因为设备可能永远不会重新上线。然后使用设备管理控制以及服务所有者的撤销流程。等待应用移除命令送达并不等于完成遏制。
成功的发布应该平淡无奇
最好的本地网关发布不会引发太多波澜,因为每条边界都很清楚。MDM 团队交付签名应用并控制其生命周期。开发者将凭据保存在本地保险库中,并能看到代理何时请求权限。服务所有者在源头授予和撤销访问。审计轨迹记录操作,但不会变成秘密倾倒区。
从最能暴露错误假设的测试开始:注册一台干净的受管理 Mac,以普通开发者身份登录,通过 MDM 安装生产软件包,退出登录再重新登录,在本地添加一个非关键凭据,执行一次无害的代理操作,验证其审计记录,然后移除应用,并从全新注册状态重复整个流程。如果这套流程需要未记录的人工操作、隐藏的 root 脚本或复制的凭据文件,就应在增加一百台设备之前修好发布流程。
常见问题
MDM 应该把 API 密钥部署到本地代理网关吗?
MDM 应安装、更新和移除签名的网关应用,并报告预期版本是否存在。它不应分发开发者 API 令牌或 SSH 私钥。每位开发者都应在应用以自己的登录账户运行后,在本地添加凭据。
部署 macOS 代理网关时,需要签名的软件包吗?
签名的安装包让 MDM 能够验证软件包,并以一致的方式进行部署。安装后,应用包也应通过 Gatekeeper 检查。签名不能替代测试,但它能阻止 IT 把随意分发的磁盘映像或复制的应用包当成生产构件。
代理网关应该使用登录项还是 LaunchDaemon?
当应用需要在开发者的图形界面会话中运行,并显示本地审批界面时,应使用受管理的登录项。只有在任务确实必须在登录前或任何用户会话之外运行时,才使用 LaunchDaemon。依赖用户本地授权的凭据保险库应放在用户会话中。
macOS 开发者工具的更新环应该如何运作?
先从内部环开始,让能够识别开发者工作流故障并清楚报告问题的人员参与。然后将同一个签名构建版本推进到更大的试点环,审查安装结果、启动行为和更新影响后,再推广到全体用户。不要让更新环变成永久不更新的借口。
为什么每位开发者都应把凭据保存在独立的本地保险库中?
本地保险库将秘密保留在开发者的 Mac 上,并让网关执行操作,而不把凭据交给代理进程。这种隔离能降低提示注入或代理工作区遭入侵后的影响,也意味着 IT 无法仅靠重新安装应用来恢复某个人的秘密。
如何验证本地网关部署确实有效?
重新安装应用只能证明二进制文件存在。它不能证明开发者的保险库已解锁、会话能够接收审批、代理能够连接本地 MCP shim,或允许的 API 和 SSH 调用能够返回预期结果。应使用无害的端点或主机测试完整链路。
Mac 退役时,本地代理网关应该怎么处理?
应先处理网关访问:在可能的情况下撤销活动会话,移除受管理访问,并记录设备与用户的关系。然后按照组织的返还流程擦除 Mac。将公司 Mac 从 Apple Business Manager 中释放是独立的所有权操作,只有在组织确实放弃对该硬件的控制时才应执行。
IT 应为代理网关部署保留哪些记录?
在 MDM 清单中保留网关应用版本、软件包收据、签名身份、部署环、设备标识符和支持负责人。在网关自己的审计记录中保留操作级证据。将两类记录关联起来后,你既能回答“安装了什么软件”,也能回答“代理做了什么”,而不必假装它们是同一份记录。
开发者可以不等 IT 介入就撤销访问吗?
开发者应能够移除不再需要的凭据,并在代理行为异常时立即撤销会话。IT 应能够移除受管理应用,或阻止设备继续使用受管理访问。这些控制解决的是不同问题,因此两者都应保留。