Jenkins sous OS X: xcodebuild donne une erreur de signe de code

107

Résumé:

La configuration de Jenkins sur OS X a été considérablement simplifiée avec le dernier programme d'installation (à partir de 1.449 - 9 mars 2012 ), mais la gestion du processus de signature de code est toujours très difficile sans réponse simple.

Motivation:

Exécutez un serveur CI sans tête qui suit les meilleures pratiques courantes pour exécuter des services sur OS X (dont certains sont expliqués ici en langage clair ).

Contexte:

Processus:

Installez Jenkins CI via OS X package d'installation . Pour l'étape «Type d'installation», cliquez sur le bouton Personnaliser et choisissez «Démarrer au démarrage en tant que« jenkins »».

Discussion:

L'attente naïve à ce stade était qu'un projet de style libre avec le script de construction xcodebuild -target MyTarget -sdk iphoneosdevrait fonctionner. Comme l'indique le titre de cet article, il ne fonctionne pas et échoue avec:

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

Ce qui doit se passer est assez évident: vous devez ajouter un certificat de signature de code valide et une clé privée dans le trousseau par défaut. En recherchant comment y parvenir, je n'ai pas trouvé de solution qui n'ouvre pas le système à un certain niveau de vulnérabilité.

Problème 1: pas de trousseau par défaut pour le démon jenkins

sudo -u jenkins security default-keychain ... renvoie "Un trousseau par défaut est introuvable"

