Jenkins su OS X: xcodebuild restituisce un errore di Code Sign


107

Sommario:

La configurazione di Jenkins su OS X è stata notevolmente semplificata con il programma di installazione più recente ( dall'1.449 al 9 marzo 2012 ), tuttavia la gestione del processo di firma del codice è ancora molto difficile senza una risposta semplice.

Motivazione:

Esegui un server CI headless che segue le migliori pratiche comuni per l'esecuzione di servizi su OS X ( alcuni dei quali sono spiegati qui in un linguaggio semplice ).

Sfondo:

Processi:

Installare Jenkins CI tramite OS X pacchetto di installazione . Per il passaggio "Tipo di installazione", fai clic sul pulsante Personalizza e scegli "Avvia all'avvio come" jenkins "".

Discussione:

L'ingenua aspettativa a questo punto era che un progetto in stile libero con lo script di compilazione xcodebuild -target MyTarget -sdk iphoneosavrebbe funzionato. Come indicato dal titolo di questo post, non funziona e fallisce con:

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

È abbastanza ovvio ciò che deve accadere: è necessario aggiungere un certificato di firma del codice valido e una chiave privata nel portachiavi predefinito. Nella ricerca di come ottenere questo risultato, non ho trovato una soluzione che non apra il sistema a un certo livello di vulnerabilità.

Problema 1: nessun portachiavi predefinito per il demone jenkins

sudo -u jenkins security default-keychain ... restituisce "Impossibile trovare un portachiavi predefinito"

Come sottolineato di seguito da Ivo Dancet , UserShell è impostato su / usr / bin / false per il daemon jenkins per impostazione predefinita (penso che questa sia una funzionalità, non un bug); segui la sua risposta per cambiare UserShell in bash. È quindi possibile utilizzare sudo su jenkinsper accedere come utente jenkins e ottenere un prompt 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

Va bene, fantastico. Ora abbiamo un portachiavi predefinito; andiamo avanti giusto? Ma prima perché ci siamo presi la briga di creare un portachiavi predefinito?

Quasi tutte le risposte, i suggerimenti o le conversazioni che ho letto durante la ricerca suggeriscono che si dovrebbe semplicemente inserire i certificati e le chiavi di firma del codice nel portachiavi del sistema. Se corri security list-keychainscome progetto in stile libero a Jenkins, vedrai che l'unico portachiavi disponibile è il portachiavi di sistema; Penso che sia qui che la maggior parte delle persone ha avuto l'idea di inserire il proprio certificato e la chiave. Ma questa sembra solo una pessima idea, soprattutto dato che dovrai creare uno script di testo semplice con la password per aprire il portachiavi .

Problema 2: aggiunta di certificati di firma del codice e chiave privata

È qui che comincio davvero a diventare schizzinoso. Ho la sensazione viscerale che dovrei creare una nuova chiave pubblica / privata unica per l'uso con Jenkins. Il mio pensiero è che se il daemon jenkins è compromesso, posso facilmente revocare il certificato nel portale di provisioning di Apple e generare un'altra chiave pubblica / privata. Se utilizzo la stessa chiave e certificato per il mio account utente e Jenkins, significa più problemi (danni?) Se il servizio jenkins viene attaccato.

Indicando la risposta di Simon Urbanek sbloccherai il portachiavi da uno script con una password in testo semplice. Sembra irresponsabile mantenere qualsiasi cosa tranne i certificati e le chiavi "usa e getta" nel portachiavi del demone jenkins.

Sono molto interessato a qualsiasi discussione contraria. Sono eccessivamente cauto?

Per creare un nuovo CSR come demone jenkins in Terminal ho fatto quanto segue ...

  1. sudo su jenkins
  2. certtool r CertificateSigningRequest.certSigningRequest Ti verrà chiesto di fornire quanto segue (la maggior parte di questi ho fatto ipotesi plausibili alla risposta corretta; hai una visione migliore? Per favore condividi.) ...
    • Immettere la chiave e l'etichetta del certificato:
    • Seleziona algoritmo: r(per RSA)
    • Immettere la dimensione della chiave in bit: 2048
    • Seleziona algoritmo di firma: 5(per MD5)
    • Inserisci la stringa della sfida:
    • Poi un mucchio di domande per RDN
  3. Invia il file CSR generato (CertificateSigningRequest.certSigningRequest) al portale di provisioning di Apple con un nuovo ID Apple
  4. Approva la richiesta e scarica il file .cer
  5. security unlock-keychain
  6. security add-certificate ios_development.cer

Questo ci fa fare un passo avanti ...

Problema 3: profilo di provisioning e sblocco del portachiavi

Ho creato uno speciale profilo di provisioning nel portale di provisioning solo per l'uso con CI nella speranza che se succede qualcosa di brutto ho ridotto un po 'l'impatto. Best practice o eccessivamente cauto?

  1. sudo su jenkins
  2. mkdir ~/Library/MobileDevice
  3. mkdir ~/Library/MobileDevice/Provisioning\ Profiles
  4. Sposta il profilo di provisioning che hai configurato nel portale di provisioning in questa nuova cartella. Siamo ora a due brevi passi dall'essere in grado di eseguire xcodebuild dalla riga di comando come jenkins, e quindi questo significa che siamo anche vicini alla possibilità di eseguire build in esecuzione della CI di Jenkins.
  5. security unlock-keychain -p <keychain password>
  6. xcodebuild -target MyTarget -sdk iphoneos

Ora otteniamo una build di successo da una riga di comando quando accediamo come demone jenkins, quindi se creiamo un progetto in stile libero e aggiungiamo quei due passaggi finali (# 5 e # 6 sopra) saremo in grado di automatizzare la creazione di il nostro progetto iOS!

Potrebbe non essere necessario, ma mi sono sentito meglio impostare jenkins UserShell su / usr / bin / false dopo aver ottenuto con successo tutta questa configurazione. Sono paranoico?

Problema 4: portachiavi predefinito ancora non disponibile!

( EDIT: ho pubblicato le modifiche alla mia domanda, riavviato per assicurarmi che la mia soluzione fosse al 100% e, naturalmente, avevo tralasciato un passaggio )

Anche dopo tutti i passaggi precedenti, sarà necessario modificare il plist di avvio del demone su /Library/LaunchDaemons/org.jenkins-ci.plist come indicato in questa risposta . Tieni presente che anche questo è un bug di openrdar .

Dovrebbe sembrare come questo:

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

Con questa configurazione, consiglierei anche il plugin Xcode per Jenkins , che rende un po 'più semplice la configurazione dello script xcodebuild. A questo punto, consiglierei anche di leggere le pagine man per xcodebuild - diavolo sei arrivato così lontano in Terminal, giusto?

Questa configurazione non è perfetta e qualsiasi consiglio o intuizione è molto apprezzata.

Ho avuto difficoltà a selezionare una risposta "corretta" poiché ciò che ho utilizzato per risolvere il mio problema era una raccolta di input di quasi tutti. Ho cercato di dare a tutti almeno un voto positivo, ma assegnare la risposta a Simon perché ha risposto per lo più alla domanda originale. Inoltre, Sami Tikka merita molto credito per i suoi sforzi nel far funzionare Jenkins tramite AppleScript come una semplice app OS X. Se sei interessato solo a far funzionare Jenkins e ad andare velocemente all'interno della tua sessione utente (cioè non come un server headless) la sua soluzione è molto più simile a quella di un Mac.

Spero che i miei sforzi suscitino ulteriori discussioni e aiutino la prossima povera anima che arriva pensando di poter installare Jenkins CI per i loro progetti iOS in un fine settimana a causa di tutte le cose meravigliose di cui hanno sentito parlare.


Aggiornamento: 9 agosto 2013

Con così tanti voti positivi e preferiti, ho pensato di tornare a questo 18 mesi dopo con alcune brevi lezioni apprese.

Lezione 1: non esporre Jenkins a Internet pubblico

Al WWDC del 2012 ho rivolto questa domanda agli ingegneri di Xcode e OS X Server. Ho ricevuto una cacofonia di "non farlo!" da chiunque io abbia chiesto. Tutti concordavano sul fatto che un processo di compilazione automatizzato fosse ottimo, ma che il server dovrebbe essere accessibile solo sulla rete locale. Gli ingegneri di OS X Server hanno suggerito di consentire l'accesso remoto tramite VPN.

Lezione 2: ora sono disponibili nuove opzioni di installazione

Di recente ho tenuto un discorso a CocoaHead sulla mia esperienza con Jenkins e, con mia grande sorpresa, ho trovato alcuni nuovi metodi di installazione: Homebrew e persino una versione di Bitnami per Mac App Store . Vale sicuramente la pena provarli. Jonathan Wright ha un'idea che dettaglia come funziona Homebrew Jenkins .

Lezione 3: No, seriamente, non esporre la tua build box a Internet

È abbastanza chiaro dal post originale che non sono né un amministratore di sistema né un esperto di sicurezza. Il buon senso per le cose private (portachiavi, credenziali, certificati, ecc.) Mi ha fatto sentire piuttosto a disagio nel mettere la mia scatola Jenkins su Internet. Nick Arnott di Neglected Potential è stato in grado di confermare i miei heebie-jeebies abbastanza facilmente in questo articolo .

TL; DR

La mia raccomandazione ad altri che cercano di automatizzare il loro processo di creazione è cambiata nell'ultimo anno e mezzo. Assicurati che la tua macchina Jenkins sia dietro il firewall. Installa e imposta Jenkins come utente Jenkins dedicato utilizzando il programma di installazione, la versione di Bitnami per Mac App Store, AppleScript di Sami Tikka, ecc .; questo risolve la maggior parte del mal di testa che ho descritto sopra. Se hai bisogno di un accesso remoto, la configurazione dei servizi VPN in OS X Server richiede al massimo dieci minuti. Uso questa configurazione da oltre un anno e ne sono molto soddisfatto. In bocca al lupo!


10
Sono triste di poter dare solo un voto positivo a questa domanda concisa e completa con risposte modificate :)
Zsub

Qualcosa ha rotto il lancio di Jenkins su OS X Yosemite - ha utilizzato il programma di installazione di Jenkins.
Jonny

Sposta il tuo certificato nel portachiavi di sistema e sii felice;)
Julian F. Weinert

