使用 Jenkins/Hudson 作为 iOS 和 Mac 开发的持续集成时,钥匙串中缺少证书和密钥

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6827874/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 20:52:17  来源:igfitidea点击:

Missing certificates and keys in the keychain while using Jenkins/Hudson as Continuous Integration for iOS and Mac development

ioshudsonjenkinskeychainlaunchd

提问by Dmytro

I'm trying to improve Hudson CI for iOS and start Hudson as soon as system starts up. To do this I'm using the following launchd script:

我正在尝试改进适用于 iOS 的 Hudson CI,并在系统启动后立即启动 Hudson。为此,我使用以下 launchd 脚本:

<?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>Hudson CI</string>
    <key>ProgramArguments</key>
    <array>
    <string>/usr/bin/java</string>
    <string>-jar</string>
    <string>/Users/user/Hudson/hudson.war</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>UserName</key>
    <string>user</string>
</dict>
</plist>

This works OK but when xcodebuild, which is started by Hudson, tries to sign an app it fails because it cant find the proper key/certificate in the keychain. However key/certificate pair is there since it's working correct if I start Hudson from command line.

这工作正常,但是当由 Hudson 启动的 xcodebuild 尝试签署应用程序时,它失败了,因为它无法在钥匙串中找到正确的密钥/证书。但是,密钥/证书对存在,因为如果我从命令行启动 Hudson,它可以正常工作。

Do you have any ideas why it happens?

你知道为什么会这样吗?

采纳答案by Jens Kohl

After spending hours and days with this issue I found a fairly easy solution to this. It doesn't matter if you have a distinct username in your launchd configuration as stated above:

在这个问题上花费了数小时和数天后,我找到了一个相当简单的解决方案。如上所述,您的 launchd 配置中是否有不同的用户名并不重要:

<key>UserName</key>
<string>user</string>

The missing certificates and keys have to be on the system keychain (/Library/Keychains/System.keychain). I found this after I setup a jenkins job which executes several securityshell calls. The one which's interesting is security list-keychains:

丢失的证书和密钥必须在系统钥匙串 ( /Library/Keychains/System.keychain) 上。我在设置执行多个securityshell 调用的 jenkins 作业后发现了这一点。有趣的是security list-keychains

+ security list-keychains
    "/Library/Keychains/System.keychain"
    "/Library/Keychains/applepushserviced.keychain"
    "/Library/Keychains/System.keychain"

That are the keychains jenkins will search the certificates and keys for so they should be there. After I moved my certs there it works. Make sure you also copy the ?Apple Worldwide Developer Relations Certification Authority? certificate to the system keychain, otherwise you will see a CSSMERR_TP_NOT_TRUSTEDerror from codesign.

那是 jenkins 将搜索证书和密钥的钥匙串,因此它们应该在那里。在我将证书移到那里之后,它就可以工作了。确保您还复制了?Apple Worldwide Developer Relations Certification Authority?证书到系统钥匙串,否则您将看到CSSMERR_TP_NOT_TRUSTED来自codesign.

It is also possible to register more keychains with security list-keychains -s [path to additional keychains]. I haven't tried it but something like security list-keychains -s $HOME/Library/Keychains/login.keychainas a pre-build shell execution in jenkins might work.

也可以使用 注册更多钥匙串security list-keychains -s [path to additional keychains]。我还没有尝试过,但像security list-keychains -s $HOME/Library/Keychains/login.keychainjenkins 中的预构建 shell 执行可能会起作用。

EDIT:I've tried to add a user keychain to the search path with -sbut I wasn't able to get it to work. So for now, we have to copy our certs and keys into the system keychain.

编辑:我试图将用户钥匙串添加到搜索路径中,-s但我无法让它工作。所以现在,我们必须将我们的证书和密钥复制到系统钥匙串中。

EDIT^2:Read and use joensson' solutioninstead of mine, he managed it to access the users keychain instead of just the system keychain.

编辑 ^2:阅读并使用 joensson 的解决方案而不是我的解决方案,他设法访问用户钥匙串,而不仅仅是系统钥匙串。

回答by joensson

I have found a solution giving me access to the regular keychains for my Jenkins user.

我找到了一个解决方案,可以让我访问 Jenkins 用户的常规钥匙串。

In addition to specifying the UserName element in the plist as the accepted answer suggests, the trick to get access to the normal keychains for the user you specified in UserName is to also add a SessionCreate element with value true to the plist file - /Library/LaunchDaemons/org.jenkins-ci.plist :