Comme indiqué ci-dessous par Ivo Dancet , le UserShell est défini sur / usr / bin / false pour le démon jenkins par défaut (je pense que c'est une fonctionnalité, pas un bogue); suivez sa réponse pour changer le UserShell en bash. Vous pouvez ensuite utiliser sudo su jenkinspour vous connecter en tant qu'utilisateur jenkins et obtenir une invite 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

D'accord! Super. Nous avons maintenant un trousseau par défaut; allons-y, non? Mais d'abord pourquoi avons-nous même pris la peine de créer un trousseau par défaut?

Presque toutes les réponses, suggestions ou conversations que j'ai lues tout au long de la recherche suggèrent qu'il suffit de jeter leurs certificats et clés de signature de code dans le trousseau du système. Si vous exécutez en security list-keychainstant que projet de style libre dans Jenkins, vous voyez que le seul trousseau disponible est le trousseau système; Je pense que c'est là que la plupart des gens ont eu l'idée d'y mettre leur certificat et leur clé. Mais cela semble être une très mauvaise idée - d'autant plus que vous devrez créer un script en texte brut avec le mot de passe pour ouvrir le trousseau .

Problème 2: Ajout de certificats de signature de code et de clé privée

C'est là que je commence vraiment à être dégoûté. J'ai le sentiment instinctif que je devrais créer une nouvelle clé publique / privée unique à utiliser avec Jenkins. Mon processus de réflexion est que si le démon jenkins est compromis, je peux facilement révoquer le certificat dans le portail de provisionnement d'Apple et générer une autre clé publique / privée. Si j'utilise la même clé et le même certificat pour mon compte utilisateur et Jenkins, cela signifie plus de tracas (dommage?) Si le service jenkins est attaqué.

En indiquant la réponse de Simon Urbanek, vous déverrouillerez le trousseau à partir d'un script avec un mot de passe en texte brut. Il semble irresponsable de garder autre chose que des certificats et des clés «jetables» dans le trousseau du démon jenkins.

Je suis très intéressé par toute discussion à l'effet contraire. Suis-je trop prudent?

Pour créer un nouveau CSR en tant que démon jenkins dans Terminal, j'ai fait ce qui suit ...

  1. sudo su jenkins
  2. certtool r CertificateSigningRequest.certSigningRequest Vous serez invité à fournir ce qui suit (la plupart d'entre eux, j'ai fait des suppositions éclairées sur la bonne réponse; avez-vous un meilleur aperçu? Veuillez partager.) ...
    • Entrez la clé et l'étiquette du certificat:
    • Sélectionnez l'algorithme: r(pour RSA)
    • Entrez la taille de la clé en bits: 2048
    • Sélectionnez l'algorithme de signature: 5(pour MD5)
    • Entrez la chaîne de défi:
    • Puis un tas de questions pour RDN
  3. Soumettez le fichier CSR généré (CertificateSigningRequest.certSigningRequest) au portail de provisioning d'Apple sous un nouvel identifiant Apple
  4. Approuvez la demande et téléchargez le fichier .cer
  5. security unlock-keychain
  6. security add-certificate ios_development.cer

Cela nous rapproche un peu plus ...

Problème 3: profil de provisionnement et déverrouillage du trousseau

J'ai créé un profil de provisionnement spécial dans le portail de provisionnement juste pour une utilisation avec CI dans l'espoir que si quelque chose de mauvais se produit, j'ai réduit un peu l'impact. Meilleure pratique ou trop prudent?

  1. sudo su jenkins
  2. mkdir ~/Library/MobileDevice
  3. mkdir ~/Library/MobileDevice/Provisioning\ Profiles
  4. Déplacez le profil de provisioning que vous avez configuré dans le portail de provisioning dans ce nouveau dossier. Nous sommes maintenant à deux pas de la possibilité d'exécuter xcodebuild à partir de la ligne de commande en tant que jenkins, ce qui signifie que nous sommes également sur le point de pouvoir obtenir les builds en cours d'exécution de Jenkins CI.
  5. security unlock-keychain -p <keychain password>
  6. xcodebuild -target MyTarget -sdk iphoneos

Maintenant, nous obtenons une construction réussie à partir d'une ligne de commande lorsque nous nous connectons en tant que démon jenkins, donc si nous créons un projet de style libre et ajoutons ces deux dernières étapes (n ° 5 et n ° 6 ci-dessus), nous pourrons automatiser la construction de notre projet iOS!

Ce n'est peut-être pas nécessaire, mais je me suis senti mieux en remettant jenkins UserShell à / usr / bin / false après avoir réussi à obtenir toute cette configuration. Suis-je paranoïaque?

Problème 4: le trousseau par défaut n'est toujours pas disponible!

( EDIT: j'ai publié les modifications de ma question, redémarré pour m'assurer que ma solution était à 100%, et bien sûr, j'avais laissé de côté une étape )

Même après toutes les étapes ci-dessus, vous devrez modifier le plist de lancement du démon à /Library/LaunchDaemons/org.jenkins-ci.plist comme indiqué dans cette réponse . Veuillez noter qu'il s'agit également d'un bogue openrdar .

Ça devrait ressembler à ça:

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

Avec cette configuration, je recommanderais également le plugin Xcode pour Jenkins , ce qui facilite un peu la configuration du script xcodebuild. À ce stade, je vous recommande également de lire les pages de manuel de xcodebuild - vous êtes arrivé jusqu'ici dans Terminal, non?

Cette configuration n'est pas parfaite et tout conseil ou aperçu est grandement apprécié.

J'ai eu du mal à choisir une réponse «correcte» car ce que j'ai fini par utiliser pour résoudre mon problème était une collection d'entrées de presque tout le monde. J'ai essayé de donner à tout le monde au moins une voix positive, mais attribuez la réponse à Simon parce qu'il a principalement répondu à la question initiale. De plus, Sami Tikka mérite beaucoup de crédit pour ses efforts pour que Jenkins fonctionne via AppleScript comme une application OS X simple. Si vous êtes seulement intéressé par la mise en service rapide de Jenkins dans votre session utilisateur (c'est-à-dire pas en tant que serveur sans tête), sa solution ressemble beaucoup plus à Mac.

J'espère que mes efforts susciteront de nouvelles discussions et aideront la prochaine pauvre âme qui arrivera en pensant pouvoir installer Jenkins CI pour ses projets iOS en un week-end à cause de toutes les choses merveilleuses dont elle a entendu parler.


Mise à jour: 9 août 2013

Avec tant de votes positifs et de favoris, j'ai pensé que j'y reviendrais 18 mois plus tard avec quelques brèves leçons apprises.

Leçon 1: N'exposez pas Jenkins à l'Internet public

Lors de la WWDC 2012, j'ai posé cette question aux ingénieurs de Xcode et OS X Server. J'ai reçu une cacophonie de "ne fais pas ça!" de quiconque j'ai demandé. Ils ont tous convenu qu'un processus de construction automatisé était excellent, mais que le serveur ne devrait être accessible que sur le réseau local. Les ingénieurs d'OS X Server ont suggéré d'autoriser l'accès à distance via VPN.

Leçon 2: Il existe maintenant de nouvelles options d'installation

J'ai récemment donné une conférence CocoaHeads sur mon expérience Jenkins, et à ma grande surprise, j'ai trouvé de nouvelles méthodes d'installation - Homebrew et même une version Bitnami Mac App Store . Celles-ci valent vraiment le détour. Jonathan Wright a une idée générale du fonctionnement de Homebrew Jenkins .

Leçon 3: Non, sérieusement, n'exposez pas votre boîte de construction à Internet

Il est assez clair d'après l'article original que je ne suis ni un administrateur système ni un expert en sécurité. Le bon sens concernant les trucs privés (porte-clés, informations d'identification, certificats, etc.) m'a laissé assez mal à l'aise pour mettre ma boîte Jenkins sur Internet. Nick Arnott de Neglected Potential a pu confirmer assez facilement mes heebie-jeebies dans cet article .

TL; DR

Ma recommandation aux autres qui cherchent à automatiser leur processus de construction a changé au cours de la dernière année et demie. Assurez-vous que votre machine Jenkins est derrière votre pare-feu. Installez et configurez Jenkins en tant qu'utilisateur Jenkins dédié soit en utilisant le programme d'installation, la version Bitnami Mac App Store, AppleScript de Sami Tikka, etc. cela résout la plupart des maux de tête que je détaille ci-dessus. Si vous avez besoin d'un accès à distance, la configuration des services VPN dans OS X Server prend dix minutes maximum. J'utilise cette configuration depuis plus d'un an et j'en suis très content. Bonne chance!

edelaney05
la source
10
Je suis triste de ne pouvoir donner qu'une seule voix positive à cette question concise et complète avec réponses éditées :)
Zsub
Quelque chose a cassé le lancement de Jenkins sur OS X Yosemite - utilisé le programme d'installation de Jenkins.
Jonny
Déplacez votre certificat sur le trousseau du système et soyez heureux;)
Julian F. Weinert

Réponses:

30

Les porte-clés doivent être déverrouillés avant de pouvoir être utilisés. Vous pouvez utiliser security unlock-keychainpour déverrouiller. Vous pouvez le faire de manière interactive (plus sûr) ou en spécifiant le mot de passe sur la ligne de commande (unsafe), par exemple:

security unlock-keychain -p mySecretPassword...

De toute évidence, mettre cela dans un script compromet la sécurité de ce trousseau, si souvent les gens configurent un trousseau individuel avec uniquement les informations d'identification de signature pour minimiser ces dommages.

En règle générale, Terminalle trousseau est déjà déverrouillé par votre session, car le trousseau par défaut est déverrouillé lors de la connexion, vous n'avez donc pas besoin de le faire. Cependant, tout processus non exécuté dans votre session n'aura pas de trousseau déverrouillé même s'il vous a comme utilisateur (le plus souvent, cela affecte ssh, mais aussi tout autre processus).

Simon Urbanek
la source
Mais j'ai également des difficultés à charger un trousseau au-delà du trousseau système. security unlock-keychain -p password -k /path/codesign.keychainne fonctionne pas.
edelaney05
Avez-vous utilisé le trousseau par défaut comme dans mon exemple ci-dessus? Notez que pour les trousseaux personnalisés, vous devez d'abord les configurer pour qu'ils soient sur le chemin de recherche, essayez donc d'abord le trousseau par défaut. Notez également qu'il n'y a pas d' -kargument pour unlock-keychainque tout ce que vous essayez de faire ne semble pas correct (voir security help unlock-keychain).
Simon Urbanek
J'ai essayé quelque chose d'un peu différent, mais je suis finalement revenu au même endroit. J'ai édité ma question, j'espère qu'elle est un peu plus claire?
edelaney05
C'est complètement différent de la question d'origine ... Pour commencer, vous devez vous connecter en tant que jenkins (par exemple via sudo -u jenkins bash) et vérifier que vous avez les autorisations sur tout le chemin. Vous avez fait beaucoup de choses que vous n'avez pas dites (comme utiliser dsclpour créer l'utilisateur), donc vous êtes vraiment seul. Vous voudrez également vérifier le paramètre d'accueil (selon que vous définissez le shell ou non, vous pouvez utiliser sudo -u jenkins -ipour obtenir les paramètres de connexion correspondants).
Simon Urbanek
12