Risposte:


30

I portachiavi devono essere sbloccati prima di poter essere utilizzati. Puoi usare security unlock-keychainper sbloccare. Puoi farlo in modo interattivo (più sicuro) o specificando la password sulla riga di comando (non sicuro), ad esempio:

security unlock-keychain -p mySecretPassword...

Ovviamente, l'inserimento di questo in uno script compromette la sicurezza di quel portachiavi, quindi spesso le persone configurano un portachiavi individuale con solo le credenziali di firma per ridurre al minimo tale danno.

Tipicamente in Terminal portachiavi è già sbloccato dalla tua sessione, poiché il portachiavi predefinito è sbloccato all'accesso, quindi non è necessario farlo. Tuttavia, qualsiasi processo non eseguito nella tua sessione non avrà il portachiavi sbloccato anche se ti ha come utente (più comunemente questo influisce ssh, ma anche qualsiasi altro processo).


Ma ho anche difficoltà a caricare qualsiasi portachiavi oltre il portachiavi di sistema. security unlock-keychain -p password -k /path/codesign.keychainnon funziona.
edelaney05

Hai usato il portachiavi predefinito come nel mio esempio sopra? Tieni presente che per i portachiavi personalizzati devi prima impostarli sul percorso di ricerca, quindi prova prima il portachiavi predefinito. Nota anche che non ci sono -kargomenti per unlock-keychaincui qualunque cosa tu stia cercando di fare non sembra giusta (vedi security help unlock-keychain).
Simon Urbanek