除了按照公认的答案在 plist 中指定 UserName 元素之外,访问您在 UserName 中指定的用户的普通钥匙串的技巧是还将一个值为 true 的 SessionCreate 元素添加到 plist 文件 - /Library/ LaunchDaemons/org.jenkins-ci.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>EnvironmentVariables</key>
        <dict>
                <key>JENKINS_HOME</key>
                <string>/Users/Shared/Jenkins/Home</string>
        </dict>
        <key>GroupName</key>
        <string>wheel</string>
        <key>KeepAlive</key>
        <true/>
        <key>Label</key>
        <string>org.jenkins-ci</string>
        <key>ProgramArguments</key>
        <array>
                <string>/bin/bash</string>
                <string>/Library/Application Support/Jenkins/jenkins-runner.sh</string>
        </array>
        <key>RunAtLoad</key>
        <true/>
        <key>UserName</key>
        <string>jenkins</string>
        <key>SessionCreate</key>
        <true />
</dict>

Then restart the daemon and try running a job in Jenkins that calls security list-keychains - and you should no longer see System.keychain as the only entry but the regular login and any custom key chains you might have added to the list of keychains for the "jenkins" user.

然后重新启动守护进程并尝试在 Jenkins 中运行一个调用 security list-keychains 的作业 - 您不应再将 System.keychain 视为唯一条目,而是将常规登录名和您可能已添加到钥匙串列表中的任何自定义钥匙链“詹金斯”用户。

I am now using codesigning certificates from a custom keychain on my Jenkins build server - I have not installed any certificates or keys in my System keychain.

我现在在我的 Jenkins 构建服务器上使用来自自定义钥匙串的代码签名证书 - 我没有在我的系统钥匙串中安装任何证书或密钥。

回答by cemonds

We had the same problem with a hudson slave started as a launchdaemon on Mac OSX Lion. It worked, when we started the slave with webstart. The only difference we spotted was a different environment variable.

我们在 Mac OSX Lion 上将 hudson slave 作为启动守护程序启动时遇到了同样的问题。当我们使用 webstart 启动从站时,它起作用了。我们发现的唯一区别是不同的环境变量。

com.apple.java.jvmTask=WebStart

works, if we started the slave without webstart the variable was

有效,如果我们在没有 webstart 的情况下启动从站变量是

com.apple.java.jvmTask=CommandLine.java

We found no way to influence the value upfront. I suggest you create a new node in Hudson, running on the same machine and started by webstart. For starting the slave we use the following launchdaemon configuration:

我们发现无法预先影响价值。我建议您在 Hudson 中创建一个新节点,在同一台机器上运行并通过 webstart 启动。为了启动从站,我们使用以下启动守护程序配置:

<?xml version"1.0" encoding="UTF-8"?>
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>jenkins</string>
    <key>UserName</key>
    <string>apple</string>
    <key>Program</key>
    <string>/usr/bin/javaws</string>
    <key>ProgramArguments</key>
    <array>
        <string>-verbose</string>
        <string>-wait</string>
        <string>http://<hudson-hostname>:8080/computer/<node-name>/slave-agent.jnlp</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <true/>
    <key>WorkingDirectory</key>
    <string>/Users/apple</string>
</dict>
</plist>

回答by sti

You could try my Jenkins.app, https://github.com/stisti/jenkins-app, an alternative way to run Jenkins. It runs Jenkins in the user session, so Keychain access is not a problem.

你可以试试我的 Jenkins.app,https://github.com/stisti/jenkins-app,这是运行 Jenkins 的另一种方式。它在用户会话中运行 Jenkins,因此 Keychain 访问不是问题。

回答by JRV

I faced the same problem, and tried changing the user name in /Library/LaunchDaemons/org.jenkins-ci.plist as described in one of the other posts. However, it still did not work, and some obscure NullPointerException did not help me identify the problem. Therefore, I would just share my solution: I had to also change the owner of the JENKINS_HOME directory (defined in org.jenkins-ci.plist as well):

我遇到了同样的问题,并尝试更改 /Library/LaunchDaemons/org.jenkins-ci.plist 中的用户名,如其他帖子之一所述。但是,它仍然不起作用,一些晦涩的 NullPointerException 也没有帮助我确定问题。因此,我只想分享我的解决方案:我还必须更改 JENKINS_HOME 目录的所有者(也在 org.jenkins-ci.plist 中定义):

chown -R myBuildUser /Users/Shared/Jenkins

myBuildUser is the user that has the certificates installed, and this is the user that I specified in the plist file.

myBuildUser 是安装了证书的用户,这是我在 plist 文件中指定的用户。

This solution was quite obvious when I finally realized it - but it took me a couple of hours to find out about this, so hopefully this post can save the time for somebody else :-)

当我终于意识到它时,这个解决方案非常明显 - 但我花了几个小时才发现这一点,所以希望这篇文章可以为其他人节省时间:-)

回答by hieroGlype

We faced exactly the same issue on Lion as well as on SnowLeopard. We had to start a Tomcat/Hudson with xcodebuild jobs as a service. While starting from command line, the xcodebuild could access the login.keychain to use the certificate contained. But after reboot of the box, the login.keychain wasnt visible to xcodebuild and therefore the signing failed.

