Les connaissances théoriques ne suffisent pas : DevSecOps se valide en faisant. Ces trois projets progressifs sont conçus pour ancrer les compétences de chaque niveau du parcours dans un projet concret, avec des livrables précis et des critères de validation clairs.
Chaque projet est indépendant mais ils se chainement : les artefacts du projet 1 sont réutilisés dans le projet 2, et le projet 2 est déployé dans le projet 3. À la fin des trois, vous avez une application complète, sécurisée, déployée sur Kubernetes, avec GitOps, policy as code, et métriques de sécurité.
Comment utiliser ces projets
Section intitulée « Comment utiliser ces projets »Commencez ici si vous débutez ou si vous découvrez DevSecOps. Vous n’avez besoin que d’un poste Linux avec Docker installé. Le projet 1 prend 1 à 2 jours.
Passez au projet 2 une fois que vous avez un pipeline CI/CD fonctionnel et que vous maîtrisez les concepts SBOM et supply chain. Le projet 2 prend 3 à 5 jours.
Le projet 3 suppose une bonne maîtrise de Kubernetes (RBAC, Network Policies, Helm) et de GitOps. Comptez 1 à 2 semaines selon votre niveau.
Projet 1 — Socle local sécurisé
Section intitulée « Projet 1 — Socle local sécurisé »Niveau : Socle (débutant) Durée estimée : 1-2 jours Prérequis : Linux, Git, Docker installés
Objectif
Section intitulée « Objectif »Mettre en place un environnement de développement local reproductible, avec des garde-fous de sécurité activés dès la première ligne de code. À la fin de ce projet, votre dépôt est prêt à être branché à un pipeline CI/CD.
Ce que vous construisez
Section intitulée « Ce que vous construisez »Un dépôt Git contenant une application web simple (par exemple une API Node.js ou Python Flask) avec :
- Un
Dockerfilesuivant les bonnes pratiques (image non-root, multi-stage, couche minimale) - Un
docker-compose.ymlpour lancer l’environnement local - Des hooks Git
pre-commitqui bloquent les secrets et vérifient la syntaxe - Un
README.mddocumentant comment lancer, tester et contribuer
1. Créer la structure du dépôt
Section intitulée « 1. Créer la structure du dépôt »Initialisez un dépôt Git propre et structuré :
mkdir devsecops-projet && cd devsecops-projetgit initmkdir -p src tests docs
# Créer un fichier .gitignore strictcat > .gitignore << 'EOF'.env*.key*.pemsecrets/node_modules/__pycache__/.DS_StoreEOFVérification : git status ne doit montrer aucun fichier sensible.
2. Écrire un Dockerfile sécurisé
Section intitulée « 2. Écrire un Dockerfile sécurisé »Un Dockerfile sécurisé respecte trois principes : image de base minimale, build multi-stage, utilisateur non-root.
# Stage 1 : buildFROM node:20-alpine AS builderWORKDIR /appCOPY package*.json ./RUN npm ci --only=production
# Stage 2 : runtime minimalFROM node:20-alpine# Créer un utilisateur dédié non-rootRUN addgroup -S appgroup && adduser -S appuser -G appgroupWORKDIR /appCOPY --from=builder /app/node_modules ./node_modulesCOPY src/ ./src/USER appuserEXPOSE 3000CMD ["node", "src/index.js"]Vérification : docker build -t monapp:dev . doit réussir sans erreur.
3. Configurer les hooks pre-commit
Section intitulée « 3. Configurer les hooks pre-commit »Les hooks pre-commit exécutent des vérifications automatiquement avant chaque commit. Cela empêche d’envoyer accidentellement des secrets dans le dépôt.
# Installer pre-commit (macOS/Linux)pip install pre-commit
# Créer la configurationcat > .pre-commit-config.yaml << 'EOF'repos: # Détection de secrets - repo: https://github.com/Yelp/detect-secrets rev: v1.4.0 hooks: - id: detect-secrets
# Vérification shellcheck pour les scripts bash - repo: https://github.com/shellcheck-py/shellcheck-py rev: v0.9.0.6 hooks: - id: shellcheck
# Vérification des fichiers YAML - repo: https://github.com/adrienverge/yamllint rev: v1.33.0 hooks: - id: yamllint args: [-d, relaxed]
# Vérification basique des fichiers - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.5.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer - id: check-merge-conflictEOF
# Activer les hookspre-commit installVérification : créez un fichier test avec un faux secret (password=test123), faites git add, puis git commit. Le hook doit refuser le commit.
4. Écrire le README
Section intitulée « 4. Écrire le README »Un bon README répond aux questions : comment lancer en local ? Comment contribuer ? Comment tester ?
## Lancer en local
docker compose up -d
## Tester
curl http://localhost:3000/health
## Contribuer
Les hooks pre-commit s'installent avec : pre-commit installAucun secret ne doit figurer dans le code. Utilisez .env.example.Livrable validé : un dépôt Git propre, un Dockerfile non-root multi-stage, des hooks pre-commit actifs, et un README.
Projet 2 — Pipeline CI/CD avec supply chain sécurisée
Section intitulée « Projet 2 — Pipeline CI/CD avec supply chain sécurisée »Niveau : Opérationnel (intermédiaire) Durée estimée : 3-5 jours Prérequis : Projet 1 terminé, compte GitHub ou GitLab, notions CI/CD
Objectif
Section intitulée « Objectif »Transformer votre dépôt du projet 1 en un vrai pipeline CI/CD sécurisé : scan de secrets, analyse statique (SAST), analyse de dépendances (SCA), génération de SBOM, signature d’image avec attestation. À la fin, chaque image publiée est vérifiable et traçable.
Ce que vous construisez
Section intitulée « Ce que vous construisez »Un pipeline CI/CD qui enchaîne automatiquement :
- Détection de secrets dans le code
- Analyse statique (SAST) avec rapport
- Analyse des dépendances (SCA) avec seuil de blocage
- Génération d’un SBOM au format CycloneDX
- Build et scan de l’image Docker
- Signature cryptographique de l’image
- Publication dans un registre avec attestation
1. Structurer les stages du pipeline
Section intitulée « 1. Structurer les stages du pipeline »Chaque outil de sécurité correspond à un stage. Voici la structure cible :
secrets-scan → sast → sca → build → sbom → image-scan → sign → pushname: DevSecOps Pipeline
on: [push, pull_request]
jobs: secrets-scan: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: { fetch-depth: 0 } - name: Scan secrets (Gitleaks) uses: gitleaks/gitleaks-action@v2 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
sast: runs-on: ubuntu-latest needs: secrets-scan steps: - uses: actions/checkout@v4 - name: SAST avec Semgrep uses: semgrep/semgrep-action@v1 with: config: auto
sca: runs-on: ubuntu-latest needs: sast steps: - uses: actions/checkout@v4 - name: SCA avec Trivy (dépendances) uses: aquasecurity/trivy-action@master with: scan-type: fs severity: CRITICAL,HIGH exit-code: 1stages: [secrets, sast, sca, build, publish]
secrets-scan: stage: secrets image: zricethezav/gitleaks:latest script: - gitleaks detect --source . --exit-code 1
sast: stage: sast image: returntocorp/semgrep script: - semgrep --config=auto --error
sca: stage: sca image: aquasec/trivy:latest script: - trivy fs --exit-code 1 --severity CRITICAL,HIGH .2. Générer et publier le SBOM
Section intitulée « 2. Générer et publier le SBOM »Le SBOM doit être généré après le build de l’image, pas avant. Attachez-le comme artefact du pipeline.
# Générer le SBOM avec Syftsyft $IMAGE_NAME:$TAG \ -o cyclonedx-json \ --file sbom-$CI_COMMIT_SHA.json
# Vérifier le contenu (doit lister vos dépendances)cat sbom-$CI_COMMIT_SHA.json | jq '.components | length'Vérification : le fichier SBOM doit contenir toutes les bibliothèques listées dans votre package.json ou requirements.txt.
3. Signer l’image avec Cosign
Section intitulée « 3. Signer l’image avec Cosign »La signature cryptographique prouve que l’image n’a pas été modifiée après le build. Cosign utilise l’identité OIDC du pipeline pour signer sans clé gérée manuellement (keyless signing).
# Installation de Cosign dans le pipelinecurl -O https://github.com/sigstore/cosign/releases/latest/download/cosign-linux-amd64chmod +x cosign-linux-amd64 && mv cosign-linux-amd64 /usr/local/bin/cosign
# Signature keyless (avec OIDC GitHub/GitLab)cosign sign --yes $REGISTRY/$IMAGE:$TAG
# Attacher le SBOM comme attestationcosign attest --yes \ --predicate sbom.json \ --type cyclonedx \ $REGISTRY/$IMAGE:$TAGVérification : après push, vérifiez la signature :
cosign verify $REGISTRY/$IMAGE:$TAG \ --certificate-identity-regexp=".*" \ --certificate-oidc-issuer="https://token.actions.githubusercontent.com"4. Définir des quality gates
Section intitulée « 4. Définir des quality gates »Un quality gate bloque automatiquement le déploiement si les critères de sécurité ne sont pas atteints. Définissez votre seuil minimal :
# Bloquer si CVE critique sans fix disponible- trivy image --exit-code 1 --severity CRITICAL --ignore-unfixed $IMAGE:$TAG
# Bloquer si secrets détectés- gitleaks detect --exit-code 1
# Autoriser le déploiement uniquement si les 3 stages précédents ont réussideploy: needs: [secrets-scan, sast, image-scan]Livrable validé : une image Docker publiée, signée, avec SBOM attaché. Le pipeline bloque les CVE critiques et les secrets.
Ressources pour ce projet
Section intitulée « Ressources pour ce projet »- Tests de sécurité SAST/DAST/SCA
- Supply Chain Security
- Gestion des vulnérabilités CVE
- Pipeline sécurisé
Projet 3 — Déploiement Kubernetes sécurisé avec GitOps
Section intitulée « Projet 3 — Déploiement Kubernetes sécurisé avec GitOps »Niveau : Expert Durée estimée : 1-2 semaines Prérequis : Projet 2 terminé, Kubernetes (kind ou k3s), ArgoCD
Objectif
Section intitulée « Objectif »Déployer l’application du projet 2 sur un cluster Kubernetes avec une posture de sécurité complète : RBAC, Network Policies, Pod Security Standards, secrets dynamiques, GitOps via ArgoCD, et observabilité avec alertes SLO.
Ce que vous construisez
Section intitulée « Ce que vous construisez »Un environnement Kubernetes multi-environnements (dev et prod) avec :
- Déploiement GitOps via ArgoCD (le cluster se synchronise depuis Git)
- RBAC minimal (chaque composant a les droits minimaux)
- Network Policies (seuls les flux nécessaires sont autorisés)
- Pod Security Standards en mode
restricted - Secrets dynamiques injectés par un gestionnaire de secrets (pas de secrets en clair dans Git)
- SLO définis avec alertes Grafana/AlertManager
- Audit DSOMM pour mesurer votre maturité DevSecOps
1. Mettre en place le cluster local avec kind ou k3s
Section intitulée « 1. Mettre en place le cluster local avec kind ou k3s »# Option A : kind (plus léger)kind create cluster --name devsecops-lab \ --config - << 'EOF'kind: ClusterapiVersion: kind.x-k8s.io/v1alpha4nodes: - role: control-plane - role: worker - role: workerEOF
# Option B : k3s (plus proche de production)curl -sfL https://get.k3s.io | sh -
# Vérification : tous les nœuds doivent être Readykubectl get nodes2. Configurer RBAC minimal
Section intitulée « 2. Configurer RBAC minimal »Chaque namespace doit avoir son propre ServiceAccount avec des droits limités au minimum nécessaire.
apiVersion: v1kind: ServiceAccountmetadata: name: monapp-sa namespace: production---apiVersion: rbac.authorization.k8s.io/v1kind: Rolemetadata: name: monapp-role namespace: productionrules: # Autoriser uniquement la lecture des ConfigMaps de l'application - apiGroups: [""] resources: ["configmaps"] resourceNames: ["monapp-config"] verbs: ["get"]---apiVersion: rbac.authorization.k8s.io/v1kind: RoleBindingmetadata: name: monapp-rolebinding namespace: productionsubjects: - kind: ServiceAccount name: monapp-saroleRef: kind: Role name: monapp-role apiGroup: rbac.authorization.k8s.ioVérification : testez que le ServiceAccount ne peut pas créer de pods :
kubectl auth can-i create pods \ --as=system:serviceaccount:production:monapp-sa \ -n production# Doit retourner : no3. Appliquer les Network Policies
Section intitulée « 3. Appliquer les Network Policies »Par défaut, tous les pods Kubernetes peuvent communiquer entre eux. Les Network Policies définissent les flux autorisés.
# Bloquer tout le trafic entrant par défaut dans le namespaceapiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: default-deny-ingress namespace: productionspec: podSelector: {} policyTypes: [Ingress]---# Autoriser uniquement le trafic depuis l'ingress controller vers l'appapiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: allow-ingress-to-app namespace: productionspec: podSelector: matchLabels: app: monapp policyTypes: [Ingress] ingress: - from: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: ingress-nginx ports: - protocol: TCP port: 30004. Installer ArgoCD et configurer le déploiement GitOps
Section intitulée « 4. Installer ArgoCD et configurer le déploiement GitOps »# Installer ArgoCDkubectl create namespace argocdkubectl apply -n argocd \ -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
# Attendre que ArgoCD soit prêtkubectl wait --for=condition=available deployment/argocd-server \ -n argocd --timeout=300s
# Récupérer le mot de passe initialkubectl get secret argocd-initial-admin-secret \ -n argocd -o jsonpath="{.data.password}" | base64 -dCréez une Application ArgoCD qui pointe vers votre dépôt Git :
apiVersion: argoproj.io/v1alpha1kind: Applicationmetadata: name: monapp namespace: argocdspec: project: default source: repoURL: https://github.com/votre-org/devsecops-projet targetRevision: main path: k8s/ destination: server: https://kubernetes.default.svc namespace: production syncPolicy: automated: prune: true selfHeal: trueVérification : modifiez une variable dans votre dépôt Git, commitez. ArgoCD doit synchroniser automatiquement le changement sur le cluster.
5. Définir les SLO et configurer les alertes
Section intitulée « 5. Définir les SLO et configurer les alertes »Un SLO (Service Level Objective) définit l’objectif de disponibilité de votre application. Sans mesure, pas d’amélioration.
# Exemple PrometheusRule pour un SLO de disponibilité 99.5%apiVersion: monitoring.coreos.com/v1kind: PrometheusRulemetadata: name: monapp-slo namespace: productionspec: groups: - name: monapp-availability rules: # Taux d'erreur sur 5 minutes - record: job:http_inbound_requests:rate5m expr: rate(http_requests_total{job="monapp"}[5m]) # Alerte si disponibilité < 99.5% - alert: MonAppAvailabilityBelowSLO expr: | sum(rate(http_requests_total{job="monapp",status=~"5.."}[5m])) / sum(rate(http_requests_total{job="monapp"}[5m])) > 0.005 for: 5m labels: severity: critical annotations: summary: "Disponibilité en dessous du SLO (99.5%)"6. Mesurer votre maturité avec DSOMM
Section intitulée « 6. Mesurer votre maturité avec DSOMM »Le DSOMM (DevSecOps Maturity Model) est un référentiel qui évalue votre maturité sur 5 dimensions : test des applications, durcissement des builds, culture, déploiement, et monitoring.
Faites un audit rapide à la fin du projet :
- Avez-vous des scans SAST dans votre pipeline ? → Dimension “Test des applications”
- Avez-vous des images signées et des SBOM ? → Dimension “Durcissement des builds”
- Avez-vous des Security Champions dans votre équipe ? → Dimension “Culture”
- Avez-vous des SLO avec alertes ? → Dimension “Monitoring”
Consultez l’audit de maturité DSOMM pour un guide complet.
Livrable validé : une application déployée sur Kubernetes via GitOps, avec RBAC minimal, Network Policies, secrets dynamiques, SLO actifs, et un score DSOMM documenté.
À retenir
Section intitulée « À retenir »- Les trois projets forment une progression cohérente : environnement local → pipeline sécurisé → déploiement Kubernetes.
- Le projet 1 installe les réflexes : hooks pre-commit, Dockerfile non-root, pas de secrets dans Git.
- Le projet 2 est le cœur opérationnel : SBOM, SCA, signature d’image, quality gates. C’est là que se concrétise la supply chain security.
- Le projet 3 ajoute la profondeur architecturale : RBAC, Network Policies, GitOps, SLO, audit de maturité.
- Chaque projet produit des livrables concrets vérifiables, pas juste du code qui “tourne”.
- La montée en maturité est progressive : ne passez pas au projet 3 sans avoir validé le projet 2.