
Sécurité et gestion des ressources
Optimisez la sécurité et la gestion des ressources de votre Jenkins : credentials, agents distribués, nettoyage des workspaces. Assurez la fiabilité et la performance de vos pipelines.
Sécurité et gestion des ressources : les garants d'un Jenkins performant et fiable
Au-delà de la simple automatisation des tâches, un serveur Jenkins robuste et digne de confiance repose sur deux piliers fondamentaux : une sécurité rigoureuse et une gestion efficace de ses ressources. Négliger ces aspects peut transformer votre précieux outil d'automatisation en une porte d'entrée pour des menaces ou en une source de lenteurs et d'instabilité. Ce chapitre est dédié à vous fournir les bonnes pratiques essentielles pour sécuriser votre instance Jenkins et optimiser son utilisation des ressources système.
Nous aborderons trois domaines critiques. Premièrement, la gestion sécurisée des informations sensibles, comme les mots de passe et les clés API, grâce au système de "Credentials" intégré à Jenkins. Deuxièmement, l'importance de ne pas exécuter les builds sur le noeud master et de déléguer cette charge à des agents dédiés, pour des raisons de performance et de sécurité. Enfin, nous discuterons des stratégies de nettoyage régulier des espaces de travail (workspaces) et des artefacts de build pour maintenir une instance Jenkins saine et performante.
En maîtrisant ces pratiques, vous serez en mesure de construire un environnement Jenkins non seulement fonctionnel, mais aussi sécurisé, stable et capable de monter en charge efficacement pour répondre aux besoins croissants de vos projets. Ces éléments sont indispensables pour garantir la pérennité et la fiabilité de votre infrastructure CI/CD.
Utiliser le gestionnaire de "Credentials" pour les informations sensibles : une règle d'or
L'une des erreurs de sécurité les plus courantes et les plus graves dans un contexte d'automatisation est de stocker des informations sensibles (mots de passe, tokens d'accès API, clés SSH, certificats, etc.) en clair directement dans les scripts de pipeline ou dans la configuration des Jobs. Cette pratique expose dangereusement ces secrets, les rendant vulnérables au vol ou à une utilisation abusive. Jenkins fournit une solution robuste et sécurisée pour gérer ce type d'informations : le gestionnaire de "Credentials" (Identifiants).
Le principe est simple : vous enregistrez vos informations sensibles une seule fois dans le gestionnaire de credentials de Jenkins, en leur attribuant un ID unique et une description. Jenkins se charge ensuite de les stocker de manière chiffrée (le niveau de chiffrement dépend de la configuration de Jenkins et des plugins installés). Lorsque votre pipeline a besoin d'utiliser un secret, il ne fait plus référence à la valeur du secret elle-même, mais à l'ID du credential correspondant. Jenkins injectera alors la valeur du secret de manière sécurisée dans l'environnement d'exécution du build, souvent sous forme de variable d'environnement ou via des mécanismes spécifiques aux plugins.
Jenkins supporte différents types de credentials :
- Username with password : Pour les couples identifiant/mot de passe.
- SSH Username with private key : Pour l'authentification SSH via clé privée (par exemple, pour se connecter à des serveurs distants ou cloner des dépôts Git privés).
- Secret text : Pour des chaînes de caractères arbitraires comme des tokens API.
- Secret file : Pour des fichiers entiers qui sont sensibles (certificats, fichiers de configuration).
- Certificate : Pour les certificats PKCS#12.
Pour utiliser un credential dans un `Jenkinsfile` Déclaratif, vous pouvez utiliser le helper `credentials()` dans un bloc `environment` ou directement dans un `step` avec le wrapper `withCredentials`. Exemple :
pipeline {
agent any
environment {
// Injecter un secret text comme variable d'environnement
API_TOKEN = credentials('mon-api-token-id')
}
stages {
stage('Deploy') {
steps {
// Utilisation de la variable d'environnement
sh 'curl -H "Authorization: Bearer ${API_TOKEN}" https://api.example.com/deploy'
}
}
stage('SSH Connection') {
steps {
// Utilisation d'un credential SSH
withCredentials([sshUserPrivateKey(credentialsId: 'ma-cle-ssh-id',
keyFileVariable: 'SSH_KEY_FILE',
usernameVariable: 'SSH_USER')]) {
// La clé privée est disponible temporairement dans le fichier pointé par SSH_KEY_FILE
// L'utilisateur est dans SSH_USER
sh 'ssh -i ${SSH_KEY_FILE} ${SSH_USER}@serveur.example.com "ls -la"'
}
}
}
}
}L'utilisation systématique du gestionnaire de credentials est une pratique de sécurité non négociable. Elle centralise la gestion des secrets, permet de limiter leur portée (vous pouvez définir des credentials globaux ou spécifiques à des dossiers/Jobs), et facilite leur rotation en cas de compromission (il suffit de mettre à jour le credential dans Jenkins, sans modifier les pipelines).
Eviter d'exécuter des builds sur le noeud master : déléguer aux agents
Le noeud master de Jenkins (anciennement appelé "Jenkins controller") a un rôle central : il héberge l'interface utilisateur, coordonne l'exécution des pipelines, gère les configurations, stocke les logs de build, etc. Il est donc crucial pour le bon fonctionnement de votre instance Jenkins. Une pratique fondamentale pour assurer sa stabilité, sa performance et sa sécurité est d'éviter d'y exécuter directement les tâches de build.
Exécuter des builds sur le master présente plusieurs risques :
- Consommation de ressources : Les builds peuvent être gourmands en CPU, mémoire, et I/O disque. Si ces ressources sont consommées par les builds sur le master, cela peut ralentir, voire rendre instable, l'interface Jenkins et sa capacité à orchestrer d'autres tâches.
- Sécurité : Les scripts de build, surtout s'ils proviennent de sources non totalement maîtrisées, peuvent potentiellement contenir du code malveillant ou introduire des vulnérabilités. Exécuter cela sur le master, qui a accès à toutes les configurations de Jenkins, est un risque de sécurité majeur.
- Pollution de l'environnement : Les builds peuvent installer des dépendances, modifier des fichiers système, ou laisser des fichiers temporaires. Cela peut polluer l'environnement du master et créer des conflits entre différents builds ou avec le fonctionnement de Jenkins lui-même.
- Manque de flexibilité : Le master a un environnement fixe. Vous ne pouvez pas facilement avoir des environnements de build différents (ex: différentes versions de JDK, différents OS) si tout s'exécute sur le master.
La solution est d'utiliser des agents Jenkins (anciennement appelés "slaves" ou "nodes"). Un agent est une machine (physique, virtuelle, ou un conteneur Docker) connectée au master Jenkins, et dont le rôle est d'exécuter les tâches de build que le master lui délègue. Vous pouvez configurer plusieurs agents avec des environnements différents (OS, outils installés, labels spécifiques). Dans votre `Jenkinsfile`, vous spécifiez sur quel type d'agent votre pipeline (ou une étape spécifique) doit s'exécuter en utilisant la directive `agent` :
pipeline {
// Exécuter sur n'importe quel agent disponible
agent any
// Exécuter sur un agent ayant le label 'linux-build'
// agent { label 'linux-build' }
// Exécuter dans un conteneur Docker
// agent {
// docker {
// image 'maven:3.8.1-jdk-11'
// args '-v /tmp:/tmp'
// }
// }
stages {
stage('Build') {
// Ce stage utilisera l'agent défini au niveau du pipeline
steps {
sh 'mvn clean package'
}
}
stage('Deploy Windows App') {
// Ce stage peut nécessiter un agent Windows spécifique
agent { label 'windows-server' }
steps {
bat 'deploy-app.bat'
}
}
}
}Par défaut, après l'installation, Jenkins est configuré pour autoriser les builds sur le master. Il est fortement recommandé de modifier cette configuration (via "Manage Jenkins" > "Configure System" > "# of executors" sur le master, le mettre à 0) pour empêcher cela et forcer l'utilisation d'agents. Cela isole les charges de travail, améliore la sécurité, la stabilité, et permet une bien meilleure scalabilité de votre infrastructure CI/CD.
Nettoyer régulièrement l'espace de travail et les artefacts : une hygiène nécessaire
Chaque exécution d'un Job Jenkins (un "build") utilise un espace de travail (workspace) sur l'agent où le code source est récupéré et où les opérations de build (compilation, tests, etc.) sont effectuées. De plus, les builds peuvent générer des "artefacts" : des fichiers produits par le build que vous souhaitez conserver (ex: des JARs, des WARs, des rapports de test, des logs). Avec le temps, ces workspaces et ces artefacts peuvent consommer une quantité considérable d'espace disque, à la fois sur les agents et sur le master (où les archives d'artefacts et les logs de build sont stockés).
Un manque de nettoyage régulier peut entraîner plusieurs problèmes :
- Saturation de l'espace disque : C'est le problème le plus évident, pouvant empêcher de nouveaux builds de s'exécuter ou même rendre instable le système d'exploitation de l'agent ou du master.
- Ralentissement des opérations : Des workspaces volumineux peuvent ralentir les opérations de checkout SCM ou d'autres tâches manipulant des fichiers.
- Builds non reproductibles ou pollués : Si les workspaces ne sont pas nettoyés entre les builds, des fichiers résiduels d'un build précédent pourraient interférer avec le build actuel, conduisant à des résultats inattendus ou des échecs difficiles à diagnostiquer.
Jenkins offre plusieurs mécanismes pour gérer cette accumulation de données. Pour la gestion des anciens builds, vous pouvez configurer chaque Job pour ne conserver qu'un certain nombre de builds récents ou les builds des X derniers jours (option "Discard old builds" dans la configuration du Job ou via la directive `options { buildDiscarder(...) }` dans un `Jenkinsfile` Déclaratif). Lorsque Jenkins supprime un ancien build, il supprime également les artefacts et les logs associés.
pipeline {
agent any
options {
// Conserver les 10 derniers builds
buildDiscarder(logRotator(numToKeepStr: '10'))
// Ou conserver les builds des 7 derniers jours, mais au moins 5 builds
// buildDiscarder(logRotator(daysToKeepStr: '7', numToKeepStr: '5'))
}
stages {
// ...
}
}Pour le nettoyage du workspace, il est crucial de s'assurer que chaque build démarre dans un environnement propre. Vous pouvez utiliser l'option "Delete workspace before build starts" dans la configuration d'un Job Freestyle, ou, de manière plus flexible dans un pipeline, utiliser le step `cleanWs()` typiquement dans un bloc `post always` pour garantir que le workspace est nettoyé après chaque exécution, qu'elle ait réussi ou échoué.
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'echo "Building..."'
// Checkout et build
}
}
}
post {
always {
echo 'Nettoyage du workspace...'
cleanWs()
// On peut aussi choisir de nettoyer des fichiers spécifiques
// deleteDir() // Attention, cela supprime le répertoire courant du workspace
}
}
}Il existe également des options plus avancées avec le plugin Workspace Cleanup qui offre plus de contrôle. Une bonne hygiène de l'espace de travail et des artefacts est essentielle pour maintenir une instance Jenkins performante, fiable et pour éviter les mauvaises surprises liées à la saturation disque ou à la pollution entre les builds.