IT박스

OS X의 Jenkins : xcodebuild에서 코드 서명 오류 발생

itboxs 2020. 8. 8. 12:09
반응형

OS X의 Jenkins : xcodebuild에서 코드 서명 오류 발생


요약:

최신 설치 프로그램 ( 1.449-2012 년 3 월 9 일 기준 )을 사용하면 OS X에서 Jenkins를 설정하는 것이 훨씬 더 쉬워 졌지만 간단한 대답없이 코드 서명 프로세스를 관리하는 것은 여전히 ​​매우 어렵습니다.

자극:

OS X에서 서비스를 실행하기위한 일반적인 모범 사례를 따르는 헤드리스 CI 서버를 실행합니다 ( 일부는 여기에서 일반 언어로 설명 됨 ).

배경:

방법:

OS X 설치 프로그램 패키지 를 통해 Jenkins CI를 설치합니다 . "설치 유형"단계에서 Customize 버튼을 클릭하고 "Start at boot as 'jenkins'"를 선택합니다.

토론:

이 시점에서 순진한 기대는 빌드 스크립트 xcodebuild -target MyTarget -sdk iphoneos있는 자유 스타일 프로젝트 가 작동해야한다는 것입니다. 이 게시물의 제목에서 알 수 있듯이 다음과 같이 실패합니다.

Code Sign error: The identity 'iPhone Developer' doesn't match any valid certificate/private key pair in the default keychain

어떤 일이 발생해야하는지 분명합니다. 유효한 코드 서명 인증서와 개인 키를 기본 키 체인에 추가해야합니다. 이를 수행하는 방법을 연구하면서 시스템을 일정 수준의 취약성에 개방하지 않는 솔루션을 찾지 못했습니다.

문제 1 : 젠킨스 데몬에 대한 기본 키 체인 없음

sudo -u jenkins security default-keychain ... "기본 키 체인을 찾을 수 없습니다"가 나타납니다.

Ivo Dancet가 아래에서 지적했듯이 , UserShell은 기본적으로 jenkins 데몬에 대해 / usr / bin / false로 설정되어 있습니다 (버그가 아니라 기능이라고 생각합니다). 그의 대답에 따라 UserShell을 bash로 변경하십시오. 그런 다음을 사용 sudo su jenkins하여 jenkins 사용자로 로그인하고 bash 프롬프트를 얻을 수 있습니다.

  1. sudo su jenkins
  2. cd ~/Library
  3. mkdir Keychains
  4. cd Keychains
  5. security create-keychain <keychain-name>.keychain
  6. security default-keychain -s <keychain-name>.keychain

좋아요. 이제 기본 키 체인이 있습니다. 오른쪽으로 가자? 하지만 먼저 왜 우리는 기본 키 체인을 만들려고했을까요?

내가 조사하는 동안 읽은 거의 모든 답변, 제안 또는 대화는 코드 서명 인증서와 키를 시스템 키 체인에 넣어야한다고 제안합니다. security list-keychainsJenkins에서 자유 스타일 프로젝트로 실행 하면 사용 가능한 유일한 키 체인이 시스템 키 체인임을 알 수 있습니다. 나는 그것이 대부분의 사람들이 인증서와 키를 거기에 넣는 아이디어를 생각 해낸 곳이라고 생각합니다. 그러나 이것은 매우 나쁜 생각처럼 보입니다. 특히 키 체인을 열려면 암호가있는 일반 텍스트 스크립트를 만들어야 한다는 점 감안 하면 더욱 그렇습니다 .

문제 2 : 코드 서명 인증서 및 개인 키 추가

이것은 내가 정말로 비꼬기 시작하는 곳입니다. Jenkins와 함께 사용하기 위해 고유 한 새 공개 / 개인 키를 만들어야한다는 직감이 있습니다. 내 생각 과정은 jenkins 데몬이 손상되면 Apple의 프로비저닝 포털에서 인증서를 쉽게 취소하고 다른 공개 / 개인 키를 생성 할 수 있다는 것입니다. 내 사용자 계정과 Jenkins에 동일한 키와 인증서를 사용하면 젠킨스 서비스가 공격 당하면 더 많은 번거 로움 (손상?)을 의미합니다.

Simon Urbanek의 대답가리키면 일반 텍스트 암호로 스크립트에서 키 체인을 잠금 해제 할 수 있습니다. 젠킨스 데몬의 키 체인에 "일회용"인증서와 키 이외의 것을 보관하는 것은 무책임한 것 같습니다.

나는 반대되는 어떤 논의에 매우 관심이 있습니다. 지나치게 조심하고 있습니까?

터미널에서 jenkins 데몬으로 새 CSR을 만들기 위해 다음을 수행했습니다.

  1. sudo su jenkins
  2. certtool r CertificateSigningRequest.certSigningRequest 다음을 입력하라는 메시지가 표시됩니다 (이 중 대부분은 정답에 대해 교육적인 추측을했습니다. 더 나은 통찰력이 있습니까? 공유하십시오.) ...
    • 키 및 인증서 레이블 입력 :
    • 알고리즘 선택 : r(RSA 용)
    • 키 크기를 비트 단위로 입력하십시오. 2048
    • 서명 알고리즘 선택 : 5(MD5의 경우)
    • 질문 문자열 입력 :
    • 그런 다음 RDN에 대한 많은 질문
  3. 생성 된 CSR 파일 (CertificateSigningRequest.certSigningRequest)을 새 Apple ID로 Apple의 프로비저닝 포털에 제출합니다.
  4. 요청을 승인하고 .cer 파일을 다운로드합니다.
  5. security unlock-keychain
  6. security add-certificate ios_development.cer

이것은 우리를 한 걸음 더 가까이 데려갑니다 ...

문제 3 : 프로비저닝 프로파일 및 키 체인 잠금 해제

문제가 발생하면 영향을 조금 더 작게 만들었 으면하는 희망으로 CI와 함께 사용하기 위해 프로비저닝 포털에서 특수 프로비저닝 프로파일을 만들었습니다. 모범 사례 또는 지나치게 신중한가요?

  1. sudo su jenkins
  2. mkdir ~/Library/MobileDevice
  3. mkdir ~/Library/MobileDevice/Provisioning\ Profiles
  4. 프로비저닝 포털에서 설정 한 프로비저닝 프로파일을이 새 폴더로 이동하십시오. 이제 젠킨스로 명령 줄에서 xcodebuild를 실행할 수있는 두 단계가 남았습니다. 즉, 빌드를 실행하는 Jenkins CI를 가져올 수 있다는 의미이기도합니다.
  5. security unlock-keychain -p <keychain password>
  6. xcodebuild -target MyTarget -sdk iphoneos

이제 젠킨스 데몬으로 로그인했을 때 명령 줄에서 성공적인 빌드를 얻습니다. 따라서 자유형 프로젝트를 만들고 마지막 두 단계 (위의 # 5 및 # 6)를 추가하면 빌드를 자동화 할 수 있습니다. iOS 프로젝트!

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?

Problem 4: Default keychain still not available!

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

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 this answer. Please note this is also an openrdar bug.

It should look like this:

<?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>daemon</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>
        <!-- **NEW STUFF** -->
        <key>SessionCreate</key>
        <true />
</dict>
</plist>

With this setup, I would also recommend the Xcode plugin for Jenkins, 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?

This setup is not perfect, and any advice or insight is greatly appreciated.

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, Sami Tikka 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.

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.


Update: August 9, 2013

With so many upvotes and favorites, I thought I would come back to this 18 months later with some brief lessons learned.

Lesson 1: Don't expose Jenkins to the public internet

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.

Lesson 2: There are new install options now

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 Bitnami Mac App Store version. These are definitely worth checking out. Jonathan Wright has a gist detailing getting Homebrew Jenkins working.

Lesson 3: No, seriously, don't expose your build box to the internet

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. Nick Arnott at Neglected Potential was able to confirm my heebie-jeebies pretty easily in this article.

TL;DR

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!


Keychains need to be unlocked before they can be used. You can use security unlock-keychain to unlock. You can do that interactively (safer) or by specifying the password on the command line (unsafe), e.g.:

security unlock-keychain -p mySecretPassword...

Obviously, putting this into a script compromises the security of that keychain, so often people setup an individual keychain with only the signing credentials to minimize such damage.

Typically in Terminal the keychain is already unlocked by your session, since the default keychain is unlocked on login, so you don't need to do that. However, any process not run in your session won't have unlocked keychain even if it has you as the user (most commonly this affects ssh, but also any other process).


Suppose you also want to do ad hoc distribution through Jenkins, this necessitates that Jenkins has access to a Distribution certificate, and the team admin identity, in addition to the provisioning profiles.

Using an exported identity in a .cer file, you can programmatically import it like so, the -A switch is to allow all programs access to this entry. Alternatively, you could use several -T /path/to/program switches to allow codesign and xcodebuild access.:

$ security import devcertificate.cer -k jenkins.keychain -A

Of course, we should also have the Apple WWDCRA certificate, imported in pretty much the same way:

$ security import AppleWWDRCA.cer -k jenkins.keychain -A

However, we also need the private key for the devcertificate.cer. To do this, you need to export the corresponding private key as a .p12 key and set a password. Put it somewhere you can access it from your Jenkins shell, unlock the keychain, and import it:

$ security unlock-keychain -p YourKeychainPass jenkins.keychain
$ security import devprivatekey.p12 -k login.keychain -P ThePasswordYouSetWhenExporting -A

Importing the distribution certificate works the same way. I don't know why you need to unlock the keychain for importing a .p12 and not for a .cer, but well.

You will also need access to the provisioning profiles, I will edit those instructions into this post shortly.


I've had the same issue and have been searching around for some time for an answer. Here's one thing that I've learned.

I am running jenkins as the jenkins user, user created by the installer, and as everyone else has mentioned he doesn't have access to the same keychain that your normal user does. Instead of trying to login as the jenkins user, I created a second build project that simply has one build step that is "Execute Shell" in which I run commands I want to test as the jenkins user.

Once I had that set up, I could run the command

security list-keychains

And this revealed to me that the only thing that jenkins could see was the system keychain.

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

With that knowledge, I then opened the Keychain Access app and copied my "iPhone Developer: xxxx" certificate into the System keychain (Right-click, copy from the "login" keychain).

This got me passed the certificate/private key pair code sign error but opened up another one with the provisioning profile (seems like a similar, but different, issue).


To change the password you can use sudo passwd jenkins <new-pw>. However I think it would be better to use the dscl command to change the password.

In my install jenkins (official installer) had a user shell /usr/bin/false. Changing it to bash solved the problem of not being able to login:

sudo dscl . -change /Users/jenkins UserShell /usr/bin/false /bin/bash

You should now be able to login with su jenkins.


I have used Xcode plugin to build iOS app. In configuration of a project.

choose Add build step > Xcode > code signing & OS X keychain options.

tick Unlock keychain box and add as follow (for examples) enter image description here

somtimes, if I get the error

Code Sign error: ...

I will reopen Jenkins and enter password again to unlock


For people having problems with keychains, I would recommend you try my alternative Jenkins installer at https://github.com/stisti/jenkins-app, downloads at https://github.com/stisti/jenkins-app/downloads

Jenkins.app runs Jenkins in your user session, so keychain access issues are not an issue :)