Supposons que vous souhaitiez également effectuer une distribution ad hoc via Jenkins, cela nécessite que Jenkins ait accès à un certificat de distribution et à l'identité de l'administrateur de l'équipe, en plus des profils d'approvisionnement.

En utilisant une identité exportée dans un fichier .cer, vous pouvez l'importer par programme comme ceci, le commutateur -A permet à tous les programmes d'accéder à cette entrée. Vous pouvez également utiliser plusieurs -T /path/to/programcommutateurs pour autoriser codesignet xcodebuildaccéder:

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

Bien sûr, nous devrions également avoir le certificat Apple WWDCRA, importé à peu près de la même manière:

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

Cependant, nous avons également besoin de la clé privée pour le devcertificate.cer. Pour ce faire, vous devez exporter la clé privée correspondante en tant que clé .p12 et définir un mot de passe. Placez-le quelque part où vous pouvez y accéder depuis votre shell Jenkins, déverrouillez le trousseau et importez-le:

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

L'importation du certificat de distribution fonctionne de la même manière. Je ne sais pas pourquoi vous devez déverrouiller le trousseau pour importer un .p12 et pas pour un .cer, mais bien.

Vous aurez également besoin d'accéder aux profils d'approvisionnement, je modifierai ces instructions dans cet article sous peu.

