106 votes

Jenkins sur OS X : xcodebuild donne l'erreur Code Sign

Résumé :

La configuration de Jenkins sous OS X a été considérablement simplifiée avec le plus récent installateur ( à partir de 1.449 - 9 mars 2012 ), mais la gestion du processus de signature du code reste très difficile et il n'y a pas de réponse directe.

Motivation :

Exécuter un serveur CI sans tête qui suit les meilleures pratiques courantes pour l'exécution de services sur OS X ( Certaines d'entre elles sont expliquées ici en langage clair ).

Le contexte :

Processus :

Installer Jenkins CI via OS X paquet 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 la construction script. xcodebuild -target MyTarget -sdk iphoneos devrait fonctionner. Comme l'indique le titre de ce post, ce n'est pas le cas et il é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 de clés par défaut. En cherchant comment accomplir cela, 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 de clés par défaut pour le démon jenkins

sudo -u jenkins security default-keychain ...donne "Un trousseau par défaut n'a pas pu être trouvé".

Comme le souligne ci-dessous Ivo Dancet le UserShell est défini par défaut sur /usr/bin/false pour le daemon jenkins (je pense que c'est une fonctionnalité, pas un bug) ; suivez sa réponse pour changer le UserShell en bash. Vous pouvez alors utiliser sudo su jenkins pour être connecté en tant qu'utilisateur de 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

Ok, super. Nous avons maintenant un trousseau par défaut, passons à autre chose, d'accord ? Mais d'abord, pourquoi avons-nous pris la peine de faire un trousseau par défaut ?

Presque toutes les réponses, suggestions ou conversations que j'ai lues au cours de mes recherches suggèrent que l'on devrait simplement balancer ses certificats de signature de code et ses clés dans le trousseau du système. Si vous exécutez security list-keychains en tant que projet de style libre dans Jenkins, vous voyez que le seul trousseau disponible est le trousseau du système ; je pense que c'est là que la plupart des gens ont eu l'idée d'y placer leur certificat et leur clé. Mais, cela semble être une très mauvaise idée - surtout si l'on considère que vous devrez créer un script en texte brut avec le mot de passe pour ouvrir le trousseau. .

Problème 2 : Ajout des certs de signature de code et de la clé privée

C'est là que je commence vraiment à être dégoûté. J'ai l'intuition que je devrais créer une nouvelle clé publique/privée unique pour l'utilisation de Jenkins. Je pense 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 d'utilisateur et Jenkins, cela signifie plus de tracas (dommages ?) si le service jenkins est attaqué.

Pointer vers La réponse de Simon Urbanek vous déverrouillerez le trousseau de clés à partir d'un script avec un mot de passe en texte clair. Il semble irresponsable de conserver autre chose que des certificats et des clés "jetables" dans le trousseau de clés du démon jenkins.

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

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

  1. sudo su jenkins
  2. certtool r CertificateSigningRequest.certSigningRequest Vous serez invité à répondre aux questions suivantes (pour la plupart, j'ai fait des suppositions sur la bonne réponse ; avez-vous une meilleure idée ? 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 une série de questions pour RDN
  3. Soumettez le fichier CSR généré (CertificateSigningRequest.certSigningRequest) au portail d'approvisionnement d'Apple sous un nouvel identifiant Apple.
  4. Approuver la demande et télécharger 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 de clés

J'ai créé un profil de provisionnement spécial dans le portail de provisionnement uniquement pour l'utilisation de CI, dans l'espoir que si quelque chose de grave se produit, l'impact sera un peu plus faible. Meilleure pratique ou excès de prudence ?

  1. sudo su jenkins
  2. mkdir ~/Library/MobileDevice
  3. mkdir ~/Library/MobileDevice/Provisioning\ Profiles
  4. Déplacez le profil de provisionnement que vous avez configuré dans le portail de provisionnement dans ce nouveau dossier. Nous sommes maintenant à deux petits pas de pouvoir exécuter xcodebuild à partir de la ligne de commande comme jenkins, et donc cela signifie que nous sommes également proches de pouvoir obtenir le CI de Jenkins exécutant des constructions.
  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 sommes connectés en tant que démon jenkins, donc si nous créons un projet de style libre et ajoutons ces deux dernières étapes (#5 et #6 ci-dessus), nous serons en mesure d'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 à configurer tout cela. Suis-je paranoïaque ?

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

( EDIT : J'ai posté les modifications apportées à ma question, j'ai redémarré pour m'assurer que ma solution était à 100%, et bien sûr, j'avais oublié une étape. )

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

Il devrait ressembler à ceci :

<?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 recommande également le Plugin Xcode pour Jenkins ce qui rend la mise en place du script de xcodebuild un peu plus facile. A ce stade, je vous recommande également de lire les pages de manuel de xcodebuild - vous êtes arrivé jusqu'ici dans le Terminal, non ?

Cette configuration n'est pas parfaite, et tout conseil ou avis est grandement apprécié.

J'ai eu du mal à choisir une réponse "correcte", car ce que j'ai utilisé pour résoudre mon problème était une collection des contributions de tout le monde. J'ai essayé de donner à chacun au moins un vote positif, mais j'ai attribué la réponse à Simon parce qu'il a surtout répondu à la question originale. En outre, Sami Tikka mérite beaucoup de crédit pour ses efforts visant à faire fonctionner Jenkins avec AppleScript en tant qu'application OS X ordinaire. Si vous souhaitez uniquement faire fonctionner Jenkins rapidement dans votre session utilisateur (c'est-à-dire pas en tant que serveur sans tête), sa solution est beaucoup plus proche de celle du Mac.

J'espère que mes efforts susciteront d'autres discussions et qu'ils aideront la prochaine pauvre âme qui se présente en pensant qu'elle peut configurer Jenkins CI pour ses projets iOS en un week-end grâce à toutes les merveilleuses choses qu'elle a entendues à son sujet.


Mise à jour : 9 août 2013

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

Leçon 1 : Ne pas exposer Jenkins à l'internet public

Lors de la WWDC 2012, j'ai soumis cette question aux ingénieurs de Xcode et d'OS X Server. J'ai reçu une cacophonie de "ne faites pas ça !" de la part de tous ceux à qui j'ai posé la question. Ils étaient tous d'accord pour dire qu'un processus de construction automatisé était formidable, mais que le serveur ne devait ê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 un VPN.

Leçon 2 : il existe désormais de nouvelles options d'installation

J'ai récemment donné une conférence à CocoaHeads sur mon expérience de Jenkins, et à ma grande surprise, j'ai découvert de nouvelles méthodes d'installation - Homebrew et même une Bitnami Mac App Store version. Elles valent vraiment la peine d'être vérifiées. Jonathan Wright a un aperçu détaillant l'obtention Homebrew Jenkins fonctionne .

Leçon 3 : Non, sérieusement, n'exposez pas votre boîtier de montage à l'internet.

Il est clair, d'après le message original, que je ne suis ni administrateur système ni expert en sécurité. Le bon sens à propos des choses privées (trousseaux de clés, informations d'identification, certificats, etc.) m'a laissé un sentiment de malaise à l'idée de mettre ma boîte Jenkins sur Internet. Nick Arnott à Neglected Potential a pu confirmer mes frissons assez facilement en cet article .

TL;DR

Mes recommandations aux personnes qui cherchent à automatiser leur processus de construction ont changé au cours des 18 derniers mois. Assurez-vous que votre machine Jenkins est derrière votre pare-feu. Installez et configurez Jenkins en tant qu'utilisateur Jenkins dédié, en utilisant le programme d'installation, la version Mac App Store de Bitnami, l'AppleScript de Sami Tikka, etc. Si vous avez besoin d'un accès à distance, la configuration des services VPN dans OS X Server prend dix minutes au maximum. J'utilise cette configuration depuis plus d'un an et j'en suis très satisfait. Bonne chance !

30voto

Simon Urbanek Points 7803

Les porte-clés doivent être déverrouillés avant de pouvoir être utilisés. Vous pouvez utiliser security unlock-keychain à 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 (non sûr), par ex :

security unlock-keychain -p mySecretPassword...

Il est évident que le fait de placer ces informations dans un script compromet la sécurité de ce trousseau, c'est pourquoi les gens configurent souvent un trousseau individuel avec uniquement les informations de signature pour minimiser ces dommages.

Généralement dans Terminal le trousseau est déjà déverrouillé par votre session, puisque le trousseau par défaut est déverrouillé à la connexion, donc vous n'avez pas besoin de faire cela. Cependant, tout processus qui n'est pas exécuté dans votre session n'aura pas de trousseau déverrouillé, même s'il vous a comme utilisateur (le plus souvent, cela concerne ssh mais aussi tout autre processus).

12voto

Zsub Points 921

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 de manière programmatique comme suit : le commutateur -A permet à tous les programmes d'accéder à cette entrée. Alternativement, vous pouvez utiliser plusieurs -T /path/to/program pour permettre codesign et xcodebuild accès. :

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

Bien entendu, nous devrions également disposer du 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 programme devcertificate.cer . Pour ce faire, vous devez exporter la clé privée correspondante sous forme de clé .p12 et définir un mot de passe. Placez-la dans un endroit où vous pouvez y accéder depuis votre shell Jenkins, déverrouillez le trousseau de clés et importez-la :

$ 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 bon.

Vous aurez également besoin d'accéder aux profils d'approvisionnement, je vais éditer ces instructions dans ce post sous peu.

5voto

brianestey Points 3206

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

J'exécute 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 de clés que l'utilisateur normal. Au lieu d'essayer de se connecter en tant qu'utilisateur jenkins, j'ai créé un deuxième projet de construction qui a simplement une étape de construction qui est "Execute Shell" dans lequel je lance les commandes que je veux tester en tant qu'utilisateur jenkins.

Une fois que j'ai eu cette configuration, j'ai pu lancer la commande

security list-keychains

Et cela m'a révélé que la seule chose que Jenkins pouvait voir était le trousseau de clés du 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, copier depuis le trousseau "login").

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

5voto

Ivo Dancet Points 61

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 l'impossibilité de se connecter :

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

Vous devriez maintenant être en mesure de vous connecter avec su jenkins .

4voto

biolinh Points 71

J'ai utilisé le plugin Xcode pour construire une application iOS. Dans la configuration d'un projet.

choisissez Ajouter l'étape de construction > Xcode > signature de code et options de trousseau de clés OS X.

tique Porte-clés de déverrouillage et ajoutez ce qui suit (à titre d'exemple) enter image description here

Parfois, si je reçois l'erreur

Erreur de signature du code : ...

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X