Ho provato qualcosa di leggermente diverso, ma alla fine sono tornato nello stesso punto. Ho modificato la mia domanda, spero che sia un po 'più chiara?
edelaney05

È completamente diverso dalla domanda originale ... Per cominciare, dovresti accedere come jenkins (ad esempio tramite sudo -u jenkins bash) e verificare di avere i permessi su tutto il percorso corretto. Hai fatto molte cose che non hai detto (come usare dsclper creare l'utente), quindi sei davvero da solo. Dovrai anche controllare le impostazioni home (a seconda che tu imposti o meno la shell che puoi usare sudo -u jenkins -iper ottenere le impostazioni di login corrispondenti).
Simon Urbanek

12

Supponiamo che tu voglia eseguire anche la distribuzione ad hoc tramite Jenkins, ciò richiede che Jenkins abbia accesso a un certificato di distribuzione e all'identità dell'amministratore del team, oltre ai profili di provisioning.

Utilizzando un'identità esportata in un file .cer, è possibile importarla a livello di codice in questo modo, l'opzione -A consente a tutti i programmi di accedere a questa voce. In alternativa, puoi utilizzare diversi -T /path/to/programinterruttori per consentire codesigne xcodebuildaccedere:

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

Ovviamente dovremmo anche avere il certificato WWDCRA di Apple, importato più o meno allo stesso modo:

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

Tuttavia, abbiamo anche bisogno della chiave privata per devcertificate.cer. Per fare ciò, è necessario esportare la chiave privata corrispondente come chiave .p12 e impostare una password. Mettilo da qualche parte in cui puoi accedervi dalla tua shell Jenkins, sbloccare il portachiavi e importarlo:

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

L'importazione del certificato di distribuzione funziona allo stesso modo. Non so perché devi sbloccare il portachiavi per importare un .p12 e non per un .cer, ma bene.

Avrai anche bisogno di accedere ai profili di provisioning, modificherò queste istruzioni in questo post a breve.


1
Potresti aggiornare con le istruzioni per l'accesso al profilo di provisioning?
Luca


5

Ho avuto lo stesso problema e da tempo ho cercato una risposta. Ecco una cosa che ho imparato.

Sto eseguendo jenkins come utente jenkins, utente creato dal programma di installazione e, come tutti gli altri hanno detto, non ha accesso allo stesso portachiavi del tuo utente normale. Invece di provare ad accedere come utente jenkins, ho creato un secondo progetto di compilazione che ha semplicemente un passaggio di compilazione che è "Esegui Shell" in cui eseguo i comandi che voglio testare come utente jenkins.

Una volta impostato, potrei eseguire il comando

security list-keychains

E questo mi ha rivelato che l'unica cosa che Jenkins poteva vedere era il portachiavi del sistema.

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

Con queste informazioni, ho quindi aperto l'app Accesso Portachiavi e ho copiato il mio certificato "iPhone Developer: xxxx" nel portachiavi di sistema (fai clic con il tasto destro, copia dal portachiavi "login").

Questo mi ha fatto superare l'errore di firma del codice della coppia di chiavi private / certificato, ma ne ha aperto un altro con il profilo di provisioning (sembra un problema simile, ma diverso).


Sto riscontrando lo stesso problema del profilo di fornitura, qualche idea su come risolverlo?
Santthosh

2
Ho scoperto che i profili di provisioning per l'utente Jenkins sono archiviati in "/ Users / Shared / Jenkins / Library / MobileDevice / Provisioning Profiles" e quindi ho inserito un passaggio nella mia build per copiare un profilo di provisioning dall'interno del mio repository git in quella posizione. Ciò mi consente di aggiornare il profilo di provisioning e di inviarlo a SCM e Jenkins acquisisce automaticamente tale modifica.
brianestey

se copi login.keychain nella tua libreria portachiavi jenkins, dovrai chown in modo che l'utente jenkins possa sbloccarlo con sicurezza
ganoro

1
Sei l'eroe, mi sono strappato i capelli in testa per 2 giorni, la copia dei certificati sul sistema ha aiutato
Roman Bobelyuk

5

Per cambiare la password puoi usare sudo passwd jenkins <new-pw> . Tuttavia penso che sarebbe meglio usare il comando dscl per cambiare la password.

Nella mia installazione, jenkins (programma di installazione ufficiale) aveva una shell utente / usr / bin / false. Cambiarlo in bash ha risolto il problema di non essere in grado di accedere:

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

Ora dovresti essere in grado di accedere con su jenkins.


Questo è stato molto utile per me: ho avuto un problema simile con il create-keychaincomando che non funzionava con l'utente jenkins. L'esecuzione di questo comando sembrava risolvere il problema.
lxt

Quando eseguo il comando per modificare la password utente jenkins, mi viene richiesta la password corrente. Non ho idea di cosa sia e non posso premere invio. Eventuali suggerimenti?
CMVR

4

Ho usato il plugin Xcode per creare un'app iOS. Nella configurazione di un progetto.

scegli Aggiungi passaggio di compilazione> Xcode> firma codice e opzioni portachiavi OS X.

spuntare la casella Sblocca portachiavi e aggiungere come segue (per esempi) inserisci qui la descrizione dell'immagine

a volte, se ottengo l'errore

Errore di sigla del codice: ...

Riaprirò Jenkins e inserirò di nuovo la password per sbloccarlo


3

Per le persone che hanno problemi con i portachiavi, consiglierei di provare il mio programma di installazione Jenkins alternativo su https://github.com/stisti/jenkins-app , download su https://github.com/stisti/jenkins-app/downloads

Jenkins.app esegue Jenkins nella tua sessione utente, quindi i problemi di accesso al portachiavi non sono un problema :)


