« Pour déployer, je donne à Jenkins mon kubeconfig admin, c’est plus simple. »
Jamais. Un serveur CI qui détient les pleins pouvoirs sur le cluster est une catastrophe de sécurité en attente. On donne à Jenkins une identité dédiée et limitée : le droit de déployer uniquement dans son namespace, rien d’autre. C’est le principe de moindre privilège, appliqué au CD.
À la fin de ce module, tu sauras…
- Installer Helm sur la VM Jenkins et comprendre pourquoi il déploie localement
- Créer une identité cluster limitée (ServiceAccount + Role + RoleBinding)
- Générer un kubeconfig dédié et l’injecter comme credential
- Ajouter un stage Deploy qui met à jour la release via Helm
01Donner Helm à Jenkins
L’outil de déploiement, côté Jenkins
Le stage Deploy utilisera Helm : il doit être présent sur la VM Jenkins (c’est Jenkins qui déploie). Installe-le en binaire autonome :
Manipulecurl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
helm versionObserveversion.BuildInfo{Version:"v3.x.x", ...}helm upgrade depuis le pipeline.Comprends deux patterns de CD, et pourquoi celui-ci
Pattern A (celui-ci) : Jenkins exécute Helm localement, en pointant vers l’API du cluster via un kubeconfig. Pattern B : Jenkins se connecte en SSH à un nœud et y lance Helm. A est plus propre — pas de couplage à une machine précise, tout passe par l’API Kubernetes. C’est aussi ce que fait un outil comme Argo CD, en continu : parler à l’API du cluster avec une identité limitée. Le concept (identité + API) survit au changement d’outil.
02Une identité limitée sur le cluster
ServiceAccount + Role + RoleBinding
Sur le nœud master, crée une identité jenkins-cd qui ne peut agir que dans lab-soria :
cat > /tmp/jenkins-cd-rbac.yaml <<'EOF'
apiVersion: v1
kind: ServiceAccount
metadata:
name: jenkins-cd
namespace: lab-soria
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: jenkins-cd-role
namespace: lab-soria
rules:
- apiGroups: [""]
resources: ["configmaps","secrets","services","pods","pods/log","events"]
verbs: ["get","list","watch","create","update","patch","delete"]
- apiGroups: ["apps"]
resources: ["deployments","replicasets"]
verbs: ["get","list","watch","create","update","patch","delete"]
- apiGroups: ["networking.k8s.io"]
resources: ["ingresses"]
verbs: ["get","list","watch","create","update","patch","delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: jenkins-cd-binding
namespace: lab-soria
subjects:
- kind: ServiceAccount
name: jenkins-cd
namespace: lab-soria
roleRef:
kind: Role
name: jenkins-cd-role
apiGroup: rbac.authorization.k8s.io
EOF
kubectl apply -f /tmp/jenkins-cd-rbac.yaml
kubectl -n lab-soria get sa jenkins-cdlab-soria. Aucun droit ailleurs, aucun droit cluster-admin.Comprends le modèle RBAC, universel
Trois objets : le ServiceAccount (l’identité), le Role (quelles actions sur quelles ressources, dans un namespace), le RoleBinding (qui relie l’identité au rôle). C’est le modèle RBAC de Kubernetes : « qui peut faire quoi, où ». Les verbes autorisés couvrent exactement ce dont Helm a besoin pour gérer l’app — ni plus. Ce raisonnement « donner juste les droits nécessaires » vaut pour tout outil de CD.
03Fabriquer un kubeconfig dédié
Un kubeconfig pour cette identité
ManipuleSA=jenkins-cd
NS=lab-soria
TOKEN=$(kubectl -n $NS create token $SA --duration=8760h)
CA=$(kubectl -n kube-system get configmap kube-root-ca.crt -o jsonpath='{.data.ca\.crt}')
SERVER=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}')
cat > /tmp/kubeconfig-jenkins-cd.yaml <<EOF
apiVersion: v1
kind: Config
clusters:
- name: k3s
cluster:
server: ${SERVER}
certificate-authority-data: $(printf "%s" "$CA" | base64 -w0)
contexts:
- name: jenkins-cd@k3s
context:
cluster: k3s
namespace: ${NS}
user: jenkins-cd
current-context: jenkins-cd@k3s
users:
- name: jenkins-cd
user:
token: ${TOKEN}
EOF
ls -la /tmp/kubeconfig-jenkins-cd.yamlserver:. Il doit contenir une adresse d’API joignable depuis la VM Jenkins. Si c’est https://127.0.0.1:6443 ou une IP interne inaccessible, le deploy échouera. Vérifie et, au besoin, remplace par l’IP réseau du master atteignable par Jenkins.Comprends ce que contient un kubeconfig
Un kubeconfig = où est l’API (server), comment vérifier son certificat (certificate-authority-data), et qui tu es (token du ServiceAccount). Avec ces trois éléments, Helm/kubectl peut parler au cluster en tant que jenkins-cd, borné à son namespace.
04Injecter le kubeconfig dans Jenkins
Un credential de type Secret file
Récupère /tmp/kubeconfig-jenkins-cd.yaml, puis dans Jenkins → Credentials → Add Credentials :
| Champ | Valeur |
|---|---|
| Kind | Secret file |
| ID | kubeconfig-soria |
| File | le fichier kubeconfig généré |
Comprends pourquoi Secret file, pas texte
Un kubeconfig est un fichier ; le type Secret file le stocke tel quel et le remet au pipeline comme chemin temporaire (via KUBECONFIG). Il n’apparaît jamais en clair dans les logs et n’est présent que le temps du stage.
05Le stage Deploy
helm upgrade, piloté par Jenkins
Ajoute ce stage après Push dans le Jenkinsfile (on suppose un chart soria-web dans le dépôt) :
stage('Deploy (Helm)') {
steps {
withCredentials([file(credentialsId: 'kubeconfig-soria', variable: 'KUBECONFIG_FILE')]) {
sh '''
set -eu
export KUBECONFIG="$KUBECONFIG_FILE"
helm upgrade --install soria-web ./soria-web \\
-n lab-soria \\
--set image.repository="$IMAGE_REPO" \\
--set image.tag="$IMAGE_TAG"
helm -n lab-soria history soria-web | tail -n 5
'''
}
}
}Commit, push, relance le job, et lis le Console Output du stage Deploy :
ObserveRelease "soria-web" has been upgraded. Happy Helming!
REVISION STATUS DESCRIPTION
2 deployed Upgrade completeComprends upgrade –install, et le passage de tag
helm upgrade –install : installe si la release n’existe pas, met à jour sinon (idempotent — parfait pour un pipeline rejoué). Le pipeline passe le même tag calculé au stage Compute Tag ($IMAGE_TAG) : l’image construite est exactement celle déployée. Traçabilité de bout en bout : commit → image → release.
✓Ce que tu retiens
Le CD relie l’artefact au cluster. Jenkins déploie via Helm local, avec une identité limitée (ServiceAccount + Role + RoleBinding, bornée au namespace) et un kubeconfig dédié stocké en Secret file. Le stage Deploy fait helm upgrade –install avec le tag calculé : commit → image → release, sans jamais de droits admin dans Jenkins.
De l’image à la release, automatiquement
À faire
- Installe Helm sur la VM Jenkins.
- Crée l’identité
jenkins-cd(SA + Role + RoleBinding) bornée àlab-soria. - Génère le kubeconfig dédié, vérifie le champ
server:, injecte-le en Secret file. - Ajoute le stage Deploy, push, relance, prouve la révision Helm qui s’incrémente.
- Vérifie
kubectl -n lab-soria get pods: nouvelle image en service. - Documente dans BookStack le modèle RBAC (SA/Role/Binding) et le contenu d’un kubeconfig.
?Auto-évaluation
1. Pourquoi ne pas donner un kubeconfig admin à Jenkins ?
Moindre privilège : Jenkins ne doit pouvoir déployer que dans son namespace. Un accès admin ferait de Jenkins un point de compromission du cluster entier.
2. À quoi servent le Role et le RoleBinding ?
Le Role définit les actions autorisées sur des ressources dans un namespace ; le RoleBinding relie ce rôle au ServiceAccount de Jenkins.
3. Pourquoi helm upgrade –install et pas juste upgrade ?
Il est idempotent : installe si absent, met à jour sinon. Idéal pour un pipeline rejoué plusieurs fois sans erreur.