症状:fastlane match 拉取失败,不要先重建或撤销证书。
最快解法:先区分私有仓库访问、match 加密口令和 Apple 开发者账户校验,再检查 Keychain 签名身份;CI 与无人值守构建优先使用只读模式。

这篇文章适合首次在远程 Mac 配置 fastlane match、签名材料无法读取的独立开发者;也适合需要管理共享签名仓库写入权限的小团队负责人,以及迁移到新 Mac 或 CI 后遇到读取故障的发布维护者。

远程 Mac 首次构建:先定位失败发生在哪一层

错误信息里的“认证失败”不一定指同一套凭据。fastlane match 读取私有仓库时需要仓库访问凭据;仓库中的签名材料还需要 MATCH_PASSWORD 解密;与 Apple 开发者账户交互则是另一条授权路径。把这几种凭据混在一起换,常常只会增加新的故障点。

先看 match 输出停在哪个动作,再在实际执行构建的远程 Mac 用户和终端环境里复现。可用 Git 的只读查询检查仓库是否能返回引用:

git ls-remote "$MATCH_GIT_URL" HEAD

git ls-remote 的作用是显示远程仓库可见的引用。如果这一步报认证或权限错误,先不要改 MATCH_PASSWORD:命令尚未证明当前身份能读取仓库。

如果仓库使用 SSH,可检查当前 SSH 身份:

ssh -T git@github.com

这项检查能确认 SSH 身份是否通过认证,却不能单独证明该身份有权读取目标仓库;还要用上面的只读查询测试实际仓库地址。官方 SSH 测试说明也建议核对连接响应。排查时只使用脱敏地址与输出,不要贴出私钥、令牌、仓库真实路径或未经处理的构建日志。

本机可用、新远程 Mac 失败:核对实际认证身份

本机能拉取而新远程 Mac 失败,通常说明两边使用的账号、密钥、凭据助手或仓库 URL 并不相同。不要只对比项目里的 Matchfile;还要确认远程任务由哪个系统用户启动、该用户加载了哪把 SSH 密钥,或 HTTPS 凭据实际来自哪个秘密存储范围。

  • SSH 仓库:核对远程构建身份加载的密钥是否对应签名仓库的授权。若使用部署密钥,确认目标仓库确实绑定了对应公钥。
  • HTTPS 仓库:核对凭据是否已在构建进程可用的秘密范围内注入,并确认凭据权限覆盖该仓库。不要把个人密码写入 URL 或提交到项目配置。
  • 其他存储后端:检查远程进程实际使用的云端身份、桶或项目授权范围。开发者本机已有权限,并不代表无人值守任务继承了该权限。

场景案例:开发者在自己的 Mac 上用 SSH URL 成功,而新远程 Mac 的任务使用 HTTPS URL。此时,即使两边指向同一个仓库,SSH 密钥也不会替 HTTPS 认证。先统一地址形式,或为该构建身份配置与其地址相匹配的凭据。

修复应只授权给需要读取签名材料的构建身份。不要把私有签名仓库改为公开,也不要把团队成员的个人密码共享给构建机。GitHub 的部署密钥说明列明了只读默认权限及密钥的适用边界;团队撤销人员访问后,也应单独检查仍有效的部署密钥。

仓库可读、材料不能解密:检查 MATCH_PASSWORD

当远程 Git 查询成功、match 已经开始读取签名材料,但随后无法解密,才应把重点转向 match 加密口令。Git 凭据解决的是“能不能读取仓库”;MATCH_PASSWORD 解决的是“能不能解开仓库里的加密文件”。前者成功不能证明后者正确。

按以下顺序检查:

  • 确认运行环境注入的变量名与项目实际读取的名称一致,包括 MATCH_PASSWORD 的拼写和大小写。
  • 确认远程 Mac 或 CI 使用的是该应用、该环境对应的秘密,而不是另一项目或另一发布环境的值。
  • 确认最近是否更换过加密口令,以及执行者使用的口令是否与仓库现存材料一致。
  • 重新运行时避免打印变量内容。不要将口令写进仓库、命令历史、可公开访问的构建日志或调试截图。

在 GitHub Actions 等 CI 中,秘密可能按仓库、环境或组织范围配置;工作流是否能拿到某个秘密,取决于其触发方式与授权范围。查看Actions 秘密的可用范围和限制,确认当前任务实际采用哪一份配置。若秘密没有注入,别用把口令硬编码进工作流的方式绕过。

Apple 账户校验失败:不要误判为仓库故障

仓库读取和材料解密通过后,如果输出转而报告 Apple 开发者账户、团队或 Portal 校验问题,应按账户授权路径检查。核对构建使用的团队身份、相关会话或授权是否仍有效,并确认此任务是否确实需要访问 Apple 开发者服务。