La preoccupazione è che questo utente Jenkins si trovi nello spazio utente e non nello spazio demone ... quindi se un utente malintenzionato fosse in grado di compromettere il tuo utente Jenkins, avrebbe pieno accesso al tuo computer.
edelaney05

Questo potrebbe risolvere i problemi che ho riscontrato. Il problema è che ho un'installazione Jenkins esistente (eseguita in un altro modo) e non voglio perdere tutte le mie build, ecc. Cosa succederà nel mio caso?
Mike S

2

Se hai sudo, puoi usare passwd per cambiare la password dell'utente Jenkins. Quindi puoi ottenere la password di Jenkins.

Inoltre, non sono sicuro che questo sia il problema per te, ma lo script ANT che uso tramite Jenkins ha questo:

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

1
Sembra che tu abbia configurato Jenkins sotto un utente "macbuild"; Presumo che questo utente sia un utente e non un demone. Capisco sicuramente (ora) che il portachiavi dovrà essere sbloccato tramite gli argomenti della riga di comando (vedi i commenti di Simon Urbanek), ma non sono ancora sicuro di come creare un portachiavi predefinito per il demone jenkins.
edelaney05

1

Per qualche ragione, l'utilità di "sicurezza" non funzionava su Lion con una nuova installazione di Jenkins.

Dopo "sudo su jenkins" è stato in grado di creare un nuovo portachiavi, ma ha ignorato silenziosamente tutti i comandi "default-keychain -s ..." o "unlock" restituendo lo stato di uscita zero e non stampando nulla sulla console. L'elenco dei portachiavi predefiniti o di accesso non dava nulla, l'elenco di ricerca dei portachiavi conteneva solo il portachiavi di sistema e non potevo cambiarlo qualunque cosa digito.

Dopo aver effettuato l'accesso al desktop di quell'utente e avviato Keychain Utility, ha mostrato il mio portachiavi creato e successivamente tutto ha funzionato come descritto nei post superiori.

Mi chiedo se alcuni dei comportamenti iniziali dei portachiavi siano cambiati in Lion o mi sto perdendo qualcosa?


Ho eseguito i passaggi precedenti su un'installazione "pulita" di Lion, quindi forse c'è stato un problema con la sicurezza prima di iniziare? Un'altra possibilità è che ci sia stato un aggiornamento di sicurezza / OS X da quando l'ho pubblicato inizialmente?
edelaney05

0

Ho aggiunto la chiave privata e pubblica dell'azienda al portachiavi. Ho aggiunto i profili di fornitura per la produzione che costruirò.

Poiché questo utente non aveva un account, ho effettuato l'accesso a devcenter con il mio account. Hai scaricato i certificati di provisioning e li ho caricati in Xcode.

Non ho aggiunto un certificato specifico per l'account del ruolo di creazione, ad es. Jenkins.

Ho aggiunto questo allo script di build: security unlock-keychain -p mySecretPassword come sopra, ma ...

Ho creato un file ~ / .ssh / mypass e ho aggiunto la password al file.

Quindi il comando diventa: security unlock-keychain -p cat ~/.ssh/mypass

Le build funzionano come un campione. Ottengo il file ipa, si carica su app central e funziona sul dispositivo.


0

Potrebbe anche installare e avviare JenkinsCI come utente OS X invece che come demone:

  1. installa jenkins utilizzando il programma di installazione ufficiale ( https://jenkins-ci.org/ )
    • Fare clic su Avanti
    • Fai clic su "Personalizza"
    • Deseleziona "Avvia all'avvio come 'jenkins'" - * IMPORTANTE * questa opzione normalmente consente un jenkins senza testa che non funziona bene con l'accesso al portachiavi
  2. Lanciare http://127.0.0.1:8080
    • verificare che NON si avvii
    • potrebbe essere necessario fermare Jenkins sudo launchctl unload /Library/LaunchDaemons/org.jenkins-ci.plist
  3. Doppio click /Applications/Jenkins/jenkins.war
    • ovviamente questo dovrebbe essere automatizzato per avviare @ avviare
  4. Aperto http://127.0.0.1:8080
    • verificare che ora sia in esecuzione

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.