Zsub
la source
1
Pourriez-vous s'il vous plaît mettre à jour avec les instructions d'accès au profil d'approvisionnement?
Luc
5

J'ai eu le même problème et je cherche depuis un certain temps une réponse. Voici une chose que j'ai apprise.

J'utilise jenkins en tant qu'utilisateur jenkins, utilisateur créé par l'installateur, et comme tout le monde l'a mentionné, il n'a pas accès au même trousseau que votre utilisateur normal. Au lieu d'essayer de me connecter en tant qu'utilisateur jenkins, j'ai créé un deuxième projet de construction qui a simplement une étape de construction qui est "Exécuter Shell" dans lequel j'exécute les commandes que je veux tester en tant qu'utilisateur jenkins.

Une fois que j'ai mis cela en place, je pourrais exécuter la commande

security list-keychains

Et cela m'a révélé que la seule chose que jenkins pouvait voir était le trousseau système.

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

Avec cette connaissance, j'ai ensuite ouvert l'application Keychain Access et copié mon certificat «iPhone Developer: xxxx» dans le trousseau système (clic droit, copie du trousseau «login»).

Cela m'a permis de passer l'erreur de signature de code certificat / paire de clés privées, mais en a ouvert une autre avec le profil d'approvisionnement (cela semble être un problème similaire, mais différent).

Brianestey
la source
Je rencontre le même problème de profil de provision, des idées sur la façon de résoudre cela?
Santthosh
2
J'ai trouvé que les profils d'approvisionnement pour l'utilisateur Jenkins sont stockés dans '/ Users / Shared / Jenkins / Library / MobileDevice / Provisioning Profiles' et j'ai donc mis une étape dans ma construction pour copier un profil d'approvisionnement de l'intérieur de mon dépôt git vers cet emplacement. Cela me permet de mettre à jour le profil d'approvisionnement et de le pousser dans SCM et Jenkins prend automatiquement ce changement.
brianestey
si vous copiez le login.keychain dans votre bibliothèque de trousseaux jenkins, vous devrez le chown afin que l'utilisateur jenkins puisse le déverrouiller en sécurité
ganoro
1
Vous êtes le héros, je me suis déchiré les cheveux sur la tête pendant 2 jours, la copie des certificats sur le système a aidé
Roman Bobelyuk
5

Pour changer le mot de passe, vous pouvez utiliser sudo passwd jenkins <new-pw>. Cependant, je pense qu'il serait préférable d'utiliser la commande dscl pour changer le mot de passe.

Dans mon installation, jenkins (installateur officiel) avait un shell utilisateur / usr / bin / false. Le changer en bash a résolu le problème de ne pas pouvoir se connecter:

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

Vous devriez maintenant pouvoir vous connecter avec su jenkins.

Ivo Dancet
la source
Cela m'a été très utile - j'ai eu un problème similaire avec la create-keychaincommande ne fonctionnant pas avec l'utilisateur jenkins. L'exécution de cette commande a semblé résoudre le problème.
lxt
Lorsque j'exécute la commande pour changer le mot de passe de l'utilisateur jenkins, on me demande le mot de passe actuel. Je n'ai aucune idée de ce que c'est et je ne peux pas appuyer sur Entrée. Aucune suggestion?
CMVR
4

J'ai utilisé le plugin Xcode pour créer une application iOS. En configuration d'un projet.

Choisissez Ajouter une étape de construction> Xcode> Options de signature de code et de trousseau OS X.

cochez la case Déverrouiller le trousseau et ajoutez comme suit (pour des exemples) entrez la description de l'image ici

parfois, si j'obtiens l'erreur

Erreur de signe de code: ...

Je vais rouvrir Jenkins et entrer à nouveau le mot de passe pour déverrouiller

biolinh
la source
3

Pour les personnes ayant des problèmes avec les porte-clés, je vous recommanderais d'essayer mon autre programme d'installation Jenkins à https://github.com/stisti/jenkins-app , à télécharger sur https://github.com/stisti/jenkins-app/downloads

