KISS

Keep It Simple Stupid

Jenkins: setting up iOS code signing

| comments

This post continues the Jenkins setup theme started with this post: Jenkins in OSX guest in VirtualBox for iOS jobs – full setup guide. I’m going to explain how to properly setup code signing for iOS apps on Jenkins and use it.

You can use your own developer profile on the Jenkins, but it’s better to add another user for improved security and separation of concerns. NB: It can only be done for enterprise accounts, for personal ones you’ll have to use your own certificate.

Creating developer certificate

Open the “Keychain Access” app, as your normal user on your Mac. Create new keychain, call it jenkins_dev, enter a password. Select the keychain, then “within the Keychain Access drop down menu, select Keychain Access > Certificate Assistant > Request a Certificate from a Certificate Authority.” Enter email (Jenkins’), name “Jenkins Bot”, save the CSR to disk. Move the generated public and private keys from the login keychain to the jenkins_dev one.

Create an apple id for your jenkins bot and invite her to the team. If you upload the CSR from your own account, the generated certificate will have your name, regardless of what name you used on the previous step.

Go to Jenkins’ Apple Developer Portal, the “Certificates, Identifiers & Profiles” section, click on Certificates link, then Development on the left, add a new one, type “iOS App Development”, now upload the generated CSR. Login as your primary account and approve the new developer certificate.

As the Jenkins apple id, download the certificate and drag it directly into the jenkins_dev keychain. See the screenshot what it should look like:

Click the private key, “Get Info”, “Access Control” tab. Select “Confirm before allowing access”. In “Always allow access by these applications”, click “+”. In the dialog press “Cmd+Shift+G”, enter /usr/bin/codesign, press “Add”. Save the changes. While still here, go to the keychain’s settings, and increase the lock timeout from 5 to at least 15 minutes, depending on the build time of your jobs. If the timeout is too small, you may get weird errors; I learned that the hard way: Jenkins and Xcode: “User interaction is not allowed”.

Generating provisioning profile

Now you need to generate/update a provisioning profile. Let’s try with the “Team Provisioning Profile” first. It’s managed by Xcode and you can’t edit it on the website. Hopefully, the fix is simple. Open Xcode, “Settings”, “Accounts”, click your own Apple ID, “View Details…”, and press the “Update” button under the “Provisioning Profiles” section. The Xcode should pick up the new developer and update the Team profile. To make sure, go to Development Provisioning Profiles and check the expiration date which should be “(today – 1) next year”.

Now you need to find the provisioning profile file among those that you might have. The easiest way for me ATM is to use the ProvisionQL QuickLook plugin (install it with brew cask install provisionql), then go to ~/Library/MobileDevice/Provisioning Profiles/, and manually go through the files to find the matching one.

Copying files to Jenkins

Copy the keychain and provisioning profile to the jenkins host (in this example I’m using Jenkins in a VM as described in the original post):

1
2
3
4
scp -P 20022 ~/Library/Keychains/jenkins_dev.keychain jenkins@127.1:~/Library/Keychains/

ssh -p 20022 jenkins@127.1 'mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles'
scp -P 20022 ~/Library/MobileDevice/Provisioning\ Profiles/cedfea8c-8eab-46cd-acbe-aa438f6d1559.mobileprovision jenkins@127.1:'~/Library/MobileDevice/Provisioning\ Profiles/'

(I hate spaces in filenames when it comes to working in shell. Please don’t use spaces in filenames for your projects’ source files, documents, etc.)

Don’t forget to run this command on the Jenkins host as the jenkins user to add the new keychain to the search list:

1
security list-keychains -s ~/Library/Keychains/{login,jenkins_dev}.keychain

Or you’ll receive this vague error:

1
2
3
Check dependencies
Code Sign error: No code signing identities found: No valid signing identities (i.e. certificate and private key pair) matching the team ID “(null)” were found.
CodeSign error: code signing is required for product type 'Unit Test Bundle' in SDK 'iOS 8.1'

Setting up Jenkins job

On Jenkins, install the Mask Passwords Plugin, which will allow you to specify the keychain password without revealing it in the logs. In the job config, enable Mask passwords, and add an entry jenkins_dev_password = “your password”. Later, in a shell script build step before building your project, add:

1
2
# unlock the keychain with a developer profile for code signing
security unlock-keychain -p "${jenkins_dev_password}" "$HOME/Library/Keychains/jenkins_dev.keychain"

Run a build, and it should be fine now!

Comments