我们在 Lion 和 SnowLeopard 上遇到了完全相同的问题。我们必须使用 xcodebuild 作业作为服务启动 Tomcat/Hudson。从命令行启动时,xcodebuild 可以访问 login.keychain 以使用包含的证书。但是在重新启动盒子后,login.keychain 对 xcodebuild 不可见,因此签名失败。

Since we needed to provide our company certificate by a keychain, the system keychain wasnt an option. Instead, we solved the issue by a simple workaround. We removed the user name, so that the launch daemon launches the process under root.

由于我们需要通过钥匙串提供我们的公司证书,因此系统钥匙串不是一个选项。相反,我们通过一个简单的解决方法解决了这个问题。我们删除了用户名,以便启动守护进程在root下启动进程。

<plist version="1.0">
 <dict>
   <key>Label</key>
   <string>${LAUNCH_LABEL}</string>
   <key>Disabled</key>
   <false/>
   <key>RunAtLoad</key>
   <true/>
   <key>ProgramArguments</key>
   <array>
     <string>${INSTALL_DIR}/start.sh</string>
   </array>
   <key>StandardOutPath</key>
   <string>${INSTALL_DIR}/tomcat-stdout.log</string>
   <key>StandardErrorPath</key>
   <string>${INSTALL_DIR}/tomcat-stderr.log</string>
 </dict>
</plist>

The launch daemon called a simple script (start.sh), simulation a full login and running the program wanted

启动守护进程调用一个简单的脚本(start.sh),模拟完整登录并运行想要的程序

su -l username -c program

Now, even after booting, the xcodebuild can access the login.keychain. This works on Snow Leopard too, but, if you close the user specific login.keychain in a parallel session (like vnc login/logout) the keychain gets lost. Lion behaves different. Seems that Lion decouples the keychain from the user and assigns it to a login-session.

现在,即使在启动后,xcodebuild 也可以访问 login.keychain。这也适用于 Snow Leopard,但是,如果您在并行会话(如 vnc 登录/注销)中关闭用户特定的 login.keychain,钥匙串就会丢失。狮子的行为不同。似乎 Lion 将钥匙串与用户分离并将其分配给登录会话。

回答by igorsales

To keep a compartmentalized keychain for Jenkins/Hudson, I moved the launchctl item from

为了为 Jenkins/Hudson 保留一个分区钥匙串,我将 launchctl 项从

/Library/LaunchDaemons/org.jenkins-ci.plist

to

/Users/Shared/Jenkins/Home/Library/LaunchAgents/org.jenkins-ci.plist

And that allows me to access the private keychain created for Jenkins.

这允许我访问为 Jenkins 创建的私人钥匙串。

回答by Francois Nadeau

Adding this since I had the same problem, but none of these solutions worked for me.

添加这个是因为我遇到了同样的问题,但这些解决方案都不适合我。

My problem was that my signing certificate had expired. After the update, xcode and running xcodebuild manually worked fine, BUT Jenkins could not sign the app.

我的问题是我的签名证书已过期。更新后,xcode 和手动运行 xcodebuild 工作正常,但 Jenkins 无法签署应用程序。

Here is how I fixed it:

这是我修复它的方法:

  1. Look into Keychain and search for the key. For some reason that I don't understand I had multiple results.

  2. Make sure that the private key is in the System level (if it isn't then drag and drop it to the System icon on the left.

  1. 查看 Keychain并搜索 key。出于某种原因,我不明白我有多个结果。

  2. 确保私钥在系统级别(如果不是,则将其拖放到左侧的系统图标上。

enter image description here

在此处输入图片说明

回答by Shauket Sheikh

For Manual Signing Move your certificate from login to System in keychain. Login not accessible during archive and generating iPA.

对于手动签名,将您的证书从登录移动到钥匙串中的系统。在存档和生成 iPA 期间无法访问登录。

回答by Dan Kegel

Adding SessionCreate and setting lots of certificates to 'always trust' in keychain manager worked for me with buildbot started from plist... but at some point, codesign started failing with CSSMERR_TP_NOT_TRUSTED. I recovered by setting the iPhone Distribution cert to 'use system defaults' in keychain manager. Even after a reboot, without logging in, the buildbot slave was then able to sign code, whew.

添加 SessionCreate 并将大量证书设置为“始终信任”钥匙串管理器对我有用,buildbot 从 plist 开始......但在某些时候,协同设计开始失败,CSSMERR_TP_NOT_TRUSTED。我通过在钥匙串管理器中将 iPhone 分发证书设置为“使用系统默认值”来恢复。即使在重新启动后,无需登录,构建机器人从站也能够签署代码,哇。