Jenkins.app exécute Jenkins dans votre session utilisateur, les problèmes d'accès au trousseau ne sont donc pas un problème :)

sti
la source
Le problème est que cet utilisateur Jenkins est dans l'espace utilisateur et non dans l'espace démon ... donc si un attaquant pouvait compromettre votre utilisateur Jenkins, il aurait un accès complet à votre ordinateur.
edelaney05
Cela pourrait résoudre les problèmes que j'ai rencontrés. Le problème est que j'ai une installation Jenkins existante (faite dans l'autre sens) et je ne veux pas perdre toutes mes compilations - etc. Que se passera-t-il dans mon cas?
Mike S
2

Si vous avez sudo, vous pouvez utiliser passwd pour changer le mot de passe de l'utilisateur Jenkins. Ensuite, vous pouvez obtenir le mot de passe Jenkins.

De plus, je ne sais pas si c'est le problème pour vous, mais le script ANT que j'utilise via Jenkins a ceci:

<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>
Feasoron
la source
1
Il semble que vous ayez installé Jenkins sous un utilisateur "macbuild"; Je suppose que cet utilisateur est un utilisateur et non un démon. Je comprends vraiment (maintenant) que le trousseau devra être déverrouillé via les arguments de ligne de commande (voir les commentaires de Simon Urbanek), mais je ne sais toujours pas comment créer un trousseau par défaut pour le démon jenkins.
edelaney05
1

Pour une raison quelconque, l'utilitaire "sécurité" ne fonctionnait pas pour moi sur Lion avec la nouvelle installation de Jenkins.

Après "sudo su jenkins", il a pu créer un nouveau trousseau, mais a ignoré silencieusement toutes les commandes "default-keychain -s ..." ou "unlock" retournant zéro statut de sortie et n'imprimant rien sur la console. La liste des porte-clés par défaut ou de connexion ne donnait rien, la liste de recherche des porte-clés ne contenait que le porte-clés système, et je ne pouvais pas changer cela quoi que je tape.

Après m'être connecté au bureau de cet utilisateur et lancé Keychain Utility, il a montré mon trousseau créé et après cela, tout a fonctionné comme décrit dans les articles supérieurs.

Je me demande si certains des comportements initiaux des porte-clés ont changé dans Lion, ou est-ce que je manque quelque chose?

jazzcat
la source
J'ai effectué les étapes ci-dessus sur une installation "propre" de Lion, donc peut-être y avait-il un problème de sécurité avant de vous lancer? Une autre possibilité est qu'il y ait eu une mise à jour de sécurité / OS X depuis ma publication initiale?
edelaney05
0

J'ai ajouté la clé privée et publique de l'entreprise au trousseau. J'ai ajouté les profils de mise à disposition pour la production que je construirai.

Étant donné que cet utilisateur n'avait pas de compte, je me suis connecté à devcenter avec mon compte. Téléchargé les certificats d'approvisionnement et les charge dans Xcode.

Je n'ai pas ajouté de certificat spécifiquement pour le compte de rôle de build, ex. jenkins.

J'ai ajouté ceci au script de construction: security unlock-keychain -p mySecretPassword comme ci-dessus, mais ...

J'ai créé un fichier ~ / .ssh / mypass et ai ajouté le mot de passe au fichier.

Ensuite, la commande devient: security unlock-keychain -p cat ~/.ssh/mypass

Les builds fonctionnent comme un champion. Je reçois le fichier ipa, il se charge sur l'application centrale et fonctionne sur l'appareil.

mpechner
la source
0

Pourrait également installer et lancer JenkinsCI en tant qu'utilisateur OS X au lieu d'un démon:

  1. installez jenkins en utilisant le programme d'installation officiel ( https://jenkins-ci.org/ )
    • Cliquez sur Suivant
    • Cliquez sur "Personnaliser"
    • Désélectionnez "Démarrer au démarrage en tant que 'jenkins'" - * IMPORTANT * cette option autorise normalement un jenkins sans tête qui ne fonctionne pas bien avec l'accès au trousseau
  2. lancement http://127.0.0.1:8080
    • vérifiez qu'il ne se lance PAS
    • peut avoir besoin d'arrêter jenkins sudo launchctl unload /Library/LaunchDaemons/org.jenkins-ci.plist
  3. Double clic /Applications/Jenkins/jenkins.war
    • bien sûr, cela devrait être automatisé pour démarrer @ démarrer
  4. Ouvert http://127.0.0.1:8080
    • vérifier qu'il est maintenant en cours d'exécution
scotopique
la source