Jenkins Credentials Manager + Active Choices

Oct 07 2020

Je veux accéder aux informations d'identification Jenkins pour m'authentifier avec Git avant le script de pipeline - pour remplir le paramètre Active Choices.

Dans le pipeline, je le fais simplement avec withCredentials. Mais pendant la phase de pré-pipeline (c'est-à-dire le paramètre Active Choices) les extensions Hudson telles que withCredentialsou sshAgentne sont pas accessibles. Actuellement, git ls-remote -h [email protected]:repo.gitj'exécute groovy avec une clé non chiffrée dans le répertoire jenkins_home (ce qui n'est pas une bonne idée).

Je sais qu'il existe une possibilité d'importer et de construire des objets Java en lisant le code source de Jenkin et de ses plugins - mais cela semble infini.

Donc: est-il possible d'importer et d'appliquer facilement des extensions Hudson au script Groovy actuel ou est-ce que quelqu'un a une solution toute prête pour cela (apparemment personne n'a rien publié à ce sujet)?

Réponses

jayhendren Oct 08 2020 at 03:41

Il me semble que vous êtes déjà au courant de cela, mais il y a quelques moyens simples de le faire, et quelques moyens difficiles de le faire.

Les moyens faciles:

  • Rendez votre dépôt disponible pour le paiement sans clés SSH ni informations d'authentification.
  • Ajoutez manuellement une paire de clés SSH pour le retrait du dépôt à l'utilisateur Jenkins sur votre nœud maître Jenkins (puisque les scripts Active Choice Groovy s'exécutent sur le nœud maître) (c'est-à-dire n'utilisez pas le magasin d'informations d'identification).

Les moyens difficiles:

  • Utilisez l'API Java Jenkins dans votre code Active Choices pour extraire les informations d'identification du magasin d'informations d'identification. Les documents d'API sont disponibles pour le magasin d'informations d'identification et le type d'informations d'identification ssh . Il n'y a pas de documentation sur la façon d'utiliser les classes Java disponibles dans ces plugins, c'est donc à vous de le découvrir vous-même.
  • Créez un travail "méta" secondaire pour mettre à jour les paramètres dans le travail Jenkins d'origine (y compris les scripts Active Choices) - je le décris un peu ci-dessous.

Si vous ne pouvez pas faire l'une des solutions simples pour des raisons de sécurité, il n'existe pas de moyen simple et direct de mettre à jour les paramètres Active Choice en fonction du contenu d'un dépôt git. Ceci est dû au fait:

  1. Comme vous l'avez dit, "pendant la phase de pré-pipeline (c'est-à-dire le paramètre Active Choices), les extensions Hudson telles que withCredentials ou sshAgent ne sont pas accessibles".
  2. La configuration des paramètres, y compris les paramètres Active Choice, est tirée de la précédente exécution de ce pipeline, et non de celle actuelle. Cela signifie que, pour mettre à jour vos paramètres à partir de votre code Pipeline, vous devrez exécuter votre Pipeline, ce qui va à l'encontre de ce que vous voulez faire.

Il existe une solution pour 1., qui consiste à utiliser des pipelines scriptés au lieu de déclaratifs, mais cela ne contournera pas les problèmes de 2.

La solution que j'ai trouvée lorsque j'ai rencontré ce problème est de créer un deuxième travail Jenkins (je l'appelle un travail "méta") qui met à jour les paramètres du travail d'origine, y compris les scripts Active Choices. Cette deuxième méta-tâche est déclenchée par un hook git sur le référentiel que j'utilise pour remplir les options de mes paramètres Active Choices. Cela présente l'avantage que vous n'avez pas besoin d'exécuter le pipeline du travail d'origine pour mettre à jour ses paramètres, ce qui résout les problèmes de 2. De plus, comme il s'agit toujours d'un travail de pipeline, vous pouvez utiliser les étapes normales du pipeline, vous permettant ainsi d'accéder au magasin d'informations d'identification.

Mon travail ressemble (à peu près) à ceci - je l'ai beaucoup simplifié pour l'adapter ici, vous devrez donc faire quelques ajustements pour le faire fonctionner comme vous le souhaitez. Il y a probablement une tonne d'erreurs et de bugs là-dedans parce que j'ai déchiré un script existant pour le faire. Quelques points à noter:

  • Cela fait un usage intensif des API Jenkins, vous devrez donc désactiver le bac à sable de script ou mettre en liste blanche une tonne de fonctions dans le gestionnaire de sécurité Jenkins pour que cela s'exécute.
  • Il s'agit toujours techniquement d'un pipeline scripté même s'il ressemble beaucoup plus à un script Groovy normal qu'à un fichier Pipeline
  • Étant donné qu'il s'agit d'un pipeline, vous pouvez utiliser des étapes telles que l' withCredentialsextraction de référentiels à l'aide du magasin d'informations d'identification.
import groovy.json.JsonOutput

import org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript 

import org.biouno.unochoice.*
import org.biouno.unochoice.model.*

def metadataUrl = 'ssh://git@**************/metadata.git'
def metadataBranch = 'master'

def metadata = [:]

node('master') {
  git(
    url: metadataUrl,
    branch: metadataBranch,
    credentialsId: 'jenkins',
    changelog: false,
  )

  def dataDir = "${pwd()}/myJsonFiles" // can't use File.eachFileMatch() due to: // https://wiki.jenkins.io/display/JENKINS/Pipeline+CPS+method+mismatches def files = new File(dataDir).list().findAll() { f-> FilenameUtils.getExtension(f) == 'json' } files.each() { f-> // TODO: nice error messages if files are misformatted def name = FilenameUtils.removeExtension(f) def data = readJson(file: "${dataDir}/${f}") metadata[name] = data } } // ChoiceParameterDefinition is the class name for the built-in static choice parameter. // CascadeChoiceParameter is the class name for the Active Choices dynamic choice parameter. // begin first parameter def fileParam = new ChoiceParameterDefinition( 'file', 'The JSON file to use', ) fileParam.setChoices(metadata.keySet()) // end first parameter // begin second parameter def metadataJson = JsonOutput.toJson(metadata) def scriptText = """ import groovy.json.JsonSlurper def slurper = new JsonSlurper() def metadata = slurper.parseText('${metadataJson}')

return metadata[file]['versions']
"""
def mainScript = new SecureGroovyScript(scriptText, true)
def fallbackScript = new SecureGroovyScript('return ["Error encountered - see logs"]', true)
def activeChoiceScript = new GroovyScript(mainScript, fallbackScript)

def versionParam = new CascadeChoiceParameter(
  'version', 
  'The version to use',
  activeChoiceScript,
  'PT_SINGLE_SELECT',
  'file',
  false,
)
// end second parameter


def paramProp = new ParametersDefinitionProperty(fileParam, versionParam)


// this is the full name of the actual job which needs dynamic parameters
def job = Jenkins.instance.getItemByFullName('UNIX/deploy_to_environment/master')


// There is no "setProperty" - we need to remove and replace.
// removeProperty is safe to run even if no matching properties are set on the job.
// However, this method only removes one property per method call.
// Theoretically, this means the job could accumulate multiple conflicting
// ParametersDefinitionProperty properties.
// TODO: run removeProperty in a while loop to eliminate all matching properties for extra safety.
job.removeProperty(ParametersDefinitionProperty)

job.addProperty(paramProp)