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

发布于 2024-11-26 12:04:21 字数 897 浏览 2 评论 0原文

我正在尝试改进 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>

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

您知道为什么会发生这种情况吗?

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:

<?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.

Do you have any ideas why it happens?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

冷情妓 2024-12-03 12:04:21

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

找到此 plist:/Library/LaunchDaemons/org.jenkins-ci.plist 然后:

  • 添加值为 jenkinsUserName 元素。
  • 将值为 trueSessionCreate 元素添加到 plist 文件中。这将为您在 UserName 中指定的用户提供对普通钥匙串的访问权限。

示例:

<?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>
</plist>

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

通过上述设置,我可以在 Jenkins 构建服务器上使用来自自定义钥匙串的协同签名证书。我不必在我的系统钥匙串中安装任何证书或密钥。

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

Find this plist: /Library/LaunchDaemons/org.jenkins-ci.plist then:

  • Add the UserName element with a value of jenkins.
  • Add a SessionCreate element with a value true to the plist file. This gives access to the normal keychains for the user you specified in UserName

Example:

<?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>
</plist>

Then restart the daemon and try running a job in Jenkins that calls security list-keychains. 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.

With the above setup I am able to use codesigning certificates from a custom keychain on my Jenkins build server. I don't have to install any certificates or keys in my System keychain.

拥抱没勇气 2024-12-03 12:04:21

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

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

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

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

这是詹金斯将搜索证书和密钥的钥匙串,因此它们应该在那里。在我将证书移到那里后,它就可以工作了。确保您还将“Apple 全球开发者关系认证机构”证书复制到系统钥匙串,否则您将看到来自 codesignCSSMERR_TP_NOT_TRUSTED 错误。

还可以使用 security list-keychains -s [附加钥匙串的路径] 注册更多钥匙串。我还没有尝试过,但是像 security list-keychains -s $HOME/Library/Keychains/login.keychain 这样的东西作为 jenkins 中的预构建 shell 执行可能会起作用。

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

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

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:

<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 security shell calls. The one which's interesting is 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_TRUSTED error from 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.keychain as a pre-build shell execution in jenkins might work.

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

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

暖心男生 2024-12-03 12:04:21

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

com.apple.java.jvmTask=WebStart

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

com.apple.java.jvmTask=CommandLine.java

我们发现没有办法预先影响该值。我建议您在 Hudson 中创建一个新节点,在同一台计算机上运行并由 webstart 启动。为了启动从站,我们使用以下 launchdaemon 配置:

<?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>

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.

com.apple.java.jvmTask=WebStart

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

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:

<?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>
余生共白头 2024-12-03 12:04:21

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

chown -R myBuildUser /Users/Shared/Jenkins

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

当我最终意识到这个解决方案时,它是非常明显的 - 但我花了几个小时才找到这个问题,所以希望这篇文章可以为其他人节省时间:-)

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):

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.

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 :-)

但可醉心 2024-12-03 12:04:21

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

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

以下是我修复此问题的方法:

  1. 查看钥匙串并搜索密钥。由于某种我不明白的原因,我有多个结果。

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

在此处输入图像描述

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.

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.

enter image description here

A君 2024-12-03 12:04:21

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

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

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

su -l username -c program

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

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.

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.

<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

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.

阪姬 2024-12-03 12:04:21

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

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.

泪意 2024-12-03 12:04:21

为了为 Jenkins/Hudson 保留一个分隔的钥匙串,我将 launchctl 项从 移至

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

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

这使我能够访问为 Jenkins 创建的私有钥匙串。

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

/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.

轻拂→两袖风尘 2024-12-03 12:04:21

添加
会话创建

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

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.

圈圈圆圆圈圈 2024-12-03 12:04:21

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

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文