Xcode Server 构建出现多个匹配的 codesigning identities
结论
重复的 signing identities 通常保存在 Xcode Server 自己维护的 keychain 中,不会出现在登录用户、_xcsbuildd 或 _xcsd 的默认 keychain 搜索列表里。所以下面的命令查不到它们是正常的:
security find-identity -p codesigning
sudo -u _xcsbuildd security find-identity -p codesigning
sudo -u _xcsd security find-identity -p codesigning
需要显式指定 /Library/Developer/XcodeServer/Keychains 下的 keychain 文件,找到同名 identity,删除已经过期的项,然后让 Server.app 重新同步 Developer Team。
不要直接删除整个 Certificates 或 Keychains 目录。这些目录可能还保存着 Xcode Server 的私钥和内部证书数据,整体删除可能导致所有 bot 的签名配置失效。
删除 provisioning profiles 为什么没用
错误信息已经指出,重复匹配的是:
certificate and private key pairs
这指的是 codesigning identity。每个 identity 由证书及其对应的私钥组成。provisioning profile 只规定可以参与签名的证书、App ID 和权限。
删除 provisioning profiles 只会清理描述文件,不会删除 keychain 中的证书或私钥。只要同名的新旧证书仍然同时存在,Xcode 就会继续报告多个匹配项。
旧证书到期后,Xcode Server 可能重新申请或导入了一份同名证书,却没有清除原来的 identity。这可能解释问题为什么正好出现在旧内容过期之后。具体是否由自动更新引起,不能只凭过期日期判断,应以 keychain 中实际列出的 identity 为准。
查找 Xcode Server 使用的 keychain
先列出 Xcode Server 目录中的 keychain 文件:
sudo find /Library/Developer/XcodeServer/Keychains \
-type f \
\( -name '*.keychain' -o -name '*.keychain-db' \) \
-print
Yosemite 时代通常使用 .keychain 文件,但文件名不一定固定,应以命令输出为准。
对找到的每个文件显式执行查询,例如:
sudo security find-identity -v -p codesigning \
"/Library/Developer/XcodeServer/Keychains/实际文件名.keychain"
也可以按证书名称查询:
sudo security find-certificate -a \
-c "Mac Developer: OS X Server" \
-Z \
"/Library/Developer/XcodeServer/Keychains/实际文件名.keychain"
需要把 keychain 路径作为最后一个参数传入。仅切换执行用户,不会自动将 Xcode Server 的私有 keychain 加入该用户的搜索列表。
如果有重复项,find-identity 通常会列出两个或更多 SHA-1 标识,其名称相同或相近。
核对证书有效期
删除前要先确认哪一项已经过期。可以导出匹配证书的 PEM 数据:
sudo security find-certificate -a \
-c "Mac Developer: OS X Server" \
-p \
"/Library/Developer/XcodeServer/Keychains/实际文件名.keychain" \
> /tmp/xcode-server-certificates.pem
如果只导出了一张证书,可以直接查看:
openssl x509 \
-in /tmp/xcode-server-certificates.pem \
-noout \
-subject \
-issuer \
-serial \
-dates \
-fingerprint \
-sha1
如果文件中包含多张连续的 PEM 证书,需要拆开逐张检查。也可以临时把该 keychain 添加到 Keychain Access 中查看,但不要修改其他系统 keychain。
检查时记录这些信息:
find-identity输出的 SHA-1- 证书名称和 Team ID
notBefore与notAfter- 已经过期和仍然有效的项
如果无法确认私钥和证书的对应关系,先不要删除。
备份并停止 Xcode Server
修改前先备份相关目录:
sudo ditto \
"/Library/Developer/XcodeServer/Keychains" \
"/Library/Developer/XcodeServer/Keychains.backup"
sudo ditto \
"/Library/Developer/XcodeServer/Certificates" \
"/Library/Developer/XcodeServer/Certificates.backup"
备份目标目录应当不存在,以免新旧文件混在一起。备份中可能包含私钥,因此只能允许管理员访问。
然后停止 Xcode 服务:
sudo serveradmin stop xcode
如果当前 Server.app 版本不接受这个服务名,请直接在 Server.app 中停止 Xcode 服务。不同 Server 版本使用的命令行服务名称可能不同。
删除过期的 identity
使用 find-identity 查到的 SHA-1 删除过期 identity:
sudo security delete-identity \
-Z "过期IDENTITY的SHA1" \
"/Library/Developer/XcodeServer/Keychains/实际文件名.keychain"
例如:
sudo security delete-identity \
-Z "0123456789ABCDEFFEDCBA987654321001234567" \
"/Library/Developer/XcodeServer/Keychains/xcs.keychain"
只能删除已经确认过期或不再使用的 identity。delete-identity 会同时处理证书及其私钥,误删仍在使用的项会导致签名完全失败。
删除后再次检查:
sudo security find-identity -v -p codesigning \
"/Library/Developer/XcodeServer/Keychains/实际文件名.keychain"
对应名称应当只剩一个有效匹配项。
重新同步 Developer Team
清理完成后启动服务:
sudo serveradmin start xcode
随后在 Server.app 中完成以下操作:
- 确认旧的 Developer Team 已经移除。
- 重新添加开发者账号和 Team。
- 等待 provisioning profiles 和证书同步完成。
- 再次检查 Xcode Server 的 keychain,确认没有重新生成重复 identity。
- 先运行启用了
Perform analyze action的 bot,再验证 archive。
如果刚删除的过期 identity 再次出现,它可能是从 /Library/Developer/XcodeServer/Certificates 中的旧数据重新导入的。不要批量删除这个目录。先停止服务并确认已有备份,然后逐个检查其中的证书文件,只移走已经确认过期且与重复 SHA-1 对应的文件,最后重新启动服务。
命令无法访问 keychain 时
可能会遇到以下错误:
User interaction is not allowed
或者:
The specified keychain could not be found
先检查路径和权限:
sudo ls -la "/Library/Developer/XcodeServer/Keychains"
sudo file "/Library/Developer/XcodeServer/Keychains/实际文件名.keychain"
Xcode Server 的内部 keychain 可能使用了由服务管理的密码或访问控制设置。如果无法解锁,不要尝试替换权限、修改 owner 或直接删除 keychain 文件,否则可能破坏 Xcode Server 保存的全部签名凭据。
最后的恢复手段
旧版 Xcode Server 提供过重置服务数据的工具,部分安装环境可以使用:
sudo xcrun xcscontrol --reset
该操作可能清除 bots、integrations、repositories、凭据和其他 Xcode Server 数据。不同 Xcode/Server 版本的清理范围可能不同,执行前先查看本机帮助:
sudo xcrun xcscontrol --help
只有在服务器已经完成备份、bots 可以重建,并且定向删除过期 identity 仍然无效时,才考虑完整重置。
关闭 Perform analyze action 或 Perform archive action 只能绕开需要签名的构建路径,无法解决 identity 重复的问题。应当直接检查 Xcode Server 的私有 keychain,保留一个有效 identity,并删除已经过期的重复项。
备注:内容仅供参考。