这类报错不等于私有仓库拒绝访问,也不等于证书已损坏。若 CI 只负责读取团队已经准备好的签名资产,应评估是否可以使用只读运行方式,避免不必要地触发证书或描述文件变更。只有在确认具体操作需要开发者账户授权后,才处理账户侧权限。

材料已拉取、Xcode 仍无法签名:检查完整身份

match 拉取成功,只能说明同步动作完成;它不能单独证明当前构建用户已具备可用签名身份。Apple 将代码签名身份与证书及其对应私钥关联起来;只有证书而没有配对私钥,不能完成签名。Apple 关于代码签名证书的说明解释了身份和私钥之间的关系。

在执行构建的 Mac 账户下查看身份:

security find-identity -v -p codesigning

若预期身份没有出现,先检查 Keychain 是否包含对应私钥、该 Keychain 是否对当前任务可用,以及任务与桌面登录是否使用同一用户。再确认 Provisioning Profile 是否匹配目标应用、Bundle ID、签名证书和所需能力。Apple 对描述文件所关联条件的说明可用于核对这一步。

不要把“Apple 账户无法验证”和“本地 Keychain 缺少私钥”合并成一个故障。也不要因为 Xcode 找不到身份就直接重新生成或撤销证书:这可能影响共享该证书的其他构建者。若 Profile 已过期或能力发生变化,再按 Apple 的描述文件更新与下载流程评估更新范围。

团队仓库与 CI:划清读取和写入责任

团队签名仓库的权限,应按实际工作拆分,而不是让所有构建身份都能写入。开发者通常需要的是读取并在本机签名;CI 通常需要读取并构建;负责证书或 Profile 更新的维护者才应按团队审批流程执行写入。

fastlane 建议 CI 使用 readonly 模式,避免自动构建创建或修改签名材料。match 官方文档同时说明了存储方式、仓库认证和 CI 配置。对于 GitHub Actions,还要注意某些来源的拉取请求工作流不会获得常规 Actions secrets;排查时先判断工作流触发场景,而不是把缺少秘密误诊为错误口令。

决策条件

  • 若只需让 CI 读取既有签名材料,则使用 readonly,并为构建身份授予最小读取权限;否则,若确需维护材料,交由获授权的维护者在受控流程中执行写入。
  • 若SSH 身份认证失败,则检查加载的密钥与身份配置;否则,若身份认证成功但仓库查询失败,转查目标仓库授权和 URL。
  • 若仓库读取成功、解密失败,则检查 MATCH_PASSWORD 的注入与来源;否则,若同步成功但 Xcode 找不到身份,转查 Keychain、私钥和 Profile。
  • 若错误明确发生在 Apple 开发者账户校验,则查账户授权;否则,不要为了“试试看”撤销或重建证书。

修复后验收:从凭据读取走到真实构建

逐层验证,不要把一次 match 成功当作发布链路恢复:

  • 在实际构建身份下检查私有仓库可读。记录测试结果与使用的认证类型,不保存密钥内容。
  • 执行 match 的只读同步,确认仓库访问与材料解密分别通过。
  • 检查 Keychain 中可用的签名身份,并核对目标 Profile 与应用标识、签名类型及能力相符。
  • 使用项目实际的 Xcode 构建或 Archive 流程完成验收,记录构建结果、签名设置和失败阶段。
  • 在修改证书、清理 Keychain 或替换 Profile 之前,确认哪些开发者和任务会受影响,并准备备份与回退路径。
观察到的结果 优先检查 暂不采取的操作
Git 只读查询失败 当前构建身份、仓库 URL、读权限 不要先改加密口令
仓库可读、解密失败 MATCH_PASSWORD 注入范围与值来源 不要把口令写进配置或日志
Apple 账户校验失败 账户、团队与任务所需授权 不要误判为 Git 故障
match 完成、Xcode 无签名身份 Keychain、配对私钥、Profile 匹配 不要先撤销共享证书
角色 通常需要的权限 验收责任
开发者 读取其工作所需的签名材料 本机目标与签名身份可用
CI 维护者 读取、解密与构建所需秘密 只读同步和实际构建通过
签名仓库维护者 按审批流程写入或更新材料 变更影响范围与回退路径清楚

如果问题最终指向“当前没有可用于 Xcode 签名构建的 macOS 环境”,本机临时借用或自购 Mac 仍可行,但前者不适合无人值守,后者则需要自行承担设备与持续运维。远程 Mac 也不能替你修复错误授权或缺失私钥;它的价值在于提供可持续使用的 macOS 构建环境。你可以先查看 MACCOME 的远程 Mac 方案,再结合团队实际的构建频率,决定是临时使用还是租用常驻打包环境。需要了解服务入口时,也可前往 MACCOME 中文页面。