If you have sudo, you can use passwd to change the Jenkins user's password. Then you can get the Jenkins password.

Also, I'm not sure if this is the issue for you, but the ANT Script I use via Jenkins has this :

<target name="unlock_keychain">
    <exec executable="security">
        <arg value="-v"/>
        <arg value="unlock-keychain"/>          
        <arg value="-p"/>
        <arg value="<My Password>"/>
        <arg value="/Users/macbuild/Library/Keychains/login.keychain"/>
    </exec>
</target>

For some reason, "security" utility wasn't working for me on Lion with fresh Jenkins install.

After "sudo su jenkins" it was able to create new keychain, but silently ignored all "default-keychain -s ..." or "unlock" commands returning zero exit status and printing nothing to the console. Listing default or login keychains gave nothing, keychains search list was containing only system keychain, and I couldn't change this whatever I type.

After I logged in to that user's desktop and launched Keychain Utility, it did show my created keychain and after that everything worked as described in upper posts.

I am wondering whether some of initial keychains behavior changed in Lion, or am I missing something?


I added the private and public key for the company to the keychain. I added the provision profiles for the production I will be building.

Since this user did not have an account I logged into devcenter with my account. Downloaded the provisioning certs and loaded them into Xcode.

I did not add a cert specifically for the build role account, ex. jenkins.

I did add this to the build script: security unlock-keychain -p mySecretPassword as above, but...

I created a file ~/.ssh/mypass and add the password to the file.

Then the command becomes: security unlock-keychain -p cat ~/.ssh/mypass

Builds are working like a champ. I get the ipa file, it loads on app central and works on the device.


Could also install & launch JenkinsCI as a OS X user instead of a daemon:

  1. install jenkins using the official installer (https://jenkins-ci.org/)
    • Click next
    • Click "Customize"
    • Unselect "Start at boot as 'jenkins'" - * IMPORTANT * this option normally allows a headless jenkins which doesn't work well with keychain access
  2. Launch http://127.0.0.1:8080
    • verify it DOESN'T launch
    • may need to stop jenkins sudo launchctl unload /Library/LaunchDaemons/org.jenkins-ci.plist
  3. Double click /Applications/Jenkins/jenkins.war
    • of course this should be automated to start @ start up
  4. Open http://127.0.0.1:8080
    • verify it's now running

To solve this issue try to log in to http://appleid.apple.com and update your security questions.

It helped me.

참고URL : https://stackoverflow.com/questions/9245149/jenkins-on-os-x-xcodebuild-gives-code-sign-error

반응형