Sécurité DevOps - Intermédiaire
🎯 Objectifs
- Automatiser le scanning de dépendances avec Dependabot
- Analyser le code statiquement avec CodeQL (SAST)
- Scanner les images Docker avec Trivy
- Gérer les secrets de CI/CD de manière sécurisée
- Sécuriser un workflow GitHub Actions
📋 Prérequis
- Sécurité DevOps - Débutant terminé
- Maîtriser les bases de GitHub Actions
- Connaître Docker (images, Dockerfile)
🤔 Pourquoi automatiser la sécurité ?
La sécurité vérifiée à la main, c'est une sécurité oubliée.
Une revue de code manuelle ne détecte pas une dépendance vulnérable publiée hier. Un développeur fatigué laisse passer une faille d'injection. L'outil, lui, ne se fatigue jamais.
💡 Le principe : intégrer des outils de sécurité dans le pipeline CI/CD pour qu'ils tournent à chaque commit, sans intervention humaine.
C'est ce qu'on appelle le Shift Left Security : détecter les problèmes le plus tôt possible, quand ils coûtent le moins cher à corriger.
🤖 Dependabot : mises à jour automatiques des dépendances
Qu'est-ce que Dependabot ?
Dependabot est un outil GitHub qui surveille tes dépendances et ouvre automatiquement des Pull Requests quand une mise à jour est disponible - notamment quand une faille de sécurité est corrigée.
L'analogie
C'est comme avoir un assistant qui lit tous les bulletins de sécurité à ta place, et qui pose sur ton bureau un formulaire pré-rempli chaque fois qu'une mise à jour urgente est disponible. Il ne la fait pas lui-même - il te la propose.
Configuration
Créer le fichier .github/dependabot.yml :
version: 2
updates:
# Dépendances Node.js
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly" # vérification chaque semaine
open-pull-requests-limit: 10 # maximum 10 PRs ouvertes simultanément
labels:
- "dependencies"
- "security"
# Actions GitHub (les actions elles-mêmes ont des versions)
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"💡 Dependabot s'occupe aussi des actions GitHub (
uses: actions/checkout@v3→@v4). C'est souvent oublié mais important.
Alertes de sécurité vs mises à jour
Dependabot propose deux fonctionnalités distinctes :
| Fonctionnalité | Rôle | Activation |
|---|---|---|
| Security alerts | Alerte quand une CVE concerne tes dépendances | Automatique (dépôts publics) |
| Security updates | Ouvre une PR pour corriger la CVE | Security → Dependabot security updates |
| Version updates | Ouvre une PR pour les nouvelles versions | Via dependabot.yml |
🔍 SAST : analyser ton code statiquement
Qu'est-ce que le SAST ?
SAST = Static Application Security Testing. L'outil lit ton code source (sans l'exécuter) et cherche des patterns dangereux.
Exemples de ce qu'il détecte :
- Une requête SQL construite par concaténation (injection SQL)
- Un mot de passe codé en dur dans le code
- L'utilisation de fonctions cryptographiques obsolètes
GitHub Code Scanning avec CodeQL
GitHub propose CodeQL gratuitement pour les dépôts publics et via GitHub Advanced Security pour les dépôts privés.
# .github/workflows/codeql.yml
name: "CodeQL"
on:
push:
branches: [main]
pull_request:
branches: [main]
schedule:
# Scan complet chaque lundi matin
- cron: '30 1 * * 1'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write # nécessaire pour publier les résultats
strategy:
matrix:
language: ['javascript', 'typescript']
# Autres langages supportés : python, java, go, csharp, cpp, ruby
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
- name: Autobuild
uses: github/codeql-action/autobuild@v3
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3Les résultats apparaissent dans : Repository → Security → Code scanning alerts
🐳 Scanner les images Docker avec Trivy
Pourquoi scanner une image ?
Une image Docker contient un OS minimal + des paquets + tes dépendances applicatives. Chacun de ces composants peut avoir des vulnérabilités connues.
L'analogie
Construire une image Docker sans la scanner, c'est comme cuisiner avec des ingrédients sans vérifier leurs dates de péremption. Le plat a l'air bon, mais il peut rendre malade.
Utiliser Trivy en local
# Installer Trivy
brew install trivy # macOS
# ou
sudo apt install trivy # Debian/Ubuntu
# Scanner une image
trivy image node:20-alpine
# Scanner ton image buildée localement
trivy image mon-app:latest
# Scanner uniquement les vulnérabilités HIGH et CRITICAL
trivy image --severity HIGH,CRITICAL mon-app:latest
# Scanner le filesystem (dépendances applicatives)
trivy fs --scanners vuln .Exemple de sortie :
mon-app:latest (alpine 3.18.4)
===============================
Total: 3 (HIGH: 1, CRITICAL: 2)
┌────────────────┬────────────────┬──────────┬──────────────┬────────────────┐
│ Library │ Vulnerability │ Severity │ Installed │ Fixed Version │
├────────────────┼────────────────┼──────────┼──────────────┼────────────────┤
│ openssl │ CVE-2023-5678 │ CRITICAL │ 3.1.1-r1 │ 3.1.4-r0 │
└────────────────┴────────────────┴──────────┴──────────────┴────────────────┘Intégrer Trivy dans GitHub Actions
# .github/workflows/security.yml
name: Security Scan
on:
push:
branches: [main]
pull_request:
jobs:
trivy:
runs-on: ubuntu-latest
permissions:
security-events: write
steps:
- uses: actions/checkout@v4
- name: Build Docker image
run: docker build -t mon-app:${{ github.sha }} .
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@0.24.0
with:
image-ref: 'mon-app:${{ github.sha }}'
format: 'sarif' # format compatible GitHub Security
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'
exit-code: '1' # fait échouer le pipeline si CVE trouvée
- name: Upload Trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v3
if: always() # même si l'étape précédente a échoué
with:
sarif_file: 'trivy-results.sarif'💡
exit-code: '1'est essentiel : il fait échouer le pipeline si une vulnérabilité critique est trouvée. Sans ça, le scan tourne mais ne bloque rien.
🔑 Gérer les secrets dans GitHub Actions
Les GitHub Secrets
Les secrets GitHub sont des valeurs chiffrées, stockées par GitHub, et injectées comme variables d'environnement dans tes workflows.
Ajouter un secret :
Repository → Settings → Secrets and variables → Actions → New repository secret
Utiliser un secret dans un workflow :
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy
env:
# ${{ secrets.NOM_DU_SECRET }} est remplacé par la valeur réelle
# La valeur n'apparaît jamais dans les logs
DATABASE_URL: ${{ secrets.DATABASE_URL }}
API_KEY: ${{ secrets.API_KEY }}
run: ./scripts/deploy.sh⚠️ GitHub masque automatiquement les secrets dans les logs (
***). Mais ne les affiche jamais volontairement avececho.
Environments : secrets par environnement
Pour des secrets différents selon l'environnement (staging vs production) :
jobs:
deploy-prod:
runs-on: ubuntu-latest
environment: production # utilise les secrets de l'environnement "production"
steps:
- name: Deploy to production
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }} # la valeur de prod, pas de staging
run: ./scripts/deploy.sh🛡️ Sécuriser ses workflows GitHub Actions
Le risque : l'injection de commandes
Un workflow qui utilise ${{ github.event.pull_request.title }} peut être exploité si le titre d'une PR contient du code malveillant.
# ❌ Dangereux : un attaquant peut injecter des commandes dans le titre de la PR
- name: Greet contributor
run: echo "Merci pour ${{ github.event.pull_request.title }}"
# ✅ Sécurisé : passer par une variable d'environnement
- name: Greet contributor
env:
PR_TITLE: ${{ github.event.pull_request.title }}
run: echo "Merci pour $PR_TITLE"Pincer les versions des actions
# ❌ Dangereux : si le mainteneur pousse du code malveillant sur @main, tu l'exécutes
- uses: some-action/checkout@main
# ✅ Bien : version sémantique (le mainteneur peut modifier un tag existant)
- uses: actions/checkout@v4
# ✅✅ Optimal : SHA de commit (immuable - impossible à modifier)
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11Principe du moindre privilège
# ❌ Trop de permissions
permissions: write-all
# ✅ Permissions minimales et explicites
permissions:
contents: read # lire le code
packages: write # publier une image Docker
# tout le reste est refusé par défautExemple : workflow sécurisé complet
name: CI Sécurisé
on:
pull_request:
branches: [main]
# Permissions minimales par défaut pour tout le workflow
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest
steps:
# SHA pinné
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci # préféré à npm install en CI : reproductible et sécurisé
- name: Run tests
run: npm test
- name: Audit dependencies
run: npm audit --audit-level=high # échoue si vulnérabilité HIGH ou CRITICAL📊 Récapitulatif des outils
| Outil | Type | Ce qu'il détecte | Gratuit |
|---|---|---|---|
| Dependabot | SCA | Dépendances vulnérables, mises à jour | ✅ |
| CodeQL | SAST | Failles dans le code source | ✅ (dépôts publics) |
| Trivy | Scanner | Vulnérabilités dans les images Docker | ✅ |
| npm audit | SCA | Dépendances Node.js vulnérables | ✅ |
| gitleaks | Détection | Secrets commités dans Git | ✅ |
✅ Checklist Sécurité Intermédiaire
dependabot.ymlconfiguré (npm + github-actions)- Dependabot security updates activé
- Workflow CodeQL en place sur
mainet PRs - Trivy intégré dans le pipeline CI (avec
exit-code: 1) - Secrets stockés dans GitHub Secrets (pas dans le code)
- Environments configurés pour prod vs staging
- Actions pinnées par version ou SHA
permissions:explicites dans chaque workflow- Variables d'environnement pour les inputs GitHub (pas d'injection directe)
🚀 Prochaines Étapes
Tu sécurises maintenant ton code et ton pipeline automatiquement. L'étape suivante : la sécurité de l'infrastructure et de la supply chain.
- 👉 Sécurité DevOps - Avancé - Vault, supply chain, Kubernetes, compliance as code
- 👉 Kubernetes - Débutant - Déployer ses premiers pods