title: Jenkins on OS X: xcodebuild gives Code Sign error
body: <p><em>Summary:</em></p>
  
  <p>Setting up Jenkins on OS X has been made significantly easier with the most recent installer (<a href="http://ingorichter.blogspot.com/2012/03/jenkins-osx-installer-now-supports.html" rel="noreferrer">as of 1.449 - March 9, 2012</a>), however managing the process of code signing is still very difficult with no straightforward answer.</p>
  
  <p><em>Motivation:</em></p>
  
  <p>Run a headless CI server that follows common best practices for running services on OS X (<a href="http://www.minecraftwiki.net/wiki/Tutorials/Create_a_Mac_OS_X_startup_daemon#Creating_a_minecraft_daemon_user_and_group" rel="noreferrer">Some of which is explained here in plain language</a>).</p>
  
  <p><em>Background:</em></p>
  
  <ul>
  <li>October 12, 2009 - <a href="http://nachbaur.com/blog/how-to-automate-your-iphone-app-builds-with-hudson" rel="noreferrer">How to automate your iPhone app builds with Hudson</a></li>
  <li>June 15, 2011 - <a href="http://colonelpanic.net/2011/06/jenkins-on-mac-os-x-git-w-ssh-public-key/" rel="noreferrer">Jenkins on Mac OS X; git w/ ssh public key</a></li>
  <li>June 23, 2011 - <a href="http://blog.shinetech.com/2011/06/23/ci-with-jenkins-for-ios-apps-build-distribution-via-testflightapp-tutorial/" rel="noreferrer">Continuous Deployment of iOS Apps with Jenkins and TestFlight</a></li>
  <li>July 26, 2011 - <a href="https://stackoverflow.com/questions/6827874/missing-certificates-and-keys-in-the-keychain-while-using-jenkins-hudson-as-cont">Missing certificates and keys in the keychain while using Jenkins/Hudson as Continuous Integration for iOS and Mac development</a></li>
  <li>August 30, 2011 - <a href="https://stackoverflow.com/questions/7243882/xcode-provisioning-file-not-found-with-jenkins">Xcode Provisioning File not found with Jenkins</a></li>
  <li>September 20, 2011 - <a href="http://goodliffe.blogspot.com/2011/09/how-to-set-up-jenkins-ci-on-mac.html" rel="noreferrer">How to set up Jenkins CI on a Mac</a></li>
  <li>September 14, 2011 - <a href="http://ljnelson.posterous.com/getting-jenkins-running-on-a-mac" rel="noreferrer">Getting Jenkins Running on a Mac</a></li>
  <li>November 12, 2011 -  <a href="http://momo.brauchtman.net/2011/11/12/howto-install-jenkins-on-os-x-and-make-it-build-mac-stuff/" rel="noreferrer">Howto: Install Jenkins on OS X and make it build Mac stuff</a></li>
  <li>January 23, 2012 - <a href="http://ingorichter.blogspot.com/2012/01/upcoming-jenkins-osx-installer-changes.html" rel="noreferrer">Upcoming Jenkins OSX installer changes</a></li>
  <li>March 7, 2012 - <a href="https://wiki.jenkins-ci.org/display/JENKINS/Thanks+for+using+OSX+Installer" rel="noreferrer">Thanks for using OSX Installer</a></li>
  </ul>
  
  <p><em>Process:</em></p>
  
  <p>Install Jenkins CI via OS X <a href="http://mirrors.jenkins-ci.org/osx/latest" rel="noreferrer">installer package</a>. For the "Installation Type" step, click the Customize button, and choose "Start at boot as 'jenkins.'"</p>
  
  <p><em>Discussion:</em></p>
  
  <p>The naive expectation at this point was that a free-style project with the build script <code>xcodebuild -target MyTarget -sdk iphoneos</code> should work. As indicated by the title of this post, it does not and fails with:</p>
  
  <p><code>Code Sign error: The identity 'iPhone Developer' doesn't match any valid certificate/private key pair in the default keychain</code></p>
  
  <p>It is obvious enough what needs to happen - you need to add a valid code signing certificate and a private key into the default keychain. In researching how to accomplish this, I have not found a solution that doesn't open up the system to some level of vulnerability.</p>
  
  <p><em>Problem 1: No default keychain for jenkins daemon</em></p>
  
  <p><code>sudo -u jenkins security default-keychain</code> 
  ...yields "A default keychain could not be found"</p>
  
  <p>As pointed out below by <a href="https://stackoverflow.com/questions/9245149/jenkins-on-os-x-xcodebuild-sdk-iphoneos5-0-code-sign-error/9598192#9598192">Ivo Dancet</a>, the UserShell is set to /usr/bin/false for the jenkins daemon by default (I think this is a feature, not a bug); follow his answer to change the UserShell to bash. You can then use <code>sudo su jenkins</code> to get logged in as the jenkins user and get a bash prompt.</p>
  
  <ol>
  <li><code>sudo su jenkins</code></li>
  <li><code>cd ~/Library</code></li>
  <li><code>mkdir Keychains</code></li>
  <li><code>cd Keychains</code></li>
  <li><code>security create-keychain &lt;keychain-name&gt;.keychain</code></li>
  <li><code>security default-keychain -s &lt;keychain-name&gt;.keychain</code></li>
  </ol>
  
  <p>Okay, great. We've got a default keychain now; let's move on right? But, first why did we even bother making a default keychain?</p>
  
  <p>Almost all answers, suggestions, or conversation I read throughout researching suggest that one should just chuck their code signing certs and keys into the system keychain. If you run <code>security list-keychains</code> as a free-style project in Jenkins, you see that the only keychain available is the system keychain; I think that's where most people came up with the idea to put their certificate and key in there. But, this just seems like a very bad idea - especially given that <a href="https://stackoverflow.com/questions/9245149/jenkins-on-os-x-xcodebuild-sdk-iphoneos5-0-code-sign-error/9246321#9246321">you'll need to create a plain text script with the password to open the keychain</a>.</p>
  
  <p><em>Problem 2: Adding code signing certs and private key</em></p>
  
  <p>This is where I really start to get squeamish. I have a gut feeling that I should create a new public / private key unique for use with Jenkins. My thought process is if the jenkins daemon is compromised, then I can easily revoke the certificate in Apple's Provisioning Portal and generate another public / private key. If I use the same key and certificate for my user account and Jenkins, then it means more hassle (damage?) if the jenkins service is attacked.</p>
  
  <p>Pointing to <a href="https://stackoverflow.com/questions/9245149/jenkins-on-os-x-xcodebuild-sdk-iphoneos5-0-code-sign-error/9246321#9246321">Simon Urbanek's answer</a> you'll be unlocking the keychain from a script with a plain text password. It seems irresponsible to keep anything but "disposable" certificates and keys in the jenkins daemon's keychain.</p>
  
  <p><strong>I am very interested in any discussion to the contrary. Am I being overly cautious?</strong></p>
  
  <p>To make a new CSR as the jenkins daemon in Terminal I did the following...</p>
  
  <ol>
  <li><code>sudo su jenkins</code></li>
  <li><code>certtool r CertificateSigningRequest.certSigningRequest</code> You'll be prompted for the following (most of these I made educated guesses at the correct answer; do you have better insight? Please share.)...
  
  <ul>
  <li>Enter key and certificate label: </li>
  <li>Select algorithm: <code>r</code> (for RSA)</li>
  <li>Enter key size in bits: <code>2048</code></li>
  <li>Select signature algorithm: <code>5</code> (for MD5)</li>
  <li>Enter challenge string: </li>
  <li>Then a bunch of questions for RDN </li>
  </ul></li>
  <li>Submit the generated CSR file (CertificateSigningRequest.certSigningRequest) to Apple's Provisioning Portal under a new Apple ID</li>
  <li>Approve the request and download the .cer file</li>
  <li><code>security unlock-keychain</code></li>
  <li><code>security add-certificate ios_development.cer</code></li>
  </ol>
  
  <p>This takes us one step closer...</p>
  
  <p><em>Problem 3: Provisioning profile and Keychain unlocking</em></p>
  
  <p>I made a special provisioning profile in the Provisioning Portal just for use with CI in hopes that if something bad happens I've made the impact a little smaller. Best practice or overly cautious?</p>
  
  <ol>
  <li><code>sudo su jenkins</code></li>
  <li><code>mkdir ~/Library/MobileDevice</code></li>
  <li><code>mkdir ~/Library/MobileDevice/Provisioning\ Profiles</code></li>
  <li>Move the provisioning profile that you setup in the Provisioning Portal into this new folder. <em>We're now two short steps away from being able to run xcodebuild from the the command line as jenkins, and so that means we're also close to being able to get the Jenkins CI running builds.</em></li>
  <li><code>security unlock-keychain -p &lt;keychain password&gt;</code></li>
  <li><code>xcodebuild -target MyTarget -sdk iphoneos</code></li>
  </ol>
  
  <p>Now we get a successful build from a command line when logged in as the jenkins daemon, so if we create a free-style project and add those final two steps (#5 and #6 above) we will be able to automate the building of our iOS project!</p>
  
  <p>It might not be necessary, but I felt better setting jenkins UserShell back to /usr/bin/false after I'd successfully gotten all this setup. Am I being paranoid?</p>
  
  <p><em>Problem 4: Default keychain still not available!</em></p>
  
  <p>(<em>EDIT: I posted the edits to my question, rebooted to make sure my solution was 100%, and of course, I'd left out a step</em>)</p>
  
  <p>Even after all the steps above, you'll need to modify the Launch Daemon plist at /Library/LaunchDaemons/org.jenkins-ci.plist as stated in <a href="https://stackoverflow.com/questions/6827874/missing-certificates-and-keys-in-the-keychain-while-using-jenkins-hudson-as-cont/9482707#9482707">this answer</a>. Please note this is also an <a href="http://www.openradar.me/11708751" rel="noreferrer">openrdar bug</a>.</p>
  
  <p>It should look like this:</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
  &lt;!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&gt;
  &lt;plist version="1.0"&gt;
  &lt;dict&gt;
          &lt;key&gt;EnvironmentVariables&lt;/key&gt;
          &lt;dict&gt;
                  &lt;key&gt;JENKINS_HOME&lt;/key&gt;
                  &lt;string&gt;/Users/Shared/Jenkins/Home&lt;/string&gt;
          &lt;/dict&gt;
          &lt;key&gt;GroupName&lt;/key&gt;
          &lt;string&gt;daemon&lt;/string&gt;
          &lt;key&gt;KeepAlive&lt;/key&gt;
          &lt;true/&gt;
          &lt;key&gt;Label&lt;/key&gt;
          &lt;string&gt;org.jenkins-ci&lt;/string&gt;
          &lt;key&gt;ProgramArguments&lt;/key&gt;
          &lt;array&gt;
                  &lt;string&gt;/bin/bash&lt;/string&gt;
                  &lt;string&gt;/Library/Application Support/Jenkins/jenkins-runner.sh&lt;/string&gt;
          &lt;/array&gt;
          &lt;key&gt;RunAtLoad&lt;/key&gt;
          &lt;true/&gt;
          &lt;key&gt;UserName&lt;/key&gt;
          &lt;string&gt;jenkins&lt;/string&gt;
          &lt;!-- **NEW STUFF** --&gt;
          &lt;key&gt;SessionCreate&lt;/key&gt;
          &lt;true /&gt;
  &lt;/dict&gt;
  &lt;/plist&gt;
  </code></pre>
  
  <p>With this setup, I would also recommend the <a href="https://wiki.jenkins-ci.org/display/JENKINS/Xcode+Plugin" rel="noreferrer">Xcode plugin for Jenkins</a>, which makes setting up the xcodebuild script a little bit easier. At this point, I'd also recommend reading the man pages for xcodebuild - hell you made it this far in Terminal, right?</p>
  
  <p><strong>This setup is not perfect, and any advice or insight is greatly appreciated.</strong></p>
  
  <p>I have had a hard time selecting a "correct" answer since what I've come to use to solve my problem was a collection of just about everyone's input. I've tried to give everyone at least an up vote, but award the answer to Simon because he mostly answered the original question. Furthermore, <a href="https://github.com/stisti" rel="noreferrer">Sami</a> <a href="https://stackoverflow.com/users/1287080/sti">Tikka</a> deserves a lot of credit for his efforts getting Jenkins to work through AppleScript as a plain ol' OS X app. If you're only interested in getting Jenkins up and going quickly within your user session (i.e. not as a headless server) his solution is much more Mac-like.</p>
  
  <p>I hope that my efforts spark further discussion, and help the next poor soul who comes along thinking they can get Jenkins CI setup for their iOS projects in a weekend because of all the wonderful things they've heard about it.</p>
  
  <hr>
  
  <h2><em>Update: August 9, 2013</em></h2>
  
  <p>With so many upvotes and favorites, I thought I would come back to this 18 months later with some brief lessons learned.</p>
  
  <p><em>Lesson 1: Don't expose Jenkins to the public internet</em></p>
  
  <p>At the 2012 WWDC I took this question to the Xcode and OS X Server engineers. I received a cacophony of "don't do that!" from anyone I asked. They all agreed that an automated build process was great, but that the server should only be accessible on the local network. The OS X Server engineers suggested allowing remote access via VPN.</p>
  
  <p><em>Lesson 2: There are new install options now</em></p>
  
  <p>I recently gave a CocoaHeads talk about my Jenkins experience, and much to my surprise I found some new install methods - Homebrew and even a <a href="https://itunes.apple.com/us/app/bitnami-stack-for-jenkins/id598883005?mt=12" rel="noreferrer">Bitnami Mac App Store</a> version. These are definitely worth checking out. <a href="http://www.twitter.com/schwa" rel="noreferrer">Jonathan Wright</a> has a gist detailing getting <a href="https://gist.github.com/schwa/4033966" rel="noreferrer">Homebrew Jenkins working</a>.</p>
  
  <p><em>Lesson 3: No, seriously, don't expose your build box to the internet</em></p>
  
  <p>It's pretty clear from the original post that I'm neither a system administrator nor security expert. Common sense about private-y stuff (keychains, credentials, certificates, etc) left me feeling pretty uneasy about putting my Jenkins box on the internet. <a href="https://twitter.com/noir" rel="noreferrer">Nick Arnott</a> at Neglected Potential was able to confirm my heebie-jeebies pretty easily in <a href="http://www.neglectedpotential.com/2013/08/build-server-security/" rel="noreferrer">this article</a>.</p>
  
  <p><strong>TL;DR</strong></p>
  
  <p>My recommendation to others looking to automate their build process has changed over the past year and a half. Make sure your Jenkins machine is behind your firewall. Install and set Jenkins up as a dedicated Jenkins user either using the installer, Bitnami Mac App Store version, Sami Tikka's AppleScript, etc; this resolves most of the headache I detail above. If you need remote access, setting up VPN services in OS X Server takes ten minutes tops. I've been using this setup for over a year and am very happy with it. Good luck!</p>