尝试使用codesign签署OSX应用程序时出现“不允许用户交互”的错误。

161
我们的自动化构建正在Jenkins上运行。构建本身是在从属机器上运行的,这些从属机器通过SSH执行。
我遇到了一个错误:
00:03:25.113 [codesign-app] build/App.app: User interaction is not allowed.

我已经尝试了在其他帖子中看到的所有建议:

  • 在签名之前立即使用security unlock-keychain解锁钥匙串。
  • 将签名密钥移动到自己的钥匙串中。
  • 将签名密钥移动到登录钥匙串中。
  • 将签名密钥移动到系统钥匙串中。
  • 手动设置list-keychains只包含包含密钥的钥匙串。

无论哪种情况,我都收到相同的错误。

为了诊断问题,我尝试在本地终端上运行"security unlock-keychain"命令,并发现它实际上并没有解锁钥匙串——如果我在Keychain Access中查看,锁图标仍然存在。无论我是在命令行上传递密码还是让它提示我输入密码,情况都是如此。使用GUI解锁同一钥匙串将提示我输入密码,然后解锁它。另外,如果我运行"security lock-keychain",我会在运行命令后立即看到密钥被锁定。这让我觉得unlock-keychain实际上不起作用。我在Lion(我们用于构建从机)和Mavericks(我正在开发的版本)上遇到了相同的问题。

接下来,我尝试在所有security命令中添加-v:

list-keychains "-d" "system" "-s" "/Users/tester/.secret/App.keychain"
Listing keychains to see if it was added: ((
        "/Library/Keychains/System.keychain"
))
unlock-keychain "-p" "**PASSWORD**" "/Users/tester/.secret/App.keychain"
build/App.app: User interaction is not allowed.

由此看来,似乎list-keychains出了问题。也许两者都没有工作。 :/

这里有一个类似的问题。 解决方案很有意思——在launchctl中将"SessionCreate"设置为true。但我不是在主机上构建——我的构建过程是从SSH连接到一个从机器上启动的。也许有一种命令行的方法可以完成运行"SessionCreate"时launchctl所做的事情?


如何在CircleCI上设置钥匙串密码? - Sachin Kumaram
@SachinKumaram听起来像是一个可行的新问题? - Hakanai
17个回答

212

我也一直在尝试解决这个问题。直到我尝试了http://devnet.jetbrains.com/thread/311971上的建议,才发现可行。感谢ashish agrawal!

通过GUI登录您的构建用户并打开Keychain Access。选择您的签名私钥,右键单击,选择“获取信息”,切换到访问控制选项卡,并选择“允许所有应用程序访问此项目”。

access control tab


3
我必须按照 http://apple.stackexchange.com/a/34872/6052 的方法取消隐藏 /usr 目录,才能将 codesign 添加到“始终允许”列表中。 - Heath Borders
28
请注意,除了这个之外,你还需要完成整个“security unlock-keychain”的步骤。 - cwd
14
此外,您可能希望将您的密钥从“登录”移动到“系统”,这样当您在机器上进行远程构建时就可以访问它们。 - Krystian
2
也许我有点多疑,但在“始终允许这些应用访问”框中添加“codesign”应该没问题。我认为,如果你只需要它来进行代码签名,那么没有必要允许所有应用程序都可以访问它。 - d4Rk
9
有人知道如何通过命令行来完成这个任务吗?由于安全原因,我的远程构建机器不允许我通过屏幕共享来完成此操作。 - devios1
显示剩余10条评论

85

好的,我猜今天我得回答自己的问题了,因为在两天半里试过很多次后,我尝试的其中一种方法似乎起作用了。现在我就打算离开它,希望它能继续工作。

基本上,看起来这归结于 -d system 实际上没有起作用。因此,这里其他问题的很多答案可能需要更新以反映这一点。

security -v list-keychains -s "$KEYCHAIN" "$HOME/Library/Keychains/login.keychain"
security list-keychains # so we can verify that it was added if it fails again
security -v unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN"
codesign --sign "$SIGNER_IDENTITY" --force --signature-size 9600 \
         --resource-rules src/AppResourceRules.plist --timestamp --verbose \
         "$APP"

18
谢谢。我已经能够缩小范围了。在尝试构建之前,请运行以下命令:security -v unlock-keychain -p“ $ KEYCHAIN_PASSWORD”“$ HOME / Library / Keychains / login.keychain” - pir800
3
那么,没有办法通过ssh访问codesign而不实际在某个脚本中存储登录密码吗? - chakrit
2
在上面的例子中,我只传递了钥匙串密码,而不是登录密码。我意识到对于很多用户来说,登录钥匙串就是唯一的钥匙串,但在我们的情况下,我们将签名密钥保存在一个单独的密钥库中,以便更容易地将它们同步到构建机器上。但是,是的,很多这些东西似乎对自动化构建而言相当不方便,这让我想知道苹果是否甚至进行自动化构建。 - Hakanai
@Trejkaz 哦,好的,至少共享钥匙串密码不会太糟糕。 - chakrit
在我的自动化远程构建用例中,将密钥串密码存储到.env文件中并不那么糟糕,因为.env文件已经包含了敏感的密钥,如 AWS 和 Heroku。在我们的情况下,构建相关的代码签名凭据存储在一个新创建的 Keychain 中,然后在构建完成后被删除。接着它会再次被创建用于下一次构建。但是,login密钥串仍然必须被打开,因此 security unlock-keychain -p pass login.keychain 是这里缺失的链接。谢谢! - Petrus Repo

41

使用安全性为/usr/bin/codesign创建钥匙串

导入证书并使其与codesign程序化地工作并不是使用登录或系统钥匙串或向某个codesign之神祈求的问题。您只需要设置正确的权限即可。我建议专门为codesign目的创建一个新的钥匙串。

现在,要想使codesign不产生errSecInternalComponent错误,您需要获取分区列表(ACL)的正确设置。我将逐步介绍如何实现:

创建钥匙串

security create-keychain -p "${KEYCHAIN_PASSWORD}" "${KEYCHAIN_NAME}"

此时钥匙串已经解锁,但是不会出现在 钥匙串访问 中。

将新的钥匙串添加到搜索列表中

security list-keychains -s "${KEYCHAIN_NAME}" "${OLD_KEYCHAIN_NAMES[@]}"

将新的Keychain添加到列表中。如果你不首先从list-keychains中获取原始列表,那么在搜索列表中就不再有login.keychain了。

解锁钥匙串

security unlock-keychain -p "${KEYCHAIN_PASSWORD}" "${KEYCHAIN_NAME}"

如果您已经创建了Keychain,则此操作是多余的。但是,如果Keychain已经存在,则有必要进行此操作。

从Keychain中删除默认值

security set-keychain-settings "${TESTING_KEYCHAIN}"

如果不指定任何参数,这将把自动锁定超时设置为无限并在睡眠时取消自动锁定。

从.p12文件导入您的签名证书

security import "${DIST_CER}" -P "${CERTIFICATE_PASSWORD}" -k "${KEYCHAIN_NAME}" -T /usr/bin/codesign

导入证书并通过-T选项授予codesign访问权限。

设置钥匙串上的ACL

security set-key-partition-list -S apple-tool:,apple: -s -k "${KEYCHAIN_PASSWORD}" "${KEYCHAIN_NAME}"

许多人都会忽略这个要求。你可以使用dump-keychain查看macOS的操作方式。在签名代码时,需要使用apple:apple-tool:-s表示签名证书。

我的签名证书在哪里?

确保自己能够找到证书是个好主意。

security find-identity -p codesigning -v /path/to/keychain

Gitlab-Runner、Jenkins等

对于任何CI类型的runner或构建系统而言,确保从launchd正确启动进程非常重要。请确保您的plist文件包含<SessionCreate></true>

如果没有将钥匙串的所有者与构建过程正确匹配,并确保创建了安全会话,将导致各种问题。从诊断的角度来看,您可以引入list-keychains并查看输出是否符合您的期望。

这是来自launchd.plist手册页的内容:

SessionCreate <boolean>

此键指定作业应生成到新的安全审计会话中,而不是默认会话,因为它属于该上下文的。有关详细信息,请参见auditon(2)。

UserName <string>

此可选键指定要运行作业的用户。此键仅适用于加载到特权系统域中的服务。

GroupName <string>

此可选键指定要运行作业的组。此键仅适用于加载到特权系统域中的服务。如果设置了UserName而未设置GroupName,则该组将设置为用户的主要组。

示例 /Library/LaunchDaemons/com.company.gitlab-runner.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>com.company.gitlab-runner</string>
    <key>SessionCreate</key><true/>
    <key>KeepAlive</key><true/>
    <key>Disabled</key><false/>
    <key>UserName</key>
    <string>bob</string>
    <key>GroupName</key>
    <string>staff</string>
    <key>ProgramArguments</key>
    <array>
      <string>/usr/local/opt/gitlab-runner/bin/gitlab-runner</string>
      <string>run</string>
      <string>--working-directory</string>
      <string>/Users/bob/gitlab-runner</string>
      <string>--config</string>
      <string>/Users/bob/gitlab-runner/config.toml</string>
      <string>--service</string>
      <string>gitlab-runner</string>
      <string>--syslog</string>
    </array>
    <key>EnvironmentVariables</key>
      <dict>
        <key>PATH</key>
        <string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
    </dict>
  </dict>
</plist>

注册Runner

gitlab-runner register \
  --non-interactive \
  --tls-ca-file "{{ gitlab_runner_dir }}/certs/git.company.com.crt" \
  --config "{{ gitlab_runner_dir }}/config.toml" \
  --builds-dir "{{ gitlab_runner_dir }}/builds" \
  --url "{{ gitlab_ci }}" \
  --registration-token "{{ gitlab_token }}" \
  --name "{{ computername }}" \
  --tag-list "{{ gitlab_runner_tags }}" \
  --output-limit 16384 \
  --executor shell \
  --shell bash

最终的代码签名

您可以使用find-identity查找签名证书的哈希值。

security find-identity -p codesigning -v

在开始签署Xcode之前,需要设置环境变量CODESIGN_ALLOCATE以使用Xcode附带的codesign_allocate而不是/usr/bin中的。

export CODESIGN_ALLOCATE="$( xcrun --find codesign_allocate )"

代码签名框架、dylib等

如果您是手动进行代码签名,请从frameworksdylibs开始,并在它们全部签名后再签署.app。换句话说,您需要从下往上进行代码签名。

/usr/bin/codesign --verbose=4 -f -s "$SIGNER_HASH" "$SIGNABLE"

对应用程序包进行代码签名

在所有其他可签名内容都已签名后,对 .app 文件本身进行签名。理论上,您可以使用 --deep 一次性完成所有操作,但是,您仍需要确保您的应用程序具有授权和可能需要其他标志。

/usr/bin/codesign --verbose=4 -f -s "$SIGNER_HASH" "$SIGNABLE"

应用到所有项目的标志:

  • --timestamp=none 禁用时间戳

应用签名步骤中的其他标志:

  • --entitlements /path/to/entitlements.xcent 新的权限
  • --preserve-metadata=entitlements 保留当前权限

新的代码签名要求 - DER编码的权限

苹果最近开始要求权限不仅以plist形式嵌入,还要以DER编码形式嵌入。如果您使用的是较旧的Mac/Xcode,则可能会遇到错误...

代码签名版本不再受支持


4
兄弟,你肯定可以写一篇关于这个的文章,我已经寻找了两天。我不知道我读了多少东西和stackoverflow的帖子。非常感谢你! - Damien
我非常希望这是让它正常工作的真正技巧,但是在GitLab中我仍然遇到了相同的“errSecInternalComponent”错误。Xcode 12.2。GitLab runner 13.7.0。我完全按照您的指示操作,@cameron-lowell-palmer。我找到的唯一解决方案是在构建期间解锁钥匙串,然后签名。很遗憾。 - saxzez
我在20个不同的构建器上使用它-所以我很好奇问题出在哪里...您是否将SessionCreate设置为true,并在LaunchD中正确设置了gitlab-runner的用户名? - Cameron Lowell Palmer
1
感谢@CameronLowellPalmer。是的,我确实有SessionCreate true,并且Mac上只有一个用户,gitlab-runner仅安装在该用户上(不是系统runner,因为它们不被推荐)。我相信您已经使其工作。我只是不知道我缺少什么。我不想在这里用这个讨论来污染评论区,但不确定如何/在哪里获得帮助。我与GitLab支持合作(我们是高级客户),他们也无法解决问题。现在,我只是在每次构建时添加了通过混淆密码解锁钥匙串,以便我可以继续前进。 - saxzez
1
@saxzez,GitLab网站上有关安装的说明非常可怕。我的策略是以管理员用户身份通过brew进行基本安装,然后以builder用户身份进行配置和运行,使用launchd。不要设置自动登录-来自GitLab的评论已经过时了。跳过凭据助手的内容,事实上,唯一有价值的东西就是最后的plist文件。 - Cameron Lowell Palmer
显示剩余2条评论

19

其他答案对我都没有用。

最终救了我是这篇文章

总结一下,这可能是由于默认超时时间为5分钟,在长时间构建后会触发此错误。

解决方法如下:

security set-keychain-settings -t 3600 -l ~/Library/Keychains/login.keychain

2
在El Capitan上,您也可以通过用户界面完成这项操作。只需打开钥匙串应用程序,右键单击您的钥匙串(登录、系统等),然后点击最匹配“更改<您的钥匙串>设置”的选项。 - rubybeginner
这总是会把我的系统钥匙串访问权限设置回“确认”,即使我已经更改了访问权限。 - Alex Zavatone
这对我很有帮助!! - Nori
1
我已经苦苦挣扎了两天,直到我看到了你的评论,谢谢!!! - Gilad Novik

18

尝试将 security unlock-keychaincodesign 作为一行命令来调用。这对我很有帮助。像这样:

security unlock-keychain -p <password> /Users/<user>/Library/Keychains/login.keychain && codesign --force --verify --verbose --sign "<certificate id>" <app name>

4
这和在两行上执行是一样的。我想区别在于,如果第一个命令失败了,它就不会运行第二个。 - Hakanai
1
对我来说它们不是一样的。我通过 Ant 的 sshexec 调用它们,每次都会创建一个新的 ssh 会话。 - ZhekaKozlov
2
如果你真的想要,你也可以通过单个ssh会话执行多行命令。所以...除了错误处理之外,它仍然是一样的。 - Hakanai

12

将您的密钥放入系统钥匙串中


但它仍然要求用户名和密码。 - Durai Amuthan.H
如何将密钥放入系统钥匙串......从钥匙串访问中复制粘贴是否有效? - Ashish Karpe
1
拖放 @AshishKarpe - Alistra
拖放操作仍然出现相同的错误:=== 使用调试配置构建项目PatientPortal的目标PatientPortal ===检查依赖项 未找到“com.abc.xyz360”的配置文件:Xcode无法找到与“com.abc.xyz360”匹配的配置文件。 在SDK“iOS 10.2”中,产品类型“应用程序”需要代码签名。 - Ashish Karpe
它说你的机器上没有安装配置文件,而不是缺少密钥 @AshishKarpe - Alistra
不起作用。即使我将访问权限设置为“全部”,下次检查访问权限时,它仍会被设置回“确认”。 - Alex Zavatone

7

以下是可行的命令。使用-A可以防止Mac要求输入密码。导入到system.keychain不需要GUI。

sudo security import <cert.p12> -k "/Library/Keychains/System.keychain" -P <passphrase> -A


3

我的钥匙串被锁住了。它抵制了我想改变这个事实的尝试...

钥匙串访问 -> 钥匙串第一援助 -> 修复就这样


2

仅解锁钥匙串是不够的。您还需要将私钥访问权限设置为“允许所有应用程序访问此项”。要从命令行执行此操作,需要重新导入密钥。因此,按顺序操作:

如果登录钥匙串已锁定,请解锁它。但实际上它不应该被锁定,无论如何,以下是解锁方法:

security -v unlock-keychain -p "$KEYCHAIN_PASSWORD" "~/Library/Keychains/login.keychain"

如果因某种原因您的构建机器有登录钥匙串被锁定,而且您不想在脚本中暴露密码,那么您应该使用另一个钥匙串。您可以即时创建一个并在前面和后面的命令中使用它。要即时创建一个:

security create-keychain -p 'temporaryPassword' MyKeychain.keychain
security list-keychains -d user -s login.keychain MyKeychain.keychain

然后使用-A参数将您的证书和相关私钥导入到登录钥匙串中。请注意,您不需要为所有这些操作使用sudo...

security import <cert.p12> -k "~/Library/Keychains/login.keychain" -P <passphrase> -A

-A参数将使您的私钥设置为“允许所有应用程序访问此项”。因此,使用所有这些内容,您应该能够创建一个脚本,安装所需的证书以构建发布ipa,并在没有提示的情况下签署它。您可以将.p12文件存储在您的存储库中,因此任何机器都可以构建您的ipa,而无需手动设置。

1
除了解锁钥匙串(如其他答案中所述),您还需要允许所有应用程序访问钥匙串中的Xcode身份验证令牌:
- 选择“登录”钥匙串 - 选择“所有项目”类别 - 搜索“xcode”关键字 - 为所有Xcode令牌选择“允许所有应用程序访问此项目” - 不要忘记添加解锁钥匙串步骤(来自之前的答案)
最初的回答:截图

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接