Aller au contenu
Culture DevOps high
🔐 Alerte sécurité — Incident supply chain Trivy : lire mon analyse de l'attaque

Fil rouge DevSecOps : 3 projets progressifs

18 min de lecture

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é.

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.


Niveau : Socle (débutant) Durée estimée : 1-2 jours Prérequis : Linux, Git, Docker installés

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.

Un dépôt Git contenant une application web simple (par exemple une API Node.js ou Python Flask) avec :

  • Un Dockerfile suivant les bonnes pratiques (image non-root, multi-stage, couche minimale)
  • Un docker-compose.yml pour lancer l’environnement local
  • Des hooks Git pre-commit qui bloquent les secrets et vérifient la syntaxe
  • Un README.md documentant comment lancer, tester et contribuer

Initialisez un dépôt Git propre et structuré :

Fenêtre de terminal
mkdir devsecops-projet && cd devsecops-projet
git init
mkdir -p src tests docs
# Créer un fichier .gitignore strict
cat > .gitignore << 'EOF'
.env
*.key
*.pem
secrets/
node_modules/
__pycache__/
.DS_Store
EOF

Vérification : git status ne doit montrer aucun fichier sensible.

Un Dockerfile sécurisé respecte trois principes : image de base minimale, build multi-stage, utilisateur non-root.

# Stage 1 : build
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
# Stage 2 : runtime minimal
FROM node:20-alpine
# Créer un utilisateur dédié non-root
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY src/ ./src/
USER appuser
EXPOSE 3000
CMD ["node", "src/index.js"]

Vérification : docker build -t monapp:dev . doit réussir sans erreur.

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.

Fenêtre de terminal
# Installer pre-commit (macOS/Linux)
pip install pre-commit
# Créer la configuration
cat > .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-conflict
EOF
# Activer les hooks
pre-commit install

Vérification : créez un fichier test avec un faux secret (password=test123), faites git add, puis git commit. Le hook doit refuser le commit.

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 install
Aucun 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

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.

Un pipeline CI/CD qui enchaîne automatiquement :

  1. Détection de secrets dans le code
  2. Analyse statique (SAST) avec rapport
  3. Analyse des dépendances (SCA) avec seuil de blocage
  4. Génération d’un SBOM au format CycloneDX
  5. Build et scan de l’image Docker
  6. Signature cryptographique de l’image
  7. Publication dans un registre avec attestation

Chaque outil de sécurité correspond à un stage. Voici la structure cible :

secrets-scan → sast → sca → build → sbom → image-scan → sign → push
.github/workflows/devsecops.yml
name: 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: 1

Le SBOM doit être généré après le build de l’image, pas avant. Attachez-le comme artefact du pipeline.

Fenêtre de terminal
# Générer le SBOM avec Syft
syft $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.

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).

Fenêtre de terminal
# Installation de Cosign dans le pipeline
curl -O https://github.com/sigstore/cosign/releases/latest/download/cosign-linux-amd64
chmod +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 attestation
cosign attest --yes \
--predicate sbom.json \
--type cyclonedx \
$REGISTRY/$IMAGE:$TAG

Vérification : après push, vérifiez la signature :

Fenêtre de terminal
cosign verify $REGISTRY/$IMAGE:$TAG \
--certificate-identity-regexp=".*" \
--certificate-oidc-issuer="https://token.actions.githubusercontent.com"

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éussi
deploy:
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.


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

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.

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 »
Fenêtre de terminal
# Option A : kind (plus léger)
kind create cluster --name devsecops-lab \
--config - << 'EOF'
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
- role: worker
EOF
# Option B : k3s (plus proche de production)
curl -sfL https://get.k3s.io | sh -
# Vérification : tous les nœuds doivent être Ready
kubectl get nodes

Chaque namespace doit avoir son propre ServiceAccount avec des droits limités au minimum nécessaire.

rbac-app.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: monapp-sa
namespace: production
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: monapp-role
namespace: production
rules:
# Autoriser uniquement la lecture des ConfigMaps de l'application
- apiGroups: [""]
resources: ["configmaps"]
resourceNames: ["monapp-config"]
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: monapp-rolebinding
namespace: production
subjects:
- kind: ServiceAccount
name: monapp-sa
roleRef:
kind: Role
name: monapp-role
apiGroup: rbac.authorization.k8s.io

Vérification : testez que le ServiceAccount ne peut pas créer de pods :

Fenêtre de terminal
kubectl auth can-i create pods \
--as=system:serviceaccount:production:monapp-sa \
-n production
# Doit retourner : no

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 namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: production
spec:
podSelector: {}
policyTypes: [Ingress]
---
# Autoriser uniquement le trafic depuis l'ingress controller vers l'app
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-ingress-to-app
namespace: production
spec:
podSelector:
matchLabels:
app: monapp
policyTypes: [Ingress]
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: ingress-nginx
ports:
- protocol: TCP
port: 3000

4. Installer ArgoCD et configurer le déploiement GitOps

Section intitulée « 4. Installer ArgoCD et configurer le déploiement GitOps »
Fenêtre de terminal
# Installer ArgoCD
kubectl create namespace argocd
kubectl apply -n argocd \
-f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
# Attendre que ArgoCD soit prêt
kubectl wait --for=condition=available deployment/argocd-server \
-n argocd --timeout=300s
# Récupérer le mot de passe initial
kubectl get secret argocd-initial-admin-secret \
-n argocd -o jsonpath="{.data.password}" | base64 -d

Créez une Application ArgoCD qui pointe vers votre dépôt Git :

argocd-app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: monapp
namespace: argocd
spec:
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: true

Vérification : modifiez une variable dans votre dépôt Git, commitez. ArgoCD doit synchroniser automatiquement le changement sur le cluster.

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/v1
kind: PrometheusRule
metadata:
name: monapp-slo
namespace: production
spec:
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%)"

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é.

  • 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.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn