⚙️DevOps – Terraform, State, GitLab CI/CD & Gestion d'incidents (Part 2)
Guide pratique IDEO‑Lab pour nouveaux DevOps : infrastructure as code, modules, state, pipelines, déploiement contrôlé et production.
Runbooks DevOps
Procédures claires pour rollback, restart, saturation, DB, réseau et pipeline bloqué.
RunbookOpsSRERoadMap DevOps
Procédures claires sur la RoadMap devOps.
RunbookOpsSRECheat‑sheet
Commandes Terraform, GitLab, debug pipeline et vérifications production.
CommandsDebugAuditDesign Terraform avancé
Naming, locals, validations, count/for_each, lifecycle et dépendances.
DesignlocalslifecycleImport & drift
Rattacher l'existant, detecter la dérive et reprendre le contrôle IaC.
importdriftauditTests Terraform
Validation locale, plan de test, sandbox, Terratest et tests de modules.
testsandboxterratestCoûts & FinOps
Comprendre l'impact coût des changements infra avant apply.
costFinOpstagsMerge Request infra
Comment documenter une MR Terraform lisible et validable.
MRreviewapprovalTemplates GitLab CI
Factoriser les jobs CI/CD pour eviter la duplication.
includeextendstemplatesApprovals & protections
Branches protegees, environnements proteges, approvals et separation des droits.
protectedapprovalprodUn runbook transforme la panique en procédure
Un runbook est une procédure opérationnelle claire qui explique quoi vérifier, quelles commandes lancer, dans quel ordre, avec quels risques et comment valider le retour à un état normal.
En production, le runbook évite l’improvisation. Il permet à un DevOps, un SRE, un développeur d’astreinte ou un support technique de suivre une méthode reproductible, même sous pression.
Ce qu’un bon runbook doit contenir
| Section | Contenu attendu |
|---|---|
| Symptômes | Comment reconnaître le problème : alerte, log, métrique, comportement. |
| Impact | Quels utilisateurs, services ou données peuvent être touchés. |
| Vérifications | Commandes et dashboards à consulter avant action. |
| Actions | Procédure étape par étape, idéalement réversible. |
| Validation | Comment confirmer que le service est revenu à la normale. |
| Escalade | Qui appeler si la procédure ne fonctionne pas. |
| Rollback | Comment revenir en arrière ou mitiger. |
Runbooks prioritaires pour une équipe DevOps
Runbooks essentiels
│
├── Rollback infrastructure
├── Rollback application
├── Restart service Linux
├── Saturation CPU / RAM / disque
├── Base de données lente ou saturée
├── DNS / certificat / load balancer
├── Pipeline Terraform bloqué
├── State lock Terraform
├── Secret exposé
├── Incident sécurité
└── Provider cloud dégradéRunbook vs documentation
| Document | But | Style |
|---|---|---|
| Documentation | Expliquer un système. | Descriptif, pédagogique. |
| Runbook | Agir pendant une situation précise. | Procédural, direct, vérifiable. |
| Playbook | Coordonner une réponse plus large. | Rôles, scénarios, communication. |
| Post-mortem | Analyser après incident. | Chronologie, RCA, actions préventives. |
Template professionnel de runbook
Structure standard
# Runbook : titre court
## Objectif
Décrire le problème que ce runbook permet de traiter.
## Symptômes
- Alerte :
- Logs :
- Métriques :
- Comportement utilisateur :
## Impact possible
- Services touchés :
- Utilisateurs touchés :
- Données / sécurité :
- Niveau de gravité probable :
## Pré-requis
- Accès nécessaires :
- Outils :
- Variables :
- Dashboards :
## Étapes de diagnostic
1. ...
2. ...
3. ...
## Actions de mitigation
1. ...
2. ...
3. ...
## Validation du retour au nominal
- Healthcheck :
- Logs :
- Métriques :
- Test métier :
## Rollback
- Action de retour arrière :
- Risque :
- Vérification :
## Escalade
- Qui contacter :
- Quand escalader :
## Notes post-incident
- Ticket :
- Post-mortem :
- Actions préventives :Qualité attendue
| Critère | Bon runbook | Mauvais runbook |
|---|---|---|
| Clarté | Étapes numérotées, commandes exactes. | Texte vague ou théorique. |
| Sécurité | Précise les actions dangereuses. | Commandes destructives sans avertissement. |
| Validation | Explique comment mesurer le succès. | Dit seulement “vérifier”. |
| Escalade | Indique quand appeler un expert. | Laisse l’opérateur bloqué. |
| Mise à jour | Versionné et revu après incident. | Obsolète depuis plusieurs mois. |
Diagramme d’utilisation
Alerte déclenchée
│
▼
Identifier runbook correspondant
│
▼
Lire prérequis et risques
│
▼
Exécuter diagnostic
│
▼
Choisir mitigation
│
▼
Valider retour nominal
│
▼
Documenter résultat
│
▼
Mettre à jour runbook si manque détectéRunbook : rollback infrastructure Terraform
À utiliser lorsqu’un changement Terraform a provoqué ou semble avoir provoqué une dégradation : réseau bloqué, IAM cassé, load balancer mal configuré, DNS incorrect, security group trop restrictif.
Procédure
1. Déclarer l'incident si impact production.
2. Identifier le dernier apply Terraform.
3. Identifier le commit, la MR et le plan appliqué.
4. Lire les logs du job apply.
5. Lancer un plan refresh-only si nécessaire.
6. Déterminer si rollback complet ou patch minimal.
7. Revenir au commit précédent ou créer un correctif ciblé.
8. Générer un nouveau plan.
9. Vérifier qu'il ne détruit pas de ressource critique.
10. Faire relire le plan.
11. Appliquer avec approval.
12. Vérifier logs, métriques, health checks.
13. Documenter l'incident et la cause.Commandes utiles
# Identifier l'état courant
terraform state list
terraform plan -refresh-only
# Revenir à un commit précédent
git revert <commit_id>
git push origin main
# Générer un plan de rollback
terraform plan -out=tfplan -var-file="prod.tfvars"
terraform show -no-color tfplan > rollback-plan.txt
# Appliquer après review
terraform apply tfplanValidation post-rollback
| Zone | Vérification |
|---|---|
| Cloud | Ressource revenue à l’état attendu. |
| Application | Healthcheck OK, endpoints critiques OK. |
| Logs | Plus d’erreurs nouvelles liées au changement. |
| Metrics | 5xx, latence, saturation revenus au nominal. |
| State | Pas de drift inattendu après rollback. |
Runbook : restart contrôlé d’un service Linux
Redémarrer un service peut résoudre un blocage, mais peut aussi masquer la cause, interrompre des traitements ou aggraver l’incident. Le restart doit être contrôlé.
Diagnostic avant restart
# État du service
systemctl status app.service --no-pager
# Logs récents
journalctl -u app.service -n 100 --no-pager
# Ressources système
uptime
free -h
df -h
# Processus
ps aux | grep app
topProcédure restart
1. Confirmer impact et nécessité du restart.
2. Vérifier s'il existe plusieurs instances.
3. Prévenir dans le canal incident si production.
4. Capturer logs avant restart.
5. Redémarrer une instance à la fois si possible.
6. Vérifier status systemd.
7. Vérifier healthcheck applicatif.
8. Surveiller logs et métriques.
9. Documenter l'action.Commandes restart
# Restart contrôlé
sudo systemctl restart app.service
# Vérifier état
sudo systemctl status app.service --no-pager
# Suivre logs
sudo journalctl -u app.service -f
# Vérifier healthcheck
curl -fsS http://127.0.0.1:8000/health/
curl -fsS https://example.com/health/Quand éviter un restart immédiat ?
| Situation | Pourquoi attendre |
|---|---|
| Suspicion fuite mémoire | Capturer métriques/process avant de perdre les indices. |
| Incident sécurité | Préserver preuves et logs. |
| Migration DB en cours | Risque d’interruption dangereuse. |
| Cluster sans redondance | Restart = downtime direct. |
Runbook : saturation serveur Linux
À utiliser en cas de CPU élevé, RAM saturée, disque plein, load average anormal, I/O wait important ou service instable sur un serveur Linux.
Commandes diagnostic rapides
# Charge système
uptime
top
ps aux --sort=-%cpu | head
ps aux --sort=-%mem | head
# Mémoire
free -h
dmesg | grep -i "killed process"
# Disque
df -h
df -i
du -sh /var/log/* | sort -h
du -sh /tmp/* | sort -h
# Erreurs système
journalctl -p err -n 100 --no-pager
# Services critiques
systemctl status nginx --no-pager
systemctl status app.service --no-pager/var/lib, bases de données ou volumes applicatifs.Diagnostic par symptôme
| Symptôme | Cause possible | Action |
|---|---|---|
| CPU haut | Boucle, trafic élevé, job lourd. | Identifier process, scale, limiter job. |
| RAM saturée | Fuite mémoire, cache, trop de workers. | Identifier process, réduire workers, restart ciblé. |
| Disque plein | Logs, backups, uploads, cache. | Nettoyage contrôlé, rotation, extension volume. |
| Inodes pleins | Trop de petits fichiers. | Identifier dossier, purge contrôlée. |
| I/O wait élevé | Disque saturé, DB, logs intensifs. | Analyser I/O, réduire écriture, augmenter capacité. |
Mitigation disque plein
1. Identifier le volume plein avec df -h.
2. Identifier gros dossiers avec du.
3. Vérifier logs applicatifs et Nginx.
4. Compresser ou purger uniquement fichiers sûrs.
5. Redémarrer service seulement si nécessaire.
6. Ajouter logrotate ou corriger rétention.
7. Ajouter alerte disque 75/85/95%.Runbook : base de données lente ou saturée
Les incidents DB sont critiques : une mauvaise action peut empirer la latence, tuer des sessions utiles ou provoquer une perte de données. Il faut diagnostiquer avant d’agir.
Symptômes fréquents
| Symptôme | Cause possible |
|---|---|
| Connexions saturées | Pool mal réglé, fuite connexion, pic trafic. |
| Slow queries | Index manquant, requête non optimisée, volume élevé. |
| Locks longs | Transaction bloquée, migration, batch. |
| CPU DB élevé | Requêtes lourdes, scan complet, tri massif. |
| Disk full | WAL/binlog, backups, tables temporaires. |
| Replication lag | Replica trop lent, charge écriture élevée. |
Commandes génériques Linux côté DB
# Ressources serveur
top
free -h
df -h
iostat -xz 1 5
# Logs
journalctl -u postgresql -n 100 --no-pager
journalctl -u mysql -n 100 --no-pager
journalctl -u mariadb -n 100 --no-pagerProcédure DB
1. Confirmer impact applicatif : 5xx, latence, timeouts.
2. Vérifier connexions DB et saturation.
3. Identifier requêtes lentes ou locks.
4. Vérifier dernier déploiement ou migration.
5. Éviter restart DB brutal sauf nécessité critique.
6. Mitiger : rollback app, réduire workers, tuer requête fautive si validé.
7. Vérifier retour métriques DB.
8. Documenter requête, index, migration ou config responsable.Mitigations possibles
| Cas | Mitigation |
|---|---|
| Requête lente nouvelle | Rollback release ou désactiver feature. |
| Connexions saturées | Réduire concurrency workers, ajuster pool. |
| Lock bloquant | Identifier transaction, kill seulement après validation. |
| Disk DB presque plein | Extension volume, purge contrôlée, escalade DBA. |
Runbook : réseau, DNS, load balancer et certificats
Les incidents réseau sont souvent visibles comme des timeouts, 502/503/504, erreurs TLS, DNS incorrect, target group unhealthy ou connectivité DB impossible.
Commandes diagnostic
# DNS
dig example.com
dig +short example.com
nslookup example.com
# HTTP / TLS
curl -v https://example.com/
curl -fsS https://example.com/health/
openssl s_client -connect example.com:443 -servername example.com
# Connectivité port
nc -vz db.internal 5432
nc -vz redis.internal 6379
# Routes locales
ip addr
ip route
ss -tulpnSymptômes fréquents
| Symptôme | Cause probable |
|---|---|
| 502 | Backend indisponible ou target unhealthy. |
| 503 | Aucun backend disponible. |
| 504 | Timeout upstream. |
| TLS error | Certificat expiré, mauvais SNI, chaîne incomplète. |
| DNS mauvais | Record incorrect, TTL, propagation. |
Procédure réseau
Incident réseau détecté
│
▼
Identifier couche
├── DNS
├── TLS
├── Load balancer
├── Security group / firewall
├── Route table
└── Backend service
│
▼
Tester depuis plusieurs points
├── local
├── serveur
├── réseau interne
└── externe
│
▼
Relier à un changement récent
├── Terraform apply
├── certificat renouvelé
├── DNS modifié
└── service déployé
│
▼
Mitigation cibléeMitigations typiques
| Cas | Mitigation |
|---|---|
| DNS incorrect | Restaurer record précédent, tenir compte TTL. |
| Certificat expiré | Renouveler, recharger proxy/load balancer. |
| Security group bloque DB | Restaurer règle source SG vers port DB. |
| Targets unhealthy | Vérifier healthcheck path, app, port, logs. |
| Timeout upstream | Vérifier app, DB, proxy timeout, saturation. |
Runbook : pipeline Terraform bloqué
À utiliser lorsqu’un pipeline infra échoue ou reste bloqué : runner indisponible, state lock, backend inaccessible, provider error, variables manquantes ou artefact de plan absent.
Procédure pipeline bloqué
1. Identifier le job exact en échec.
2. Lire les logs depuis le début.
3. Vérifier runner disponible et tags.
4. Vérifier image CI et version Terraform.
5. Vérifier variables accessibles à la branche.
6. Vérifier terraform init et backend.
7. Vérifier state lock.
8. Vérifier artifact tfplan si apply.
9. Corriger la cause minimale.
10. Relancer uniquement le job nécessaire.
11. Informer l'équipe si production concernée.Commandes utiles
# Runner
gitlab-runner verify
gitlab-runner list
# Terraform
terraform --version
terraform providers
terraform init
terraform validate
terraform plan -refresh-only
terraform state list
# Lock, seulement après analyse
terraform force-unlock LOCK_IDforce-unlock sans preuve que le job détenteur du lock est terminé ou mort.Diagnostic par symptôme
| Symptôme | Cause probable | Action |
|---|---|---|
| Job pending | Runner absent ou tags incompatibles. | Vérifier runners/tags/protection. |
| Variable vide | Variable protected non disponible. | Vérifier branche protégée et scope. |
| init échoue | Backend inaccessible. | Vérifier credentials, bucket, réseau. |
| State lock | Apply actif ou lock orphelin. | Identifier job détenteur. |
| Apply sans tfplan | Artifact manquant ou expiré. | Relancer plan puis apply. |
| Provider error | Version/provider/API/cloud. | Lire erreur, vérifier versions et quotas. |
Flux décisionnel
Pipeline échoué
│
▼
Est-ce un job prod ?
│
├── Oui : informer équipe + prudence renforcée
└── Non : diagnostic standard
│
▼
Erreur runner, variable, backend, lock ou provider ?
│
▼
Corriger cause minimale
│
▼
Relancer plan
│
▼
Relancer apply uniquement si plan OKRunbook : secret exposé ou incident sécurité CI
À utiliser si un secret apparaît dans Git, dans les logs CI, dans un artifact, dans un ticket, ou si un runner/pipeline semble compromis.
Procédure immédiate
1. Identifier le secret exposé.
2. Déterminer son périmètre : dev, staging, prod.
3. Révoquer ou désactiver le secret.
4. Créer un nouveau secret avec droits minimaux.
5. Mettre à jour GitLab/Vault/Secret Manager.
6. Relancer les pipelines nécessaires.
7. Vérifier que les services fonctionnent.
8. Auditer les logs d'utilisation.
9. Nettoyer logs/artifacts si possible.
10. Documenter incident et prévention.Priorité selon secret
| Secret | Priorité | Action |
|---|---|---|
| Cloud prod admin | Critique | Révocation immédiate + audit cloud. |
| DB prod password | Critique | Rotation + analyse accès DB. |
| Token GitLab write | Élevée | Révoquer, vérifier actions repo. |
| Registry push token | Élevée | Rotation, vérifier images poussées. |
| Token dev lecture | Moyenne | Rotation planifiée rapide. |
Prévention
- Secret detection activée sur merge requests.
- Variables masked/protected/scoped.
- OIDC ou credentials courts si possible.
- Pas de
echo $SECRETnienvdans les jobs. - Artifacts explicitement listés.
- Rotation documentée.
Qualité, maintenance et tests des runbooks
Un runbook obsolète est dangereux. Les runbooks doivent être versionnés, testés, relus après incident et intégrés à la culture d’astreinte.
Critères de qualité
| Critère | Validation |
|---|---|
| Actionnable | Un opérateur peut suivre les étapes sans deviner. |
| À jour | Commandes, services, chemins et dashboards valides. |
| Sécurisé | Actions dangereuses clairement signalées. |
| Mesurable | Chaque procédure indique comment vérifier le résultat. |
| Escalable | Indique quand escalader et à qui. |
| Testé | Exercices réguliers ou simulation en staging. |
Revue périodique
Tous les 3 mois :
[ ] Vérifier commandes.
[ ] Vérifier noms de services.
[ ] Vérifier liens dashboards.
[ ] Vérifier contacts d'escalade.
[ ] Vérifier accès nécessaires.
[ ] Tester en staging si possible.
[ ] Mettre à jour après incidents récents.Exercice GameDay
Simulation contrôlée
│
▼
Choisir scénario
├── disque presque plein
├── service down
├── pipeline lock
└── DB lente
│
▼
Suivre runbook
│
▼
Mesurer
├── temps diagnostic
├── clarté étapes
├── erreurs rencontrées
└── manque documentaire
│
▼
Améliorer runbookOù stocker les runbooks ?
| Support | Avantage |
|---|---|
| Git repo | Versioning, review, historique. |
| Wiki interne | Facile à lire et partager. |
| Incident tool | Accessible depuis alertes. |
| Dashboard links | Runbook directement lié à l’alerte. |
Checklist runbooks DevOps / SRE
Checklist création
| Point | Validation attendue |
|---|---|
| Symptômes clairs | Alertes, logs, métriques associés. |
| Impact décrit | Services, utilisateurs, données, gravité. |
| Commandes exactes | Copiables, contextualisées, non destructives par défaut. |
| Risques visibles | Actions dangereuses signalées. |
| Validation définie | Healthcheck, logs, métriques, test métier. |
| Rollback indiqué | Retour arrière ou mitigation documentée. |
| Escalade indiquée | Quand et vers qui escalader. |
| Owner défini | Une équipe responsable du runbook. |
Checklist runbooks prioritaires
| Runbook | Priorité |
|---|---|
| Service down / restart contrôlé | Critique |
| Rollback applicatif | Critique |
| Rollback Terraform | Critique |
| Disque plein | Critique |
| Base de données lente/saturée | Critique |
| Pipeline Terraform bloqué | Élevée |
| DNS / certificat / load balancer | Élevée |
| Secret exposé | Critique sécurité |
Mini-cheat-sheet
Runbook = symptômes + impact + diagnostic + action + validation + rollback + escalade
Toujours préciser :
[ ] Quand utiliser
[ ] Quand ne pas utiliser
[ ] Commandes exactes
[ ] Risques
[ ] Signaux de succès
[ ] Qui appeler
[ ] Quoi documenter après actionObjectif de cette RoadMap DevOps
Cette roadmap propose une progression claire pour devenir opérationnel côté DevOps infrastructure : Linux, réseau, cloud, Terraform, GitLab CI/CD, sécurité, observabilité, incidents, runbooks et pratiques SRE.
Le but n’est pas seulement d’apprendre des outils. Le but est de construire une capacité professionnelle : livrer de l’infrastructure de façon fiable, sécurisée, automatisée, observable et récupérable en cas d’incident.
Les grands blocs à maîtriser
| Domaine | Compétence attendue |
|---|---|
| Linux | Services systemd, logs, permissions, réseau, diagnostic CPU/RAM/disque. |
| Réseau | DNS, TLS, HTTP, ports, firewall, load balancer, security groups. |
| Cloud | Compute, VPC, IAM, stockage, base de données managée, monitoring cloud. |
| Terraform | Providers, modules, state, remote backend, plan/apply, drift, imports. |
| GitLab CI/CD | Stages, runners, variables, approvals, artifacts, environnements protégés. |
| Sécurité | Secrets, OIDC, IAM least privilege, scans IaC, branches protégées. |
| Observabilité | Logs, metrics, traces, dashboards, alerting, SLO. |
| Incidents | Triage, mitigation, rollback, communication, RCA, post-mortem. |
Chemin de progression
Fondations
│
├── Linux
├── Réseau
├── Git
└── Cloud basics
│
▼
Infrastructure as Code
├── Terraform basics
├── modules
├── remote state
└── sécurité
│
▼
Industrialisation
├── GitLab CI/CD
├── runners
├── variables protégées
├── approvals
└── apply contrôlé
│
▼
Production
├── observabilité
├── alerting
├── runbooks
├── rollback
└── incidents
│
▼
Maturité SRE
├── SLO
├── error budget
├── post-mortems
└── amélioration continuePrincipe pédagogique
| Phase | Question clé |
|---|---|
| Comprendre | Est-ce que je sais expliquer ce que fait l’outil ? |
| Construire | Est-ce que je sais créer un environnement reproductible ? |
| Sécuriser | Est-ce que je limite les accès, secrets et risques ? |
| Automatiser | Est-ce que la CI/CD exécute les contrôles correctement ? |
| Exploiter | Est-ce que je peux diagnostiquer et restaurer en production ? |
Niveaux de progression DevOps
Niveau 1 : Junior opérationnel
| Compétence | Attendu |
|---|---|
| Linux | Savoir lire logs, redémarrer un service, vérifier CPU/RAM/disque. |
| Terraform | Comprendre init, plan, apply, variables, outputs, state. |
| GitLab CI/CD | Lire un pipeline, comprendre stages et jobs. |
| Cloud | Comprendre VM, réseau, security groups, DNS, stockage. |
| Incident | Savoir suivre un runbook sans improviser. |
Niveau 2 : DevOps autonome
| Terraform modules | Créer modules propres et réutilisables. |
| Remote state | Mettre en place backend distant, locking et séparation env. |
| Pipeline infra | Construire fmt, validate, scan, plan, apply manuel. |
| Sécurité CI | Variables protégées, scopes, IAM minimal, secrets hors Git. |
| Observabilité | Créer dashboards et alertes utiles. |
Niveau 3 : DevOps confirmé / SRE
| Compétence | Attendu |
|---|---|
| Architecture infra | Découper states, modules, comptes, environnements et domaines. |
| CI/CD avancée | Templates, approvals, policies, runners protégés, OIDC. |
| Production | Déploiements contrôlés, fenêtres, rollback, post-checks. |
| Incident response | Commander un incident, mitiger, communiquer, RCA. |
| SRE | SLO, error budget, runbooks testés, amélioration continue. |
Niveau 4 : Platform Engineer
| Self-service | Créer modules et pipelines consommables par les équipes dev. |
| Guardrails | Policy-as-code, standards sécurité, golden paths. |
| FinOps | Maîtriser coûts, tags, budgets, optimisation cloud. |
| Reliability engineering | Mesurer, piloter et améliorer la fiabilité système. |
RoadMap 12 semaines : progression réaliste
| Semaine | Objectif | Exercice pratique | Livrable attendu |
|---|---|---|---|
| 1 | Linux, Git, réseau de base. | Installer une VM, Nginx, service systemd, logs. | Serveur accessible + runbook diagnostic Linux. |
| 2 | Cloud basics. | Créer VM, security group, DNS, volume, firewall. | Mini architecture cloud documentée. |
| 3 | Terraform bases. | Créer ressources simples via Terraform. | Code Terraform init/plan/apply propre. |
| 4 | Variables, outputs, structure fichiers. | Paramétrer dev/staging/prod avec tfvars. | Projet Terraform structuré. |
| 5 | Modules Terraform. | Créer module network + compute. | Modules documentés avec inputs/outputs. |
| 6 | Remote state + locking. | Configurer backend distant par environnement. | State distant, verrouillé, non commité. |
| 7 | GitLab CI/CD infra. | Créer pipeline fmt/validate/plan. | MR avec plan Terraform en artefact. |
| 8 | Apply contrôlé. | Ajouter apply manuel staging/prod. | Pipeline protégé avec approvals. |
| 9 | Sécurité CI. | Variables masked/protected/scoped, scan IaC. | Secrets hors Git + rapport sécurité. |
| 10 | Observabilité. | Logs centralisés, metrics, dashboard, alertes. | Dashboard production minimal. |
| 11 | Incidents et runbooks. | Simuler disque plein, rollback, pipeline lock. | 3 runbooks testés + timeline incident. |
| 12 | Projet final. | Déployer une mini app complète avec CI/CD et monitoring. | Plateforme demo production-ready. |
Résultat après 12 semaines
- Comprendre les fondamentaux Linux, cloud et réseau.
- Créer une infrastructure Terraform propre.
- Utiliser modules, remote state et locking.
- Créer pipeline GitLab CI/CD infra avec plan/apply contrôlé.
- Sécuriser variables, secrets et environnements.
- Créer dashboard, alertes et runbooks.
- Simuler incidents et produire un post-mortem.
Diagramme de progression
Semaines 1-2
Fondations Linux / Cloud
Semaines 3-6
Terraform solide
Semaines 7-9
Industrialisation CI/CD + sécurité
Semaines 10-11
Observabilité + incidents
Semaine 12
Projet complet production-readyParcours Terraform détaillé
Ordre d’apprentissage
| Étape | Compétence | Exercice |
|---|---|---|
| 1 | Providers et resources. | Créer une VM ou un bucket. |
| 2 | Variables et outputs. | Paramétrer région, nom, taille. |
| 3 | Plan/apply. | Lire les changements +, ~, -. |
| 4 | State. | Comprendre state list et state show. |
| 5 | Modules. | Créer module réseau et compute. |
| 6 | Remote backend. | State distant + lock. |
| 7 | Drift et import. | Importer une ressource existante. |
| 8 | Production safety. | Prévenir destroy, séparer env, review plan. |
Exercices Terraform progressifs
Exercice 1 :
Créer une ressource simple avec tags.
Exercice 2 :
Ajouter variables.tf, outputs.tf, locals.tf.
Exercice 3 :
Créer dev.tfvars et prod.tfvars.
Exercice 4 :
Créer un module network.
Exercice 5 :
Créer un module compute qui consomme network outputs.
Exercice 6 :
Configurer backend distant.
Exercice 7 :
Simuler drift et le corriger proprement.
Exercice 8 :
Ajouter prevent_destroy sur ressource critique.Compétence attendue
| Junior | Sait lire un plan et appliquer en dev. |
| Autonome | Sait structurer modules, state et env. |
| Confirmé | Sait gérer drift, import, rollback, sécurité et production. |
Parcours GitLab CI/CD Infrastructure
Compétences CI/CD à acquérir
| Bloc | À maîtriser |
|---|---|
| Syntaxe YAML | Stages, jobs, variables, rules, needs, artifacts. |
| Runners | Tags, runners protégés, runners dédiés infra. |
| Terraform pipeline | fmt, validate, security, plan, apply, post-check. |
| Environnements | dev, staging, prod, protected environments. |
| Approvals | Apply manuel, review plan, approval prod. |
| Secrets | Variables masked/protected/scoped, OIDC, IAM minimal. |
| Debug | Logs pipeline, artifacts, state lock, variables absentes. |
Pipeline cible
Merge Request
│
├── terraform fmt
├── terraform validate
├── scan sécurité
└── terraform plan
│
▼
Review du plan
│
▼
Merge main
│
▼
Plan production
│
▼
Approval
│
▼
Apply manuel
│
▼
Post-checksExercices CI/CD
Exercice 1 :
Créer pipeline avec stages lint/validate.
Exercice 2 :
Ajouter terraform plan avec artifact plan.txt.
Exercice 3 :
Ajouter checkov ou trivy config.
Exercice 4 :
Ajouter apply manuel en staging.
Exercice 5 :
Protéger variables et environnement production.
Exercice 6 :
Ajouter post_deploy_checks avec curl /health.
Exercice 7 :
Simuler state lock et écrire runbook.
Exercice 8 :
Factoriser jobs avec includes/templates.Maturité CI/CD
| Niveau | Pipeline |
|---|---|
| Basique | fmt + validate. |
| Correct | fmt + validate + plan en MR. |
| Pro | scan + plan artefact + apply manuel + approvals. |
| Avancé | OIDC + policy-as-code + templates + post-checks + audit. |
Parcours Cloud, Linux et réseau
Fondations Linux
| Sujet | À savoir faire |
|---|---|
| Services | systemctl status/start/stop/restart, logs systemd. |
| Logs | journalctl, logs Nginx, logs applicatifs. |
| Ressources | top, free, df, du, iostat. |
| Réseau | curl, dig, nc, ss, routes. |
| Sécurité | users, permissions, SSH, firewall, certificats. |
Commandes indispensables
systemctl status nginx
journalctl -u nginx -n 100 --no-pager
df -h
du -sh /var/log/* | sort -h
free -h
top
ss -tulpn
curl -v https://example.com/
dig example.com
nc -vz host 443Fondations Cloud
| Sujet | Compétence attendue |
|---|---|
| Compute | VM, autoscaling, containers, images. |
| Network | VPC, subnets, routes, NAT, load balancer. |
| Security | IAM, roles, policies, security groups, KMS. |
| Data | Managed DB, backups, snapshots, storage. |
| DNS / TLS | Records DNS, certificats, renouvellement, validation. |
| Monitoring | Cloud metrics, logs, alarms, audit events. |
Mini-architecture à construire
Internet
│
▼
DNS + TLS
│
▼
Load Balancer
│
▼
Application VM / Container
│
├── logs
├── metrics
└── healthcheck
│
▼
Database managed
│
├── backups
├── private access
└── monitoringParcours Observabilité
Progression observabilité
| Étape | Objectif | Livrable |
|---|---|---|
| 1 | Centraliser les logs. | Logs app/proxy consultables. |
| 2 | Ajouter métriques système. | CPU/RAM/disque/réseau visibles. |
| 3 | Ajouter métriques applicatives. | RPS, 5xx, p95/p99. |
| 4 | Créer dashboard global. | Vue production en 30 secondes. |
| 5 | Créer alertes critiques. | Service down, 5xx, disque, DB. |
| 6 | Ajouter runbooks aux alertes. | Alerte actionnable. |
| 7 | Corréler déploiements et incidents. | Annotations deploy/Terraform. |
Golden signals
Latency:
p50, p95, p99
Traffic:
requests/sec, jobs/min
Errors:
HTTP 5xx, exceptions, failed jobs
Saturation:
CPU, RAM, disk, DB connections, queue backlogDashboard cible
Production Overview
│
├── Availability
├── HTTP 5xx
├── Latency p95 / p99
├── Traffic
├── CPU / RAM / Disk
├── Database health
├── Queue backlog
├── Last deployments
└── Active alertsAlertes minimales
| Alerte | Condition indicative |
|---|---|
| Service down | Healthcheck KO 2 à 5 minutes. |
| High 5xx | 5xx > 2% pendant 5 minutes. |
| High latency | p95 > seuil pendant 10 minutes. |
| Disk high | Disque > 85%. |
| DB saturation | Connexions ou locks élevés. |
| Pipeline prod failed | Job apply ou deploy prod échoué. |
Parcours Incidents / SRE
Compétences incident à acquérir
| Compétence | Objectif |
|---|---|
| Triage | Qualifier impact, gravité, périmètre. |
| Mitigation | Restaurer vite avec action réversible. |
| Rollback | Revenir à une version ou config stable. |
| Communication | Messages courts, factuels, réguliers. |
| RCA | Comprendre cause racine et facteurs contributifs. |
| Post-mortem | Transformer incident en amélioration. |
| SLO | Mesurer la fiabilité depuis le point de vue utilisateur. |
Exercices simulation
Simulation 1 :
Healthcheck applicatif KO.
Objectif : diagnostiquer logs + restart contrôlé.
Simulation 2 :
Disque presque plein.
Objectif : identifier dossier, mitigation, prévention.
Simulation 3 :
Terraform state lock.
Objectif : identifier job détenteur, éviter force-unlock abusif.
Simulation 4 :
Security group DB cassé.
Objectif : rollback règle réseau.
Simulation 5 :
Déploiement app provoque 5xx.
Objectif : rollback + post-mortem.Process incident cible
Alerte
│
▼
Déclaration incident
│
├── gravité
├── canal
├── Incident Commander
└── timeline
│
▼
Mitigation
├── rollback
├── scale
├── feature flag
└── patch minimal
│
▼
Vérification retour nominal
│
▼
Communication de stabilisation
│
▼
Post-mortem
│
├── RCA
├── actions préventives
└── suiviMaturité SRE
| Niveau | Pratique |
|---|---|
| Débutant | Réagit aux alertes sans procédure claire. |
| Intermédiaire | Utilise runbooks et dashboards. |
| Pro | RCA, post-mortems, actions préventives suivies. |
| Avancé | SLO, error budget, GameDays, chaos testing contrôlé. |
Projets pratiques pour valider la RoadMap
Projet 1 : mini plateforme web
| Objectif | Déployer une application simple derrière Nginx ou load balancer. |
| Infra | VM ou container, DNS, TLS, firewall/security group. |
| Terraform | Modules network + compute + DNS. |
| CI/CD | Pipeline plan/apply manuel. |
| Observabilité | Logs, healthcheck, dashboard minimal. |
Projet 2 : backend distant Terraform
| Objectif | Mettre en place remote state sécurisé. |
| Exigences | Locking, chiffrement, versioning, isolation env. |
| Livrable | State dev/staging/prod séparé + documentation. |
Projet 3 : pipeline infra complet
| Objectif | Créer pipeline GitLab CI/CD Terraform production-ready. |
| Stages | fmt, validate, security, plan, apply, post-check. |
| Sécurité | Variables protected, runner protégé, approvals. |
| Livrable | MR avec plan lisible + apply manuel protégé. |
Projet 4 : simulation incident
| Objectif | Tester réponse incident sur environnement non-prod. |
| Scénarios | Disque plein, service down, pipeline lock, SG cassé. |
| Livrables | Timeline, runbook corrigé, post-mortem. |
Projet final recommandé
Mini production platform
│
├── Terraform modules
├── remote state par environnement
├── GitLab CI/CD plan/apply
├── secrets protégés
├── app déployée
├── DNS/TLS
├── logs + metrics
├── dashboard
├── alertes
├── runbooks
└── simulation incident + post-mortemRoadMap de maturité DevOps pour une équipe
Niveaux de maturité équipe
| Niveau | Situation | Priorité |
|---|---|---|
| 0. Manuel | ClickOps, changements console, pas de state partagé. | Mettre l’infra critique en Terraform. |
| 1. Versionné | Terraform dans Git, mais peu de CI/CD. | Ajouter fmt/validate/plan en MR. |
| 2. Contrôlé | Plan en CI, remote state, apply manuel. | Protéger branches, variables, environments. |
| 3. Sécurisé | Scans, approvals, secrets gérés, IAM minimal. | Ajouter OIDC, policies, audit. |
| 4. Observable | Dashboards, alertes, logs, post-checks. | Runbooks et SLO. |
| 5. SRE mature | SLO, error budget, GameDays, amélioration continue. | Optimisation fiabilité/coût/vitesse. |
RoadMap équipe en 5 étapes
Étape 1 : Stop ClickOps
├── inventorier infra
├── créer Terraform baseline
└── remote state
Étape 2 : CI/CD minimale
├── fmt
├── validate
└── plan en MR
Étape 3 : Contrôle production
├── branches protégées
├── variables protégées
├── apply manuel
└── approvals
Étape 4 : Observabilité
├── logs
├── metrics
├── dashboards
└── alertes
Étape 5 : SRE
├── runbooks
├── post-mortems
├── SLO
└── GameDaysKPIs de maturité
| Change failure rate | Combien de changements provoquent incidents. |
| MTTR | Temps moyen de restauration. |
| Deployment frequency | Capacité à livrer régulièrement. |
| Lead time | Temps entre commit et production. |
| Alert noise | Volume d’alertes inutiles. |
Checklist finale RoadMap DevOps
Checklist compétences individuelles
| Compétence | Validation |
|---|---|
| Linux | Je sais diagnostiquer service, logs, CPU, RAM, disque. |
| Réseau | Je sais tester DNS, TLS, ports, HTTP, load balancer. |
| Terraform | Je sais lire un plan et expliquer chaque changement. |
| Modules | Je sais créer modules propres avec inputs/outputs. |
| State | Je sais configurer remote state, locking et séparation env. |
| GitLab CI/CD | Je sais créer pipeline fmt/validate/plan/apply manuel. |
| Sécurité | Je sais protéger secrets, variables, IAM, runners. |
| Observabilité | Je sais créer logs, metrics, dashboards et alertes utiles. |
| Incidents | Je sais suivre un runbook, mitiger et documenter. |
Checklist plateforme production-ready
| Élément | Attendu |
|---|---|
| Infra as Code | Infrastructure critique décrite dans Terraform. |
| Remote state | Distant, chiffré, verrouillé, isolé. |
| CI/CD | Plan en MR, apply manuel prod, artifacts. |
| Environnements | Dev/staging/prod séparés. |
| Secrets | Pas dans Git, variables protégées ou secret manager. |
| Approvals | Production protégée. |
| Observabilité | Dashboard + alertes critiques + logs. |
| Runbooks | Rollback, restart, saturation, DB, pipeline lock. |
| Post-mortem | Process RCA et actions préventives. |
Mini-cheat-sheet RoadMap
1. Linux + réseau
2. Cloud basics
3. Terraform basics
4. Modules Terraform
5. Remote state + locking
6. GitLab CI/CD infra
7. Secrets + IAM least privilege
8. Environnements dev/staging/prod
9. Déploiement contrôlé
10. Observabilité
11. Runbooks
12. Incidents + post-mortems + SRECheat-sheet DevOps infra : objectif
Cette cheat-sheet regroupe les commandes et réflexes essentiels pour travailler efficacement sur une infrastructure moderne : Terraform, GitLab CI/CD, Linux, réseau, debugging pipeline, sécurité, audit et vérifications production.
Elle est pensée comme un support opérationnel : avant une merge request, avant un apply production, pendant un incident, ou pour préparer un entretien DevOps.
Domaines couverts
| Domaine | Usage |
|---|---|
| Terraform | Initialiser, valider, planifier, appliquer, importer, inspecter. |
| State | Diagnostiquer drift, lock, remote state, ressources connues. |
| GitLab CI/CD | Analyser pipeline, runners, artifacts, variables et environments. |
| Linux | Diagnostiquer services, logs, CPU, RAM, disque, réseau local. |
| Réseau | Tester DNS, TLS, ports, HTTP, load balancer, connectivité. |
| Production | Vérifier health checks, logs, métriques, alertes et rollback. |
| Sécurité | Secrets, IAM, audit, logs sensibles, variables protégées. |
Flux mental avant action
Avant toute commande sensible
│
├── Quel environnement ?
│ ├── dev
│ ├── staging
│ └── prod
│
├── Quel state Terraform ?
│ ├── backend
│ ├── key
│ └── lock
│
├── Quel impact ?
│ ├── réseau
│ ├── IAM
│ ├── database
│ ├── compute
│ └── DNS
│
├── Quel rollback ?
│
└── Comment vérifier après ?Commandes à traiter avec prudence
| Commande | Pourquoi prudence |
|---|---|
terraform apply | Modifie réellement l’infrastructure. |
terraform destroy | Détruit les ressources gérées. |
terraform state rm | Terraform oublie une ressource sans la supprimer. |
terraform force-unlock | Peut casser un apply encore actif. |
rm -rf | Suppression potentiellement irréversible. |
systemctl restart | Peut provoquer une coupure de service. |
Commandes Terraform essentielles
Cycle standard
# Initialiser le dossier Terraform
terraform init
# Formater le code
terraform fmt -recursive
terraform fmt -check -recursive
# Valider la configuration
terraform validate
# Générer un plan
terraform plan
# Générer un plan sauvegardé
terraform plan -out=tfplan
# Lire un plan binaire en texte
terraform show -no-color tfplan
# Appliquer le plan exact
terraform apply tfplan
# Appliquer directement
terraform apply
# Afficher les outputs
terraform outputtfplan, le relire, puis appliquer exactement ce plan.Commandes avec variables
# Plan avec fichier variables
terraform plan -var-file="dev.tfvars"
terraform plan -var-file="staging.tfvars"
terraform plan -var-file="prod.tfvars"
# Plan sauvegardé avec tfvars
terraform plan -var-file="prod.tfvars" -out=tfplan
# Variable inline
terraform plan -var="environment=prod"
# Utiliser une variable d'environnement
export TF_VAR_environment="prod"
terraform planLecture rapide du plan
| Symbole | Signification | Réflexe |
|---|---|---|
+ | Création | Vérifier coût, tags, sécurité. |
~ | Modification | Comprendre l’impact. |
-/+ | Remplacement | Analyse obligatoire. |
- | Suppression | Stop si non attendu. |
Structure Terraform propre
versions.tf # versions Terraform et providers
providers.tf # configuration provider
backend.tf # configuration remote state
variables.tf # inputs
locals.tf # valeurs calculées
main.tf # ressources ou appels modules
outputs.tf # outputs utiles
*.tfvars # valeurs par environnementState Terraform, drift, import et lock
Inspection du state
# Lister les ressources connues du state
terraform state list
# Afficher une ressource précise
terraform state show aws_instance.web
# Afficher les outputs
terraform output
# Exporter le state courant localement
terraform state pull > state-backup.json
# Pousser un state modifié
# À éviter sauf procédure contrôlée
terraform state push state-backup.jsonDrift detection
# Voir les écarts entre state et infrastructure réelle
terraform plan -refresh-only
# Appliquer uniquement la mise à jour du state
terraform apply -refresh-onlyImport / move / remove
# Importer une ressource existante dans Terraform
terraform import aws_security_group.web sg-0123456789abcdef0
# Déplacer une ressource dans le state
terraform state mv aws_instance.web aws_instance.app
# Retirer une ressource du state sans la détruire
terraform state rm aws_instance.webState lock
# Déverrouiller un lock orphelin
# Seulement après preuve qu'aucun apply n'est actif
terraform force-unlock LOCK_IDRemote state
data "terraform_remote_state" "network" {
backend = "s3"
config = {
bucket = "company-terraform-state-prod"
key = "prod/network/terraform.tfstate"
region = "eu-west-3"
}
}force-unlock, state rm ou state push sans sauvegarde, revue et compréhension exacte.Diagnostic state rapide
| Symptôme | Commande | But |
|---|---|---|
| Ressource inconnue | terraform state list | Voir si Terraform la gère. |
| Diff inattendu | terraform plan -refresh-only | Détecter drift. |
| Apply bloqué | Logs pipeline + lock ID | Identifier détenteur du lock. |
| Ressource existante | terraform import | Rattacher au state. |
GitLab CI/CD : commandes, YAML et debug rapide
Git essentiel pour infra
# État du repo
git status
# Créer une branche
git checkout -b infra/change-name
# Voir les changements
git diff
git diff --staged
# Ajouter / commit
git add .
git commit -m "Update Terraform infrastructure"
# Historique
git log --oneline -10
# Revenir à un commit par revert
git revert <commit_id>
# Voir fichiers modifiés
git show --statGitLab Runner
# Vérifier runners
gitlab-runner verify
gitlab-runner list
# Service runner
systemctl status gitlab-runner --no-pager
journalctl -u gitlab-runner -n 100 --no-pager
journalctl -u gitlab-runner -fTemplate pipeline Terraform minimal
stages:
- lint
- validate
- plan
- apply
variables:
TF_IN_AUTOMATION: "true"
TF_INPUT: "false"
TF_ROOT: "infra/live/prod/app"
default:
image: hashicorp/terraform:1.6.6
before_script:
- cd "$TF_ROOT"
- terraform init
terraform_fmt:
stage: lint
script:
- terraform fmt -check -recursive
terraform_validate:
stage: validate
script:
- terraform validate
terraform_plan:
stage: plan
script:
- terraform plan -out=tfplan
- terraform show -no-color tfplan > plan.txt
artifacts:
paths:
- "$TF_ROOT/tfplan"
- "$TF_ROOT/plan.txt"
expire_in: 3 days
terraform_apply:
stage: apply
script:
- terraform apply tfplan
when: manual
rules:
- if: '$CI_COMMIT_BRANCH == "main"'Mots-clés GitLab utiles
| Mot-clé | Usage |
|---|---|
stages | Ordre logique du pipeline. |
rules | Conditions d’exécution des jobs. |
needs | Dépendances rapides entre jobs. |
artifacts | Conserver plan, rapports, logs utiles. |
environment | Associer job à dev/staging/prod. |
when: manual | Apply manuel contrôlé. |
tags | Sélectionner runner adapté. |
Linux : diagnostic production rapide
État système
# Charge et uptime
uptime
# CPU / process
top
ps aux --sort=-%cpu | head
ps aux --sort=-%mem | head
# Mémoire
free -h
dmesg | grep -i "killed process"
# Disque
df -h
df -i
du -sh /var/log/* | sort -h
du -sh /tmp/* | sort -h
# Réseau local
ss -tulpn
ip addr
ip routeServices systemd
# Statut service
systemctl status nginx --no-pager
systemctl status app.service --no-pager
# Redémarrage contrôlé
sudo systemctl restart app.service
# Activer/désactiver au boot
sudo systemctl enable app.service
sudo systemctl disable app.serviceLogs
# Logs service
journalctl -u app.service -n 100 --no-pager
journalctl -u app.service -f
# Erreurs système récentes
journalctl -p err -n 100 --no-pager
# Nginx
tail -f /var/log/nginx/access.log
tail -f /var/log/nginx/error.log
# Chercher erreurs HTTP 500
grep " 500 " /var/log/nginx/access.log | tail
# Logs depuis une heure
journalctl --since "1 hour ago" --no-pagerSaturation disque
df -h
du -sh /var/log/* | sort -h
journalctl --disk-usage
# Nettoyage journal systemd contrôlé
sudo journalctl --vacuum-time=7d
# Attention : vérifier avant suppression manuelleDiagnostic par symptôme
| Symptôme | Commandes | Hypothèse |
|---|---|---|
| Service down | systemctl status, journalctl -u | Crash, config, dépendance KO. |
| Lenteur | top, free -h, logs app | CPU, RAM, DB, API externe. |
| Disque plein | df -h, du -sh | Logs, backups, uploads. |
| Port non ouvert | ss -tulpn, nc -vz | Service non lancé, firewall, bind. |
Réseau, DNS, HTTP, TLS et load balancer
DNS
# Résolution DNS
dig example.com
dig +short example.com
nslookup example.com
# Vérifier un record précis
dig A example.com
dig CNAME www.example.com
dig TXT example.com
# Voir TTL
dig example.comHTTP / HTTPS
# Tester endpoint
curl -v https://example.com/
curl -fsS https://example.com/health/
# Voir headers
curl -I https://example.com/
# Tester avec host header
curl -H "Host: example.com" http://IP_ADDRESS/
# Mesurer temps
curl -w "@curl-format.txt" -o /dev/null -s https://example.com/TLS / certificats
# Vérifier certificat TLS
openssl s_client -connect example.com:443 -servername example.com
# Dates certificat
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
| openssl x509 -noout -dates
# Certbot
sudo certbot certificates
sudo certbot renew --dry-runConnectivité ports
# Tester port TCP
nc -vz example.com 443
nc -vz db.internal 5432
nc -vz redis.internal 6379
# Ports ouverts localement
ss -tulpn
# Routes
ip route
traceroute example.comDiagnostic HTTP rapide
| Code | Cause fréquente | Vérification |
|---|---|---|
| 502 | Backend invalide ou indisponible. | Logs proxy + service app. |
| 503 | Aucun backend disponible. | Targets LB, healthcheck, autoscaling. |
| 504 | Timeout upstream. | App lente, DB lente, timeout proxy. |
| TLS error | Certificat expiré ou mauvais SNI. | openssl s_client, certbot, LB cert. |
| NXDOMAIN | DNS absent ou zone incorrecte. | dig, zone DNS, registrar. |
Vérifications production avant / pendant / après apply
Avant apply production
| Contrôle | Commande / preuve |
|---|---|
| Bon environnement | Afficher $CI_ENVIRONMENT_NAME, $TF_ROOT, backend key. |
| Plan relu | terraform show -no-color tfplan |
| Pas de destroy inattendu | Review du plan. |
| State distant | terraform init avec backend attendu. |
| Monitoring prêt | Dashboards ouverts. |
| Rollback connu | Runbook ou procédure. |
Pendant apply
# Ne pas lancer plusieurs apply
# Surveiller logs du job
# Noter toute ressource en erreur
# Ne pas force-unlock sans preuve
# Si échec partiel : relancer plan avant correctionAprès apply production
# Outputs Terraform
terraform output
# Health checks
curl -fsS https://example.com/health/
curl -fsS https://example.com/api/status/
# Logs applicatifs
journalctl -u app.service -n 100 --no-pager
# Nginx errors
tail -n 100 /var/log/nginx/error.log
# Vérifier erreurs 5xx
grep " 500 " /var/log/nginx/access.log | tailSignaux de santé
| Domaine | Signal attendu |
|---|---|
| HTTP | Healthcheck OK, 5xx stables. |
| Latence | p95/p99 sans hausse anormale. |
| Infra | CPU/RAM/disque normaux. |
| DB | Connexions, locks, slow queries OK. |
| Alerting | Aucune nouvelle alerte critique. |
Debug pipeline Terraform / GitLab
Pipeline bloqué ou failed
| Symptôme | Cause probable | Vérification |
|---|---|---|
| Job pending | Runner indisponible ou mauvais tags. | Runner list, tags job. |
| Variable vide | Variable protected/scoped inaccessible. | Branche, environnement, scope variable. |
terraform init échoue | Backend ou credentials. | Bucket, state, IAM, réseau. |
| State lock | Autre apply actif ou lock orphelin. | Job détenteur, logs pipeline. |
| Artifact absent | Mauvais path ou expiration. | artifacts.paths, dependencies, needs. |
| Plan local différent CI | Variables ou versions différentes. | Terraform version, provider lock, tfvars. |
Méthode de debug
Job échoué
│
▼
Lire logs depuis le début
│
├── image Docker
├── dossier courant
├── variables non sensibles
├── terraform version
├── terraform init
├── provider error
└── backend / state
│
▼
Corriger cause minimale
│
▼
Relancer plan
│
▼
Apply seulement si plan OKCommandes debug CI sûres
# Afficher contexte non sensible
echo "Branch: $CI_COMMIT_BRANCH"
echo "Environment: $CI_ENVIRONMENT_NAME"
echo "Terraform root: $TF_ROOT"
terraform --version
# Vérifier présence variable sans l'afficher
if [ -z "$AWS_ACCESS_KEY_ID" ]; then
echo "AWS_ACCESS_KEY_ID is missing"
exit 1
else
echo "AWS_ACCESS_KEY_ID is present"
fi
# Terraform debug utile
terraform providers
terraform validate
terraform plan -refresh-onlyÀ ne pas faire
# Dangereux : affiche secrets potentiels
env
printenv
echo "$AWS_SECRET_ACCESS_KEY"
# Dangereux en job sensible
set -x
# Dangereux sans analyse
terraform force-unlock LOCK_IDSécurité, secrets, audit et contrôles rapides
Secrets GitLab / CI
| Contrôle | Attendu |
|---|---|
| Masked | Secrets masqués dans logs. |
| Protected | Secrets prod disponibles seulement branches/tags protégés. |
| Environment scoped | Secrets limités à dev/staging/prod. |
| Rotation | Procédure connue et testée. |
| OIDC | Préférer credentials temporaires si possible. |
| Least privilege | Rôle CI limité aux actions nécessaires. |
Secret scanning local
# Exemples d'outils possibles
gitleaks detect
trufflehog filesystem .
detect-secrets scan
# Recherche simple à la main
grep -R "AWS_SECRET" .
grep -R "PRIVATE KEY" .
grep -R "password" .Scan IaC
# Checkov
checkov -d .
# tfsec
tfsec .
# Trivy config
trivy config .
# Terraform format/validate
terraform fmt -check -recursive
terraform validateAudit rapide après incident
| Question | Où chercher |
|---|---|
| Qui a lancé le pipeline ? | GitLab pipeline / job details. |
| Quel commit a changé l’infra ? | MR, commit, plan artifact. |
| Quel rôle cloud a agi ? | Cloud audit logs / CloudTrail. |
| Un secret a-t-il fuité ? | Logs CI, artifacts, Git history. |
| Le state a-t-il été modifié ? | Backend state versioning / logs. |
.gitignore Terraform minimal
.terraform/
*.tfstate
*.tfstate.*
crash.log
crash.*.log
*.tfvars
*.tfvars.json
override.tf
override.tf.json
*_override.tf
*_override.tf.jsonRéponses courtes pour entretien DevOps
Terraform
J’utilise Terraform pour décrire l’infrastructure as code,
avec une structure claire en modules, variables, outputs et environnements séparés.
Je fais toujours relire le plan avant apply, surtout en production.
Je fais attention au remote state, au locking, au drift et aux risques de destroy/replace.
Mon approche est de rendre l’infrastructure reproductible, traçable et contrôlée.GitLab CI/CD infra
Oui, j’ai travaillé sur des pipelines GitLab CI/CD orientés infrastructure.
Je structure les étapes fmt, validate, security scan, plan, review et apply manuel.
J’utilise des artifacts pour conserver le plan, des variables protégées et des branches protégées.
En production, l’apply doit être contrôlé, approuvé et vérifié après exécution.State Terraform
Je considère le state Terraform comme un composant critique.
En production, il doit être distant, chiffré, verrouillé, versionné et isolé par environnement.
Je fais attention au drift, aux imports et aux opérations sensibles comme state rm ou force-unlock.
Je ne commite jamais de tfstate dans Git.Incidents production
Oui, j’ai déjà géré des incidents production.
Ma méthode est de qualifier l’impact, stabiliser, mitiger, restaurer le service,
puis analyser la cause racine à froid.
Je privilégie rollback, contournement ou correction minimale selon le contexte.
Après incident, je formalise un post-mortem avec actions préventives.Secrets et sécurité CI
Je fais attention à ne jamais stocker de secrets dans Git.
J’utilise des variables GitLab masked, protected et scopées par environnement.
Je privilégie les credentials courts, OIDC ou secret manager lorsque c’est possible.
Côté cloud, j’applique le principe du moindre privilège avec des rôles séparés par environnement.Observabilité
Je mets en place logs, métriques, alertes et dashboards pour piloter la production.
Les signaux importants sont les 5xx, la latence p95/p99, la saturation système,
les connexions DB, les queues et les échecs pipeline.
Une bonne alerte doit être actionnable et liée à un runbook.Formule synthétique très professionnelle
Mon approche DevOps est orientée production :
infrastructure as code, pipelines contrôlés, secrets protégés, observabilité,
rollback documenté et amélioration continue après incident.Checklist opérationnelle finale
Avant merge request infra
| Point | OK ? |
|---|---|
terraform fmt -check -recursive | Format validé. |
terraform validate | Configuration valide. |
| Plan généré | Plan lisible en artifact. |
| Destroy/replace relus | Justifiés ou absents. |
| Secrets absents | Pas de secret dans Git, logs, plan. |
| Scan IaC | Pas de risque bloquant. |
| Rollback | Procédure claire. |
Avant apply production
| Bon environnement | Production clairement ciblée. |
| Bon state | Backend distant + key correcte. |
| Locking actif | Pas d’apply concurrent. |
| Approval obtenu | Reviewer compétent. |
| Fenêtre adaptée | Si changement risqué. |
| Dashboards ouverts | Surveillance prête. |
Après apply production
| Zone | Validation |
|---|---|
| Terraform | Apply terminé sans erreur, outputs cohérents. |
| Cloud | Ressources healthy. |
| HTTP | Healthcheck OK. |
| Logs | Pas de nouvelle erreur critique. |
| Metrics | 5xx, latence, CPU/RAM stables. |
| DB | Connexions, locks, slow queries OK. |
| Alerting | Aucune alerte critique nouvelle. |
| Documentation | Change request mise à jour. |
Ultra cheat-sheet
terraform fmt -check -recursive
terraform validate
terraform plan -out=tfplan
terraform show -no-color tfplan > plan.txt
terraform apply tfplan
terraform plan -refresh-only
terraform state list
git status
git diff
git log --oneline -10
systemctl status app.service
journalctl -u app.service -n 100
df -h
free -h
curl -fsS https://example.com/health/
dig example.com
nc -vz host portLe design Terraform avancé : écrire du code sûr, lisible et stable
Le design Terraform avancé ne consiste pas à rendre le code “plus intelligent”. Il consiste à rendre l’infrastructure prévisible, lisible, contrôlée, réutilisable et moins dangereuse en production.
Un bon code Terraform permet à un autre DevOps de comprendre rapidement : quels paramètres sont exposés, quelles valeurs sont calculées, quelles ressources seront créées, quelles dépendances existent, quels garde-fous protègent les ressources critiques et comment le plan doit être relu.
Les piliers du design Terraform
| Pilier | But | Exemple |
|---|---|---|
| Naming | Créer des noms prévisibles et cohérents. | project-env-component-region |
| Locals | Centraliser les valeurs calculées. | Préfixes, tags, maps, conventions. |
| Validations | Bloquer les mauvaises entrées tôt. | Environnement limité à dev/staging/prod. |
| for_each | Créer plusieurs ressources avec des clés stables. | Subnets, DNS records, security rules. |
| Lifecycle | Protéger ou contrôler les changements sensibles. | prevent_destroy sur database. |
| Dépendances | Laisser Terraform construire un graphe propre. | Références directes plutôt que depends_on abusif. |
Vision globale
variables.tf
│
├── inputs typés
├── descriptions
├── defaults sûrs
└── validations
│
▼
locals.tf
│
├── name_prefix
├── common_tags
├── maps normalisées
└── valeurs calculées
│
▼
main.tf
│
├── resources
├── for_each / dynamic blocks
├── lifecycle
└── dépendances implicites
│
▼
outputs.tf
│
├── valeurs utiles
├── IDs nécessaires
└── aucun secret inutileBon design vs mauvais design
| Bon design | Mauvais design |
|---|---|
| Noms prévisibles et cohérents. | Noms codés en dur partout. |
| Variables typées et validées. | Variables libres sans contraintes. |
| Modules spécialisés et lisibles. | Module géant “qui fait tout”. |
for_each avec clés stables. | count fragile sur listes réordonnées. |
| Lifecycle sur ressources critiques. | Database destructible par erreur. |
| Outputs minimaux. | Outputs bavards ou sensibles. |
Naming Terraform : conventions lisibles et robustes
Le naming est fondamental. Il permet d’identifier rapidement à quel projet, environnement, composant, région ou équipe appartient une ressource.
Convention recommandée
locals {
name_prefix = "${var.project}-${var.environment}-${var.component}"
common_tags = {
Project = var.project
Environment = var.environment
Component = var.component
ManagedBy = "terraform"
Owner = var.owner
}
}Exemples de noms
| Ressource | Nom recommandé |
|---|---|
| Load balancer API prod | ideo-prod-api-alb |
| Security group web staging | ideo-staging-web-sg |
| Database production | ideo-prod-main-db |
| Redis dev | ideo-dev-cache-redis |
| Bucket logs | ideo-prod-logs-eu-west-3 |
Variables de naming
variable "project" {
description = "Project name used in resource naming."
type = string
}
variable "environment" {
description = "Environment name."
type = string
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "Environment must be dev, staging, or prod."
}
}
variable "component" {
description = "Application or infrastructure component."
type = string
}
variable "owner" {
description = "Team or owner responsible for this resource."
type = string
}Nommage : erreurs fréquentes
| Erreur | Conséquence |
|---|---|
| Noms codés en dur | Duplication et conflits entre environnements. |
| Pas d’environnement dans le nom | Confusion dev/staging/prod. |
| Noms trop longs | Limites provider dépassées. |
| Noms non stables | Terraform peut vouloir remplacer des ressources. |
| Noms avec caractères non autorisés | Plan ou apply échoue selon provider. |
Locals : centraliser les valeurs calculées
Les locals permettent de calculer une fois des valeurs réutilisées partout : préfixes, tags, noms, maps normalisées, règles transformées, listes filtrées. Ils rendent le code plus lisible et évitent les répétitions.
Exemple propre de locals.tf
locals {
name_prefix = "${var.project}-${var.environment}-${var.component}"
common_tags = merge(
{
Project = var.project
Environment = var.environment
Component = var.component
ManagedBy = "terraform"
},
var.extra_tags
)
is_prod = var.environment == "prod"
default_backup_retention_days = local.is_prod ? 14 : 3
default_deletion_protection = local.is_prod ? true : false
}Utilisation dans une ressource
resource "aws_security_group" "web" {
name = "${local.name_prefix}-web-sg"
description = "Security group for web traffic"
vpc_id = var.vpc_id
tags = local.common_tags
}local.Cas d’usage des locals
| Usage | Exemple |
|---|---|
| Préfixe de nom | ${var.project}-${var.environment} |
| Tags communs | Project, Environment, Owner, ManagedBy. |
| Valeur conditionnelle | Backup plus long en production. |
| Map normalisée | Transformer une liste en map pour for_each. |
| Feature flags | Activer monitoring seulement en staging/prod. |
Locals à éviter
# Mauvais : local trop magique et illisible
locals {
everything = {
for x in var.services :
x.name => merge(x, {
final_name = "${var.project}-${var.environment}-${x.name}"
enabled = try(x.enabled, true)
settings = try(x.settings, {})
})
}
}Diagramme d’usage
variables brutes
│
▼
locals
├── conventions
├── calculs
├── tags
├── defaults intelligents
└── maps propres
│
▼
resources lisibles
│
▼
outputs utilesValidations : bloquer les mauvaises entrées avant production
Les validations Terraform permettent d’éviter des erreurs de configuration avant le plan ou l’apply. Elles sont essentielles pour les modules partagés, car elles empêchent les utilisateurs du module de passer des valeurs dangereuses, incohérentes ou non supportées.
Validation d’environnement
variable "environment" {
description = "Deployment environment."
type = string
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "Environment must be dev, staging, or prod."
}
}Validation CIDR
variable "vpc_cidr" {
description = "CIDR block for the VPC."
type = string
validation {
condition = can(cidrhost(var.vpc_cidr, 0))
error_message = "vpc_cidr must be a valid CIDR block."
}
}Validation taille instance
variable "instance_type" {
description = "EC2 instance type."
type = string
validation {
condition = contains([
"t3.micro",
"t3.small",
"t3.medium"
], var.instance_type)
error_message = "Instance type must be one of the approved values."
}
}Validations utiles en production
| Variable | Validation recommandée |
|---|---|
environment | Limiter à dev, staging, prod. |
allowed_cidr_blocks | Interdire 0.0.0.0/0 sur ports sensibles. |
backup_retention_days | Minimum plus élevé en production. |
deletion_protection | Forcer true en production pour DB. |
instance_type | Limiter à une liste approuvée. |
domain_name | Vérifier format ou suffixe autorisé. |
Validation objet complexe
variable "services" {
description = "Map of services to deploy."
type = map(object({
image = string
desired_count = number
public = bool
}))
validation {
condition = alltrue([
for service in var.services :
service.desired_count >= 1
])
error_message = "Each service must have desired_count greater than or equal to 1."
}
}count, for_each et dynamic blocks
count et for_each permettent de créer plusieurs ressources. En production, for_each est souvent préférable car il utilise des clés stables, alors que count dépend des index de liste.
count : simple mais fragile
resource "aws_subnet" "private" {
count = length(var.private_subnets)
vpc_id = var.vpc_id
cidr_block = var.private_subnets[count.index]
tags = merge(local.common_tags, {
Name = "${local.name_prefix}-private-${count.index + 1}"
})
}Quand utiliser count ?
| Activation simple | count = var.enabled ? 1 : 0 |
| Ressource optionnelle | Créer ou non une ressource unique. |
| Liste non critique | Cas simples avec faible risque de réordonnancement. |
for_each : recommandé pour les collections stables
variable "private_subnets" {
type = map(object({
cidr_block = string
availability_zone = string
}))
}
resource "aws_subnet" "private" {
for_each = var.private_subnets
vpc_id = var.vpc_id
cidr_block = each.value.cidr_block
availability_zone = each.value.availability_zone
tags = merge(local.common_tags, {
Name = "${local.name_prefix}-private-${each.key}"
})
}Exemple tfvars
private_subnets = {
"a" = {
cidr_block = "10.20.11.0/24"
availability_zone = "eu-west-3a"
}
"b" = {
cidr_block = "10.20.12.0/24"
availability_zone = "eu-west-3b"
}
}for_each avec des clés métier stables : a, b, api, worker, admin.Dynamic blocks : utile mais à doser
resource "aws_security_group" "service" {
name = "${local.name_prefix}-sg"
vpc_id = var.vpc_id
dynamic "ingress" {
for_each = var.ingress_rules
content {
description = ingress.value.description
from_port = ingress.value.from_port
to_port = ingress.value.to_port
protocol = ingress.value.protocol
cidr_blocks = ingress.value.cidr_blocks
}
}
tags = local.common_tags
}dynamic blocks rendent le module difficile à lire. Pour les règles critiques, la clarté vaut souvent mieux que la généricité.Lifecycle : protéger et contrôler les changements sensibles
Le bloc lifecycle permet d’ajouter des garde-fous sur certaines ressources : empêcher la destruction, créer avant de détruire, ignorer certains changements ou remplacer une ressource quand une dépendance change.
prevent_destroy
resource "aws_db_instance" "main" {
identifier = "${local.name_prefix}-db"
lifecycle {
prevent_destroy = true
}
}Très utile pour les ressources critiques : bases de données, buckets contenant des données, clés KMS, volumes persistants.
create_before_destroy
resource "aws_launch_template" "app" {
name_prefix = "${local.name_prefix}-"
lifecycle {
create_before_destroy = true
}
}Utile quand on veut réduire le downtime en créant la nouvelle ressource avant de supprimer l’ancienne.
prevent_destroy protège, mais ne remplace pas la revue du plan.ignore_changes
resource "aws_autoscaling_group" "app" {
name = "${local.name_prefix}-asg"
desired_capacity = var.desired_capacity
lifecycle {
ignore_changes = [
desired_capacity
]
}
}Peut être utile si l’autoscaling modifie une valeur que Terraform ne doit pas corriger à chaque plan.
Lifecycle : cas d’usage
| Option | Usage | Risque |
|---|---|---|
prevent_destroy | Protéger DB, buckets, volumes. | Peut bloquer un changement voulu. |
create_before_destroy | Réduire downtime sur ressources remplaçables. | Peut nécessiter noms uniques. |
ignore_changes | Ignorer drift contrôlé. | Peut masquer un vrai problème. |
replace_triggered_by | Forcer remplacement si dépendance change. | À utiliser avec prudence. |
ignore_changes ne doit pas servir à cacher un drift qu’on ne comprend pas.Dépendances Terraform : laisser le graphe travailler
Terraform construit un graphe de dépendances à partir des références entre ressources. Dans la plupart des cas, il ne faut pas ajouter depends_on manuellement : une référence explicite suffit.
Dépendance implicite recommandée
resource "aws_security_group" "web" {
name = "${local.name_prefix}-web-sg"
vpc_id = aws_vpc.main.id
}
resource "aws_instance" "web" {
ami = var.ami_id
instance_type = var.instance_type
vpc_security_group_ids = [aws_security_group.web.id]
}Ici, l’instance dépend automatiquement du security group parce qu’elle référence son ID.
depends_on explicite
resource "aws_instance" "app" {
ami = var.ami_id
instance_type = var.instance_type
depends_on = [
aws_cloudwatch_log_group.app
]
}depends_on doit rester exceptionnel. Trop de dépendances manuelles rendent le graphe rigide et difficile à comprendre.Quand utiliser depends_on ?
| Cas | Justification |
|---|---|
| Dépendance non visible dans les attributs | Terraform ne peut pas la deviner. |
| Ordre requis par provider | API externe nécessite une ressource prête. |
| Module dépendant d’un autre module | Seulement si les outputs ne créent pas déjà la dépendance. |
| Provisioning spécial | Cas rares, souvent à éviter. |
Diagramme du graphe
aws_vpc.main
│
▼
aws_subnet.private
│
▼
aws_security_group.app
│
▼
aws_instance.app
│
▼
aws_lb_target_group_attachment.appPièges de dépendances
| Dépendance circulaire | Deux ressources se référencent mutuellement. |
depends_on global | Ralentit et rigidifie tout le plan. |
| Data source trop tôt | Lecture d’un objet pas encore créé. |
| Module trop couplé | Chaque changement force trop d’autres modules. |
Design avancé des modules Terraform
Un module Terraform est une API d’infrastructure. Son design doit être stable, documenté, sécurisé par défaut et assez simple pour être utilisé sans lire tout son code interne.
Contrat d’un module
| Élément | Bonne pratique |
|---|---|
| Inputs | Peu nombreux, typés, décrits et validés. |
| Outputs | Seulement les valeurs utiles aux consommateurs. |
| Defaults | Sûrs par défaut, jamais trop permissifs. |
| README | Exemple d’usage, inputs, outputs, limitations. |
| Versioning | Tags Git ou registry, pas de production sur main. |
| Responsabilité | Un module doit avoir un périmètre clair. |
Module spécialisé
module "api_service" {
source = "../../modules/compute-service"
project = var.project
environment = var.environment
component = "api"
image = var.api_image
desired_count = 3
vpc_id = module.network.vpc_id
subnet_ids = module.network.private_subnet_ids
tags = local.common_tags
}Module trop générique : danger
module "universal_resource"
│
├── create_vpc
├── create_db
├── create_lb
├── create_dns
├── enable_cache
├── enable_iam
├── enable_monitoring
├── 80 variables
└── 25 conditionsBon découpage
modules/
├── network
├── security-group
├── load-balancer
├── compute-service
├── database-postgres
├── redis-cache
├── dns-record
└── monitoring-alarmRègles de design module
| Spécialiser | Un module fait une chose importante. |
| Limiter options | Exposer seulement ce qui doit varier. |
| Documenter | README + exemples + limites. |
| Tester | fmt, validate, scan, example plan. |
| Versionner | Tag stable pour production. |
Design Terraform orienté production
En production, le design Terraform doit réduire les erreurs humaines, limiter le blast radius, protéger les données, rendre les plans lisibles et faciliter le rollback ou la mitigation.
Garde-fous production
| Zone | Garde-fou |
|---|---|
| Database | deletion_protection, backups, prevent_destroy. |
| State | Remote backend, locking, versioning, chiffrement. |
| Secrets | Pas de secrets dans Git, outputs ou logs. |
| Réseau | Pas d’ouverture large sur ports sensibles. |
| IAM | Moindre privilège, pas de wildcard inutile. |
| Plan | Review obligatoire des destroy/replace. |
| Modules | Version stable, pas de branche mutable en prod. |
Exemple DB production
resource "aws_db_instance" "main" {
identifier = "${local.name_prefix}-db"
engine = "postgres"
instance_class = var.instance_class
allocated_storage = var.allocated_storage
backup_retention_period = local.default_backup_retention_days
deletion_protection = local.is_prod ? true : var.deletion_protection
lifecycle {
prevent_destroy = true
}
tags = local.common_tags
}Review production du plan
terraform plan
│
▼
Review obligatoire
├── destroy ?
├── replace ?
├── DB touchée ?
├── IAM modifié ?
├── réseau ouvert ?
├── DNS changé ?
├── secrets affichés ?
└── coût modifié ?
│
▼
Décision
├── OK : apply contrôlé
└── KO : correction avant mergeProduction design checklist
| State isolé | Prod séparé de dev/staging. |
| Variables validées | Entrées dangereuses bloquées. |
| Naming clair | Ressources identifiables. |
| Tags complets | Owner, env, cost, managed by Terraform. |
| Lifecycle adapté | Protection des ressources critiques. |
| Outputs sobres | Aucune valeur sensible inutile. |
| Plan lisible | Petit changement, review possible. |
Anti-patterns du design Terraform avancé
| Anti-pattern | Pourquoi c’est dangereux | Correction professionnelle |
|---|---|---|
| Noms codés en dur partout | Conflits, duplication, confusion env. | Utiliser locals.name_prefix. |
| Variables sans type | Erreurs détectées tard. | Types explicites et validations. |
| Module trop générique | Illisible, fragile, difficile à tester. | Modules spécialisés par responsabilité. |
count sur listes critiques | Réordonnancement peut provoquer mauvais diff. | for_each avec clés stables. |
ignore_changes abusif | Masque drift ou problème réel. | Limiter aux cas justifiés et documentés. |
depends_on partout | Graphe rigide, plan moins lisible. | Utiliser références directes. |
| Outputs sensibles | Fuite dans logs, state ou remote state. | Outputs minimaux, sensitive si nécessaire. |
| Pas de lifecycle sur DB | Suppression accidentelle possible. | prevent_destroy et protections provider. |
Mauvais modèle
main.tf énorme
├── noms codés en dur
├── variables non typées
├── count partout
├── depends_on partout
├── secrets en outputs
├── pas de validations
└── pas de garde-fous lifecycleBon modèle
Design clair
├── variables typées
├── validations utiles
├── locals lisibles
├── naming standardisé
├── for_each stable
├── lifecycle ciblé
├── outputs minimaux
└── modules spécialisésChecklist Design Terraform avancé
Checklist code
| Point | Validation attendue |
|---|---|
| Naming | Convention claire via locals.name_prefix. |
| Tags | Tags communs appliqués partout où possible. |
| Variables | Types, descriptions, defaults sûrs. |
| Validations | Valeurs dangereuses ou invalides bloquées. |
| Locals | Calculs centralisés, lisibles, non magiques. |
| for_each | Clés stables pour collections critiques. |
| Lifecycle | Ressources critiques protégées. |
| Outputs | Utiles, minimaux, non sensibles. |
| Modules | Responsabilité claire, README, version stable. |
Checklist review production
| Question | Pourquoi |
|---|---|
| Le plan contient-il un destroy ? | Risque de suppression. |
| Le plan contient-il un replace ? | Risque de downtime ou perte d’identité ressource. |
| Le naming a-t-il changé ? | Peut forcer remplacement. |
Un count a-t-il été modifié ? | Risque d’index instable. |
Un ignore_changes cache-t-il un drift ? | Risque de masquer un vrai problème. |
| Une ressource data est-elle touchée ? | Risque élevé. |
| Les secrets apparaissent-ils ? | Risque sécurité. |
| Le rollback est-il clair ? | Indispensable avant apply prod. |
Mini-cheat-sheet
# Naming
local.name_prefix = "${var.project}-${var.environment}-${var.component}"
# Validation
contains(["dev", "staging", "prod"], var.environment)
# Prefer stable keys
for_each = var.services
# Optional resource
count = var.enabled ? 1 : 0
# Critical resource protection
lifecycle {
prevent_destroy = true
}
# Safer production flow
terraform fmt -check -recursive
terraform validate
terraform plan -out=tfplan
terraform show -no-color tfplan
terraform apply tfplanImport & drift : reprendre le contrôle sans casser l’existant
Dans beaucoup d’entreprises, Terraform arrive après plusieurs années de création manuelle : instances, security groups, load balancers, bases de données, DNS, buckets, rôles IAM, certificats ou règles réseau déjà existants.
L’import Terraform permet de rattacher ces ressources existantes au state, sans les recréer. Le drift désigne l’écart entre le code Terraform, le state et la réalité cloud. Bien gérer les deux permet de reprendre progressivement le contrôle IaC.
Les 3 réalités à aligner
| Élément | Rôle | Risque si désaligné |
|---|---|---|
| Code Terraform | Décrit l’état souhaité. | Terraform veut modifier ou recréer. |
| State Terraform | Mémorise les ressources gérées et leurs IDs. | Terraform ne sait pas ce qu’il possède. |
| Cloud réel | Infrastructure effectivement déployée. | Drift, surprise au prochain plan. |
Diagramme Import / Drift
Infrastructure existante
│
├── créée manuellement
├── créée par ancien outil
├── créée par console cloud
└── créée par script historique
│
▼
Terraform import
│
├── rattache au state
├── nécessite un bloc resource
├── ne crée pas la ressource
└── ne garantit pas que le code est complet
│
▼
terraform plan
│
├── zéro diff : alignement OK
├── diff attendu : code à ajuster
└── destroy/replace : danger
│
▼
IaC maîtriséImport vs drift
| Concept | Définition | Action |
|---|---|---|
| Import | Rattacher une ressource existante au state. | Écrire code + importer ID provider. |
| Drift | Écart entre code/state/cloud réel. | Analyser, décider, corriger code ou réel. |
| State move | Renommer ou déplacer une ressource dans le state. | terraform state mv. |
| State remove | Retirer une ressource du state sans la détruire. | terraform state rm, avec prudence. |
Inventaire : cartographier avant d’importer
Un import propre commence par un inventaire. Il faut comprendre les ressources existantes, leurs dépendances, leur criticité, leurs noms, leurs tags, leurs liens réseau et leur usage réel.
Ce qu’il faut inventorier
| Famille | Exemples | Priorité |
|---|---|---|
| Réseau | VPC, subnets, routes, NAT, security groups. | Très élevée |
| Compute | VM, autoscaling, launch templates, containers. | Élevée |
| Load balancing | ALB, target groups, listeners, health checks. | Très élevée |
| Data | RDS, buckets, volumes, snapshots, Redis. | Critique |
| IAM | Roles, policies, users techniques, bindings. | Critique sécurité |
| DNS / TLS | Zones, records, certificats, validations. | Élevée |
Template d’inventaire
Resource inventory:
- Cloud provider:
- Account / project:
- Environment:
- Resource type:
- Resource name:
- Provider ID:
- Owner:
- Criticality:
- Dependencies:
- Data risk:
- Current tags:
- Import target address:
- Validation command:
- Rollback / mitigation:Ordre recommandé d’import
1. Ressources de base
├── VPC
├── subnets
├── route tables
└── security groups
2. Ressources partagées
├── IAM roles
├── KMS
├── DNS zones
└── certificates
3. Ressources applicatives
├── load balancer
├── target groups
├── compute
└── autoscaling
4. Ressources data
├── databases
├── buckets
├── volumes
└── cachesCritères de priorité
| Critère | Pourquoi |
|---|---|
| Criticité production | Plus c’est critique, plus il faut préparer. |
| Dépendances | Importer d’abord les fondations utilisées par les autres. |
| Risque data | DB et stockage nécessitent garde-fous renforcés. |
| Complexité provider | Certaines ressources ont beaucoup d’attributs calculés. |
| Historique de ClickOps | Plus il y a eu de changements manuels, plus le drift est probable. |
Terraform import classique
La commande terraform import rattache une ressource existante à une adresse Terraform. Elle ne crée pas automatiquement un code parfait : il faut écrire le bloc resource, importer l’ID, puis ajuster le code jusqu’à obtenir un plan propre.
Processus import standard
# 1. Écrire le bloc resource minimal
resource "aws_security_group" "web" {
name = "prod-web-sg"
vpc_id = var.vpc_id
}
# 2. Importer la ressource existante
terraform import aws_security_group.web sg-0123456789abcdef0
# 3. Inspecter la ressource importée
terraform state show aws_security_group.web
# 4. Lancer un plan
terraform plan
# 5. Compléter le code jusqu'à réduire le diff
terraform planterraform plan.Exemple import security group
resource "aws_security_group" "api" {
name = "${local.name_prefix}-api-sg"
description = "Security group for API service"
vpc_id = var.vpc_id
tags = local.common_tags
}
# Commande import
terraform import aws_security_group.api sg-0abc123456789def0
# Vérification
terraform state show aws_security_group.api
terraform planExemple import DNS record
resource "aws_route53_record" "api" {
zone_id = var.zone_id
name = "api.example.com"
type = "A"
alias {
name = aws_lb.api.dns_name
zone_id = aws_lb.api.zone_id
evaluate_target_health = true
}
}
# L'ID d'import dépend du provider et du type de record.
terraform import aws_route53_record.api ZONEID_api.example.com_AImport : ce qu’il faut vérifier après chaque ressource
| Contrôle | Commande | But |
|---|---|---|
| Présence dans le state | terraform state list | Confirmer l’import. |
| Détails importés | terraform state show RESOURCE | Comprendre les attributs réels. |
| Diff restant | terraform plan | Identifier ce que le code ne décrit pas. |
| Risque destroy/replace | Review du plan | Éviter accident production. |
Import blocks et génération de configuration
Les versions récentes de Terraform permettent d’utiliser des blocs import dans le code. Cette approche rend l’import plus traçable, relisible en merge request et plus adaptée aux workflows CI/CD.
Bloc import
import {
to = aws_security_group.api
id = "sg-0abc123456789def0"
}
resource "aws_security_group" "api" {
name = "prod-api-sg"
vpc_id = var.vpc_id
}Workflow avec import block
Écrire resource minimal
│
▼
Ajouter bloc import
│
▼
terraform plan
│
├── vérifie import
├── montre diff restant
└── permet review MR
│
▼
terraform apply
│
└── state mis à jour
│
▼
Retirer bloc import après réussite
│
▼
Commit final propreGénérer une configuration initiale
# Exemple conceptuel
terraform plan -generate-config-out=generated.tfLa génération de configuration peut aider à démarrer, mais le fichier généré doit être nettoyé, simplifié, commenté et adapté aux conventions du projet.
Après génération
| Étape | Action |
|---|---|
| Nettoyer | Retirer attributs calculés ou inutiles. |
| Renommer | Appliquer naming Terraform clair. |
| Factoriser | Déplacer tags, noms, valeurs répétées dans locals. |
| Paramétrer | Remplacer valeurs fixes par variables. |
| Protéger | Ajouter lifecycle si ressource critique. |
| Planifier | Répéter terraform plan jusqu’à diff maîtrisé. |
Drift : détecter et traiter la dérive
Le drift apparaît quand la réalité cloud ne correspond plus au code Terraform ou au state. Il vient souvent de changements manuels dans la console, de hotfixs d’urgence, de scripts externes, de changements provider ou d’un import incomplet.
Détection du drift
# Voir les écarts entre state et infrastructure réelle
terraform plan -refresh-only
# Mettre à jour le state avec la réalité observée
terraform apply -refresh-only
# Plan standard après refresh
terraform planExemple de drift
Code Terraform
instance_type = "t3.small"
State Terraform
instance_type = "t3.small"
Cloud réel
instance_type = "t3.medium"
Résultat :
terraform plan propose de revenir à t3.small
ou de modifier le state selon refreshCauses fréquentes
| Cause | Exemple | Traitement |
|---|---|---|
| ClickOps | Modification console cloud. | Reporter dans Terraform ou restaurer. |
| Hotfix urgence | Security group ouvert temporairement. | Documenter puis codifier ou annuler. |
| Script externe | Script modifie tags ou scaling. | Clarifier ownership. |
| Autoscaling | Desired capacity modifiée. | Éventuellement ignore_changes. |
| Import incomplet | Attribut non décrit dans code. | Compléter resource block. |
| Provider upgrade | Attribut calculé différemment. | Lire changelog, pinner versions. |
Décision sur drift
Drift détecté
│
▼
Changement légitime ?
│
├── Oui
│ ├── intégrer dans le code
│ ├── valider en MR
│ └── appliquer proprement
│
└── Non
├── restaurer état Terraform
├── supprimer changement manuel
└── renforcer garde-fou
│
▼
Documenter la décisionState operations : déplacer, retirer, inspecter
Les opérations sur le state sont puissantes et dangereuses. Elles modifient la mémoire de Terraform, pas forcément l’infrastructure réelle. Elles doivent être utilisées avec sauvegarde, revue et procédure.
Commandes state utiles
# Lister les ressources
terraform state list
# Inspecter une ressource
terraform state show aws_instance.web
# Sauvegarder localement le state
terraform state pull > state-backup.json
# Déplacer une ressource dans le state
terraform state mv aws_instance.web aws_instance.app
# Retirer une ressource du state sans la détruire
terraform state rm aws_instance.webRenommer une ressource proprement
# Ancien nom dans le state
aws_security_group.web
# Nouveau nom dans le code
aws_security_group.api
# Déplacement state
terraform state mv aws_security_group.web aws_security_group.api
# Vérification
terraform planQuand utiliser state mv ?
| Cas | But |
|---|---|
| Renommage Terraform | Changer l’adresse sans recréer la ressource. |
| Refactor module | Déplacer une ressource vers un module. |
| Correction d’adresse | Aligner state avec le nouveau design. |
Quand utiliser state rm ?
| Cas | Danger |
|---|---|
| Ressource ne doit plus être gérée par Terraform | Terraform l’oublie mais ne la détruit pas. |
| Migration vers autre state | Risque de double gestion si mal fait. |
| Correction import raté | Risque de perdre le mapping. |
state mv ou state rm, faire un state pull, relire l’adresse exacte et prévoir un plan de retour.Process sécurisé state operation
Avant opération state
│
├── sauvegarder state
├── vérifier backend/env
├── écrire commande exacte
├── faire relire
└── bloquer apply concurrent
│
▼
Exécuter opération
│
▼
terraform plan
│
▼
Vérifier zéro destroy inattendu
│
▼
Commit / documentationImport & drift en production
En production, l’import et la correction de drift doivent être traités comme des changements sensibles. Même si l’import ne modifie pas la ressource cloud, il modifie le state et peut influencer les futurs plans.
Règles production
| Règle | Pourquoi |
|---|---|
| Importer par petits lots | Limiter le risque et faciliter la revue. |
| Lire le plan après chaque import | Détecter destroy/replace/diff inattendu. |
| Ne pas importer DB à la légère | Risque data et lifecycle critique. |
| Protéger le state | State modifié = impact futur. |
| Documenter chaque mapping | Adresse Terraform ↔ ID provider. |
| Éviter apply concurrent | Risque lock, drift ou plan obsolète. |
Change request import prod
Title: Import existing production API security group
Scope:
- Resource: aws_security_group.api
- Provider ID: sg-0abc123456789def0
- Environment: production
- State: prod/network/terraform.tfstate
Risk:
- Bad code alignment could create unexpected diff.
- Future plans may modify existing SG.
Validation:
- terraform state show
- terraform plan
- no unexpected destroy or replace
- rules match current production
Rollback:
- state backup available
- terraform state rm if import mapping is wrongProduction import workflow
Inventaire validé
│
▼
Bloc resource minimal
│
▼
Import en staging si possible
│
▼
Review MR
│
├── adresse Terraform
├── ID provider
├── backend state
├── lifecycle
└── plan attendu
│
▼
Import production
│
▼
terraform plan
│
├── zéro destroy
├── zéro replace inattendu
└── diff expliqué
│
▼
Commit documentationRessources à traiter avec prudence
| Ressource | Risque | Garde-fou |
|---|---|---|
| Database | Perte ou remplacement accidentel. | prevent_destroy, backup, review senior. |
| Bucket data | Suppression ou policy dangereuse. | Versioning, lifecycle prudent, audit policy. |
| IAM role | Blocage app ou escalade privilèges. | Review sécurité. |
| Security group | Couper flux ou ouvrir trop large. | Comparer règles actuelles. |
| DNS | Trafic envoyé au mauvais endroit. | TTL, dig, validation multi-réseau. |
terraform apply peut devenir dangereux si le code n’est pas parfaitement aligné.Audit : comprendre qui a changé quoi
Le drift est souvent la conséquence d’un changement manuel. Pour le traiter sérieusement, il faut identifier qui a modifié quoi, quand, pourquoi, et si cette modification doit être codifiée ou annulée.
Sources d’audit
| Source | Ce qu’elle révèle |
|---|---|
| Cloud audit logs | Actions console/API, utilisateur, rôle, heure. |
| Git history | Changements Terraform, MR, commit, reviewer. |
| GitLab pipeline | Job exécuté, variables, artifact plan, statut. |
| Terraform state versions | Évolution du state distant. |
| Tickets / change requests | Justification métier ou opérationnelle. |
| Incident timeline | Hotfixs et actions d’urgence. |
Questions d’audit drift
- Quelle ressource a changé ?
- Le code Terraform a-t-il changé ?
- Le state a-t-il changé ?
- Le cloud réel a-t-il changé ?
- Qui a fait l'action ?
- Était-ce un hotfix ?
- Y a-t-il un ticket ou incident associé ?
- Faut-il garder le changement ?
- Faut-il le reporter dans Terraform ?
- Faut-il renforcer un garde-fou ?Décision après audit
Drift identifié
│
▼
Audit
├── action humaine ?
├── action pipeline ?
├── provider externe ?
├── autoscaling normal ?
└── incident hotfix ?
│
▼
Décision
├── codifier dans Terraform
├── restaurer état souhaité
├── ignorer volontairement
├── déplacer ownership
└── créer garde-fou
│
▼
MR + documentationExemples de décisions
| Cas | Décision |
|---|---|
| Security group ouvert en urgence | Refermer ou codifier règle minimale. |
| Desired capacity modifiée par autoscaling | Accepter et éventuellement ignore_changes. |
| Tag ajouté par FinOps | Ajouter tag dans locals communs. |
| DB modifiée manuellement | Analyser risque, codifier prudemment, backup. |
Runbook : importer une ressource existante
Procédure import contrôlé
1. Identifier la ressource existante et son ID provider.
2. Confirmer environnement, compte cloud et state cible.
3. Sauvegarder le state si production.
4. Écrire un bloc resource minimal.
5. Ajouter lifecycle si ressource critique.
6. Lancer terraform import ou utiliser un bloc import.
7. Vérifier terraform state list.
8. Inspecter terraform state show.
9. Lancer terraform plan.
10. Ajuster le code jusqu'à diff maîtrisé.
11. Vérifier absence de destroy/replace inattendu.
12. Documenter mapping resource address ↔ provider ID.
13. Faire relire en MR.
14. Importer la ressource suivante seulement après validation.Runbook : traiter un drift
1. Lancer terraform plan -refresh-only.
2. Identifier les ressources en drift.
3. Vérifier changements récents : Git, pipeline, audit cloud.
4. Classer le drift : légitime, accidentel, provider, autoscaling.
5. Décider : intégrer dans code ou restaurer état Terraform.
6. Créer une MR si changement durable.
7. Relire plan standard.
8. Appliquer uniquement après validation.
9. Documenter cause et action.
10. Ajouter garde-fou si nécessaire.Commandes essentielles
terraform state list
terraform state show RESOURCE
terraform import RESOURCE PROVIDER_ID
terraform plan
terraform plan -refresh-only
terraform apply -refresh-only
terraform state mv OLD NEW
terraform state rm RESOURCE
terraform state pull > state-backup.jsonAnti-patterns Import & drift
| Anti-pattern | Pourquoi c’est dangereux | Alternative professionnelle |
|---|---|---|
| Importer sans inventaire | On ne comprend pas dépendances ni criticité. | Cartographie et ordre d’import. |
| Importer sans code aligné | Le plan suivant peut modifier l’existant. | Écrire resource block puis ajuster avec plan. |
| Importer trop de ressources d’un coup | Plan illisible et risques non détectés. | Importer par petits lots. |
| Ignorer le drift | Terraform devient imprévisible. | Analyse régulière et décision documentée. |
| Écraser le drift automatiquement | Peut annuler un hotfix de production. | Comprendre avant apply. |
state rm pour cacher une erreur | Terraform perd le contrôle réel. | Corriger mapping ou code. |
force-unlock réflexe | Peut casser un apply actif. | Identifier le détenteur du lock. |
| Pas de lifecycle sur ressources data | Risque destroy/replace accidentel. | prevent_destroy, backups, review senior. |
Mauvais modèle
Import improvisé
├── pas d'inventaire
├── pas de state backup
├── IDs copiés vite
├── 30 ressources importées
├── plan non relu
└── drift ignoréBon modèle
Import contrôlé
├── inventaire
├── mapping resource ↔ ID
├── state backup
├── import par petits lots
├── plan relu
├── code aligné
├── lifecycle critique
└── documentationChecklist Import & drift
Checklist avant import
| Point | Validation attendue |
|---|---|
| Ressource identifiée | Type, nom, ID provider, région, compte. |
| Environnement confirmé | Dev, staging ou production sans ambiguïté. |
| State cible confirmé | Backend et key corrects. |
| Dépendances comprises | Réseau, IAM, DNS, DB, app. |
| Code resource prêt | Bloc minimal écrit et relu. |
| Backup state | Obligatoire en production. |
| Lifecycle critique | Ajouté si DB, bucket, volume, KMS. |
| Fenêtre adaptée | Si ressource critique ou production sensible. |
Checklist après import
terraform state list | Ressource visible dans le state. |
terraform state show | Attributs réels inspectés. |
terraform plan | Diff compris et maîtrisé. |
| Destroy/replace | Absents ou explicitement justifiés. |
| Documentation | Mapping ressource ↔ ID conservé. |
Checklist drift
| Question | Pourquoi |
|---|---|
| Quel attribut a changé ? | Comprendre la nature du drift. |
| Qui a changé la ressource ? | Audit et responsabilité opérationnelle. |
| Était-ce un hotfix ? | Ne pas annuler une correction d’urgence. |
| Le changement est-il souhaité ? | Décider codification ou restauration. |
| Le code doit-il être modifié ? | Aligner état souhaité. |
| Un garde-fou manque-t-il ? | Éviter récidive. |
| Le plan est-il sûr ? | Éviter destroy/replace involontaire. |
Mini-cheat-sheet
# Import classique
terraform import RESOURCE_ADDRESS PROVIDER_ID
# Inspecter
terraform state list
terraform state show RESOURCE_ADDRESS
# Détecter drift
terraform plan -refresh-only
# Plan standard
terraform plan -out=tfplan
terraform show -no-color tfplan
# State operations sensibles
terraform state pull > state-backup.json
terraform state mv OLD_ADDRESS NEW_ADDRESS
terraform state rm RESOURCE_ADDRESS
# Règle production
# Importer petit, planifier souvent, documenter toujours.Templates GitLab CI : industrialiser les pipelines
Les templates GitLab CI permettent de factoriser les jobs répétitifs : installation, lint, tests, scan sécurité, Terraform plan, Terraform apply, build d’image, publication d’artifacts, smoke tests et déploiements.
Sans templates, chaque projet finit avec son propre .gitlab-ci.yml, ses variantes, ses bugs, ses secrets mal déclarés et ses différences de comportement. Avec des templates bien conçus, les équipes gagnent en cohérence, sécurité, lisibilité et maintenabilité.
Ce que l’on factorise
| Zone | Exemples | Bénéfice |
|---|---|---|
| Lint / format | Terraform fmt, YAML lint, shellcheck. | Qualité homogène. |
| Validation | Terraform validate, tests unitaires. | Éviter erreurs basiques. |
| Sécurité | Checkov, Trivy, tfsec, secret scan. | Garde-fous communs. |
| Terraform | init, plan, show, artifacts, apply. | Workflow infra standardisé. |
| Déploiement | staging, production, rollback, post-checks. | Moins d’improvisation. |
| Artifacts | plan.txt, plan.json, rapports sécurité. | Review et audit facilités. |
Architecture type
Projet applicatif / infra
│
└── .gitlab-ci.yml
│
├── include:
│ ├── templates/terraform.yml
│ ├── templates/security.yml
│ ├── templates/docker.yml
│ └── templates/deploy.yml
│
├── variables projet
├── jobs spécifiques
└── extends templates communs
│
▼
Bibliothèque CI centrale
├── jobs standards
├── règles communes
├── images validées
├── artifacts standards
└── politiques sécuritéPrincipe clé
| Mauvais modèle | Bon modèle |
|---|---|
| Copier-coller les jobs entre projets. | Inclure un template versionné. |
| Chaque projet réinvente Terraform plan. | Job .terraform_plan_template commun. |
| Secrets gérés différemment partout. | Conventions de variables standardisées. |
| Pas de versioning des templates. | Includes pinés sur tag ou ref stable. |
Le problème : duplication, divergence et pipelines fragiles
La duplication CI/CD devient vite une dette technique. Une correction de sécurité doit être copiée dans dix projets, un bug Terraform reste dans certains pipelines, et les nouveaux DevOps ne savent plus quel fichier est la référence.
Symptômes d’un mauvais modèle CI
| Symptôme | Cause | Impact |
|---|---|---|
| Jobs similaires mais différents | Copier-coller modifié localement. | Comportements imprévisibles. |
| Scan sécurité absent sur certains projets | Pas de template commun. | Faille non détectée. |
| Terraform plan non publié | Artifacts non standardisés. | Review difficile. |
| Variables incohérentes | Naming non défini. | Debug lent et erreurs prod. |
| Fix CI à répéter partout | Aucune bibliothèque partagée. | Maintenance coûteuse. |
| Pipeline incompréhensible | Includes et overrides non documentés. | Onboarding difficile. |
Évolution typique de la dette CI
Projet A crée un pipeline
│
▼
Projet B copie le pipeline
│
▼
Projet C adapte une version ancienne
│
▼
Un bug est corrigé dans A seulement
│
▼
Projet B garde une faille
│
▼
Projet C casse production
│
▼
Décision : créer templates communsCe qu’un template doit éviter
| Problème | Solution template |
|---|---|
Répétition du before_script | Job caché commun. |
| Versions d’images différentes | Image centralisée et versionnée. |
| Artifacts incohérents | Paths standards. |
| Rules copiées partout | Rules templates. |
| Secrets exposés par debug | Debug sécurisé commun. |
include : importer des templates GitLab CI
include permet d’importer des fichiers CI depuis le même repository, un autre projet GitLab, un template distant ou une bibliothèque centrale. C’est la base de la mutualisation.
Include local
include: - local: ".gitlab/ci/terraform.yml" - local: ".gitlab/ci/security.yml" - local: ".gitlab/ci/deploy.yml"
Include depuis un projet central
include:
- project: "platform/gitlab-ci-templates"
ref: "v1.4.2"
file:
- "/templates/terraform.yml"
- "/templates/security.yml"
- "/templates/deploy.yml"Include remote
include: - remote: "https://example.com/gitlab/templates/terraform.yml"
Quel type d’include choisir ?
| Type | Usage | Risque |
|---|---|---|
local | Templates dans le même repo. | Peu mutualisé entre projets. |
project | Bibliothèque CI interne. | Doit être versionné proprement. |
remote | Template externe ou généré. | Risque supply-chain. |
template | Templates GitLab prédéfinis. | Moins adapté aux conventions internes. |
Structure recommandée
platform/gitlab-ci-templates
│
├── templates/
│ ├── terraform.yml
│ ├── security.yml
│ ├── docker.yml
│ ├── deploy.yml
│ └── rules.yml
│
├── examples/
│ ├── terraform-project.yml
│ ├── app-project.yml
│ └── monorepo.yml
│
└── CHANGELOG.mdref: "v1.4.2", pas uniquement main.extends : réutiliser un job modèle
extends permet à un job concret d’hériter d’un job template. On définit un comportement commun dans un job caché, puis chaque projet surcharge uniquement ce qui varie : variables, rules, environment, paths ou script additionnel.
Template caché
.terraform_base:
image: hashicorp/terraform:1.6.6
variables:
TF_IN_AUTOMATION: "true"
TF_INPUT: "false"
before_script:
- cd "$TF_ROOT"
- terraform --version
- terraform init -input=falseJob concret qui étend
terraform_validate:
extends: .terraform_base
stage: validate
script:
- terraform fmt -check -recursive
- terraform validateJob plan spécifique
terraform_plan_staging:
extends: .terraform_base
stage: plan
variables:
TF_ROOT: "infra/live/staging/app"
script:
- terraform plan -out=tfplan
- terraform show -no-color tfplan > plan.txt
artifacts:
paths:
- "$TF_ROOT/tfplan"
- "$TF_ROOT/plan.txt"
expire_in: 3 daysCe que l’on met dans le template
| Élément | Dans template ? | Pourquoi |
|---|---|---|
| Image Docker standard | Oui | Cohérence des versions. |
| Variables génériques | Oui | Évite répétition. |
Chemin projet TF_ROOT | Souvent non | Spécifique à chaque repo. |
| Environment production | Dans job concret | Contrôle explicite. |
| Rules sensibles | Template ou job dédié | Selon standard interne. |
| Secrets | Non | Variables GitLab protégées/scopées. |
Héritage mental
.terraform_base
├── image
├── variables communes
├── before_script
└── init
terraform_plan_prod
├── extends .terraform_base
├── stage plan
├── TF_ROOT prod
├── plan + artifacts
└── rules main onlyextends imbriqués rend le pipeline difficile à comprendre. Préférer peu de niveaux et des noms explicites.Variables : personnaliser sans dupliquer
Les variables rendent les templates flexibles. Le projet définit ce qui change : chemin Terraform, environnement, image, nom de service, stratégie de déploiement, et le template garde la logique commune.
Variables communes recommandées
| Variable | Usage | Exemple |
|---|---|---|
TF_ROOT | Dossier Terraform. | infra/live/prod/app |
TF_VAR_environment | Variable Terraform. | production |
APP_NAME | Nom service. | api |
DEPLOY_ENV | Environnement cible. | staging |
DOCKER_IMAGE | Image applicative. | registry/app/api |
SCAN_SEVERITY | Niveau blocage sécurité. | HIGH,CRITICAL |
Variables au niveau projet
variables: APP_NAME: "api" TF_ROOT: "infra/live/staging/api" DEPLOY_ENV: "staging" TF_IN_AUTOMATION: "true" TF_INPUT: "false"
Override contrôlé par job
terraform_plan_prod:
extends: .terraform_plan
variables:
TF_ROOT: "infra/live/prod/api"
DEPLOY_ENV: "production"
environment:
name: production
rules:
- if: '$CI_COMMIT_BRANCH == "main"'Variables sensibles
| Type | Où les mettre ? | Protection |
|---|---|---|
| Cloud credentials | GitLab variables ou OIDC. | Masked, protected, scoped. |
| DB password | Vault / secret manager. | Jamais dans YAML. |
| API token | Variables protégées. | Rotation régulière. |
| SSH key | File variable ou secret manager. | Scope environnement. |
Debug sûr
echo "APP_NAME=$APP_NAME" echo "DEPLOY_ENV=$DEPLOY_ENV" echo "TF_ROOT=$TF_ROOT" if [ -z "$AWS_ACCESS_KEY_ID" ]; then echo "AWS_ACCESS_KEY_ID is missing" else echo "AWS_ACCESS_KEY_ID is present" fi
Template Terraform complet : validate, plan, apply
Terraform est l’un des meilleurs candidats à la factorisation : les commandes sont répétitives, les artifacts doivent être standards, et les garde-fous production doivent être cohérents partout.
Template Terraform central
.terraform_base:
image: hashicorp/terraform:1.6.6
variables:
TF_INPUT: "false"
TF_IN_AUTOMATION: "true"
before_script:
- echo "TF_ROOT=$TF_ROOT"
- cd "$TF_ROOT"
- terraform --version
- terraform init -input=false
.terraform_validate:
extends: .terraform_base
stage: validate
script:
- terraform fmt -check -recursive
- terraform validate
.terraform_plan:
extends: .terraform_base
stage: plan
script:
- terraform plan -input=false -out=tfplan
- terraform show -no-color tfplan > plan.txt
- terraform show -json tfplan > plan.json
artifacts:
paths:
- "$TF_ROOT/tfplan"
- "$TF_ROOT/plan.txt"
- "$TF_ROOT/plan.json"
expire_in: 3 days
.terraform_apply:
extends: .terraform_base
stage: apply
script:
- terraform apply -input=false tfplan
when: manual
allow_failure: falseUtilisation dans un projet
include:
- project: "platform/gitlab-ci-templates"
ref: "v1.4.2"
file:
- "/templates/terraform.yml"
stages:
- validate
- plan
- apply
variables:
TF_ROOT: "infra/live/staging/api"
terraform_validate:
extends: .terraform_validate
terraform_plan:
extends: .terraform_plan
terraform_apply:
extends: .terraform_apply
environment:
name: staging
dependencies:
- terraform_planProduction protégée
terraform_apply_prod:
extends: .terraform_apply
variables:
TF_ROOT: "infra/live/prod/api"
environment:
name: production
dependencies:
- terraform_plan_prod
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
tags:
- protected
- terraform
- prodplan.txt pour review humaine et plan.json pour contrôles automatiques.Sécurité des templates CI/CD
Un template CI/CD est puissant : s’il est compromis ou mal conçu, tous les projets qui l’incluent peuvent hériter du problème. Il doit donc être versionné, relu, limité et testé.
Risques principaux
| Risque | Exemple | Prévention |
|---|---|---|
| Supply-chain CI | Template central modifié malicieusement. | MR review, protected branch, tags. |
| Secrets exposés | env ou set -x. | Debug sécurisé. |
| Apply prod non protégé | Job manuel accessible trop largement. | Protected environment + runner. |
Include sur main | Changement template impacte tout sans contrôle. | Pin sur tag stable. |
| Remote include non maîtrisé | Fichier externe change sans validation. | Éviter ou contrôler strictement. |
Template debug sécurisé
.safe_debug_context:
script:
- echo "Job=$CI_JOB_NAME"
- echo "Branch=$CI_COMMIT_BRANCH"
- echo "Source=$CI_PIPELINE_SOURCE"
- echo "Environment=${CI_ENVIRONMENT_NAME:-not-set}"
- echo "TF_ROOT=${TF_ROOT:-not-set}"
- pwd
- ls -laContrôles de sécurité à standardiser
| Contrôle | Job template |
|---|---|
| Secrets scan | .secret_scan |
| IaC scan | .checkov, .trivy_config |
| Container scan | .trivy_image |
| Terraform fmt/validate | .terraform_validate |
| Plan artifact | .terraform_plan |
| Protected apply | .terraform_apply + environment. |
Règles de protection
Template repository
├── protected main
├── MR obligatoire
├── approvals DevOps/Security
├── tags de release
├── changelog
└── tests d’exemples
Project repository
├── include ref tag stable
├── variables protected
├── environments protected
└── runner protected for prodenv, printenv ou set -x dans un template partagé.Versioning des templates : stabilité et évolution contrôlée
Un template central doit évoluer comme un produit interne. Les projets doivent pouvoir choisir quand passer de v1.4.2 à v1.5.0, lire le changelog, tester la migration et éviter les ruptures surprises.
Bon include versionné
include:
- project: "platform/gitlab-ci-templates"
ref: "v1.5.0"
file:
- "/templates/terraform.yml"
- "/templates/security.yml"Mauvais include non maîtrisé
include:
- project: "platform/gitlab-ci-templates"
ref: "main"
file: "/templates/terraform.yml"main peut modifier tous les pipelines consommateurs dès qu’un template change.Stratégie de versions
| Type de changement | Version | Exemple |
|---|---|---|
| Correction bug sans rupture | Patch | v1.4.2 → v1.4.3 |
| Nouveau job optionnel | Minor | v1.4.2 → v1.5.0 |
| Breaking change | Major | v1.5.0 → v2.0.0 |
Process release template
Modifier template
│
▼
Tester exemples
│
▼
MR review DevOps/Security
│
▼
Merge main
│
▼
Créer tag vX.Y.Z
│
▼
Publier changelog
│
▼
Projets consommateurs migrent volontairementChangelog minimal
## v1.5.0 Added: - New .terraform_plan_json job - New .trivy_config template Changed: - Terraform image updated to 1.6.6 Fixed: - Artifact path handling for nested TF_ROOT Migration: - No breaking change
examples/ qui prouve que les templates fonctionnent dans des cas réalistes.Anti-patterns Templates GitLab CI
| Anti-pattern | Pourquoi c’est dangereux | Correction professionnelle |
|---|---|---|
| Copier-coller les pipelines | Les corrections ne se propagent pas. | Templates centralisés. |
Include sur main | Ruptures surprises sur projets consommateurs. | Pin sur tag versionné. |
| Templates trop magiques | Les DevOps ne comprennent plus le pipeline. | Noms explicites, documentation, exemples. |
| Trop d’extends imbriqués | Debug très difficile. | Limiter les niveaux d’héritage. |
| Variables non documentées | Erreur de configuration projet. | Table des variables obligatoires. |
| Secrets dans YAML | Fuite durable dans Git. | Variables protégées, Vault, OIDC. |
| Remote include non contrôlé | Risque supply-chain. | Templates internes versionnés. |
| Breaking changes silencieux | Les pipelines cassent sans explication. | SemVer, changelog, migration guide. |
Mauvais modèle
CI non industrialisée
├── copier-coller partout
├── variables différentes
├── pas de versioning
├── secrets mal protégés
├── jobs sécurité absents
└── debug projet par projetBon modèle
CI industrialisée
├── templates centraux
├── includes versionnés
├── jobs cachés simples
├── extends lisibles
├── variables documentées
├── sécurité standardisée
└── exemples testésChecklist Templates GitLab CI
Checklist design template
| Point | Validation attendue |
|---|---|
| Templates centralisés | Repo dédié ou dossier .gitlab/ci. |
| Jobs cachés | Templates préfixés par un point. |
| Noms explicites | .terraform_plan, .security_checkov. |
| Variables documentées | Obligatoires, optionnelles, sensibles. |
| Artifacts standards | Plans, rapports, logs utiles. |
| Exemples fournis | Projet Terraform, app, monorepo. |
| Héritage limité | Pas de chaîne obscure d’extends. |
| Sécurité intégrée | Scans, no secrets, protected apply. |
Checklist projet consommateur
| Include piné | ref: vX.Y.Z, pas main. |
| Variables définies | TF_ROOT, env, app name. |
| Secrets protégés | Masked, protected, scoped. |
| Production protégée | Environment, runner, apply manuel. |
| Pipeline lisible | Les jobs finaux sont compréhensibles. |
Checklist release template
| Question | Réponse attendue |
|---|---|
| Le changement est-il breaking ? | Oui/non documenté. |
| Les exemples passent-ils ? | Pipeline test OK. |
| La sécurité a-t-elle relu ? | Oui si secrets/IAM/prod concernés. |
| Le changelog est-il à jour ? | Ajout, changement, fix, migration. |
| Un tag est-il créé ? | vX.Y.Z. |
| Les projets critiques migrent-ils progressivement ? | Pas de bascule massive non testée. |
Mini-cheat-sheet
# Include central
include:
- project: "platform/gitlab-ci-templates"
ref: "v1.5.0"
file:
- "/templates/terraform.yml"
# Hidden job
.terraform_base:
image: hashicorp/terraform:1.6.6
before_script:
- cd "$TF_ROOT"
- terraform init
# Extends
terraform_plan:
extends: .terraform_plan
variables:
TF_ROOT: "infra/live/staging/api"
# Must have
- include versionné
- jobs cachés simples
- variables documentées
- artifacts standards
- no secrets in YAML
- protected apply production
- changelog templateTester Terraform : éviter que le premier vrai test soit la production
Tester Terraform ne signifie pas seulement lancer terraform validate. Il faut vérifier que le code est formaté, valide, sécurisé, que le plan est cohérent, que les modules créent bien les ressources attendues, et que les outputs permettent aux autres stacks de consommer proprement l’infrastructure.
Les tests Terraform doivent être proportionnés au risque. Un module réseau, IAM, base de données ou sécurité mérite beaucoup plus de contrôles qu’un simple log group ou une ressource non critique.
Ce que l’on teste vraiment
| Zone | Question | Signal attendu |
|---|---|---|
| Syntaxe | Le code Terraform est-il valide ? | terraform validate OK. |
| Format | Le code est-il standardisé ? | terraform fmt -check OK. |
| Plan | Le changement est-il celui attendu ? | Pas de destroy/replace non prévu. |
| Module | Le module crée-t-il les bonnes ressources ? | Resources, tags, outputs et règles corrects. |
| Sécurité | Le code ouvre-t-il un risque ? | Scan IaC sans blocage critique. |
| Runtime | L’infra fonctionne-t-elle vraiment après apply ? | Healthcheck, connectivité, logs et métriques OK. |
Pipeline mental des tests Terraform
Code Terraform
│
▼
Tests statiques
├── fmt
├── validate
├── tflint
└── checkov / trivy / tfsec
│
▼
Tests de plan
├── plan lisible
├── no destroy inattendu
├── review humaine
└── policy-as-code éventuelle
│
▼
Sandbox apply
├── création réelle
├── vérification outputs
├── tests connectivité
└── destroy contrôlé
│
▼
Promotion staging / prod
├── approval
├── apply contrôlé
└── post-checksPourquoi tester par niveaux ?
| Niveau | Coût | Valeur |
|---|---|---|
| fmt / validate | Très faible | Détecte erreurs basiques immédiatement. |
| Scan sécurité | Faible | Détecte ports ouverts, IAM trop larges, secrets. |
| Plan review | Moyen | Détecte effets réels avant apply. |
| Sandbox apply | Moyen à élevé | Valide comportement réel. |
| Terratest | Élevé | Automatise tests d’intégration sérieux. |
Niveaux de tests Terraform
Un bon dispositif de tests Terraform combine plusieurs couches : tests statiques rapides, revue du plan, sandbox réelle, tests de modules et vérifications post-apply.
Pyramide de tests IaC
Tests post-apply / runtime
├── healthcheck
├── connectivité
├── DNS/TLS
└── métriques
Tests d'intégration
├── sandbox apply
├── Terratest
├── outputs
└── destroy
Tests de plan
├── no destroy
├── no public exposure
├── diff attendu
└── review humaine
Tests statiques
├── terraform fmt
├── terraform validate
├── tflint
├── checkov
└── trivy configTableau des niveaux
| Niveau | Outils | Quand | Bloquant ? |
|---|---|---|---|
| Format | terraform fmt | À chaque commit/MR. | Oui |
| Validation | terraform validate | À chaque MR. | Oui |
| Lint | TFLint | À chaque MR. | Selon maturité |
| Sécurité | Checkov, tfsec, Trivy | MR et main. | Oui sur critique |
| Plan | terraform plan | MR, main, staging. | Oui |
| Intégration | Sandbox, Terratest | Modules critiques. | Oui selon criticité |
| Runtime | curl, cloud CLI, tests métier | Après apply. | Oui pour prod |
Stratégie par criticité
| Faible | fmt, validate, plan. |
| Moyenne | fmt, validate, scan, plan, review. |
| Élevée | + sandbox apply et post-checks. |
| Critique | + Terratest, policy-as-code, approval senior. |
Validation locale : première barrière avant MR
Les validations locales doivent être rapides, répétables et faciles à lancer. Elles évitent de pousser du code Terraform cassé dans la CI/CD.
Commandes locales essentielles
# Initialisation
terraform init
# Formatage
terraform fmt -recursive
terraform fmt -check -recursive
# Validation syntaxe / providers / modules
terraform validate
# Voir providers utilisés
terraform providers
# Plan local avec variables
terraform plan -var-file="dev.tfvars"
# Plan sauvegardé
terraform plan -var-file="dev.tfvars" -out=tfplan
terraform show -no-color tfplanfmt, validate et plan.Script local de validation
#!/usr/bin/env bash
set -euo pipefail
echo "[1/4] terraform fmt"
terraform fmt -check -recursive
echo "[2/4] terraform init"
terraform init
echo "[3/4] terraform validate"
terraform validate
echo "[4/4] terraform plan"
terraform plan -var-file="dev.tfvars" -out=tfplan
echo "Validation completed."Erreurs détectées localement
| Erreur | Détection | Correction |
|---|---|---|
| HCL mal formaté | terraform fmt -check | terraform fmt -recursive |
| Variable manquante | terraform plan | Ajouter default ou tfvars. |
| Provider absent | terraform init | Corriger required providers. |
| Type invalide | terraform validate | Corriger variable/object/map. |
| Backend inaccessible | terraform init | Vérifier credentials et backend. |
Tests de plan : vérifier l’intention avant l’action
Le plan est le meilleur test avant apply. Il montre les créations, modifications, remplacements et suppressions. En production, il doit être relu comme un document de changement.
Commandes plan
# Plan standard
terraform plan -var-file="prod.tfvars"
# Plan sauvegardé
terraform plan -var-file="prod.tfvars" -out=tfplan
# Plan lisible
terraform show -no-color tfplan > plan.txt
# Plan JSON pour analyse automatisée
terraform show -json tfplan > plan.jsonCe que l’on cherche dans un plan
| Signal | Interprétation | Réaction |
|---|---|---|
+ | Création. | Vérifier coût, tags, sécurité. |
~ | Modification. | Comprendre impact runtime. |
-/+ | Remplacement. | Analyse obligatoire. |
- | Suppression. | Stop si non attendu. |
destroy ou replace en production doit être explicitement justifié.Tests automatisables sur plan JSON
| Contrôle | But |
|---|---|
| No destroy | Bloquer suppressions non prévues. |
| No public DB | Interdire base de données publique. |
| No open SSH | Interdire 0.0.0.0/0 sur port 22. |
| Required tags | Vérifier tags Owner, Environment, Project. |
| Allowed instance types | Contrôler coûts et standards. |
| Backup enabled | Vérifier ressources data critiques. |
Exemple de commentaire MR
Terraform plan summary:
- Environment: staging
- Resources to add: 2
- Resources to change: 1
- Resources to destroy: 0
- Replace: 0
- Security impact: no public ingress
- Data impact: none
- Rollback: revert MR and re-apply previous planDiagramme review du plan
Plan généré
│
▼
Résumé humain
│
├── add
├── change
├── replace
└── destroy
│
▼
Contrôles risques
├── réseau
├── IAM
├── DB
├── DNS
└── coûts
│
▼
Approval ou correctionSandbox : tester sans mettre la production en danger
Une sandbox est un environnement isolé permettant d’appliquer réellement Terraform, de vérifier que les ressources se créent, que les outputs sont corrects et que la destruction contrôlée fonctionne.
Caractéristiques d’une bonne sandbox
| Critère | Attendu |
|---|---|
| Isolation | Compte/projet/région ou préfixe dédié. |
| Coût limité | Quotas, tailles petites, auto-destroy. |
| Données fictives | Aucune donnée production réelle. |
| State séparé | Backend sandbox distinct. |
| Credentials limités | Impossible d’agir sur production. |
| TTL | Nettoyage automatique ou planifié. |
Workflow sandbox
terraform init
terraform plan -var-file="sandbox.tfvars" -out=tfplan
terraform apply tfplan
# Vérifications
terraform output
curl -fsS https://sandbox.example.com/health/
# Nettoyage
terraform destroy -var-file="sandbox.tfvars"Cycle apply / verify / destroy
Sandbox state
│
▼
terraform apply
│
├── ressources créées
├── outputs produits
└── tags appliqués
│
▼
Vérifications
├── cloud resource exists
├── security rules OK
├── DNS/TLS si concerné
├── healthcheck
└── logs clean
│
▼
terraform destroy
│
├── nettoyage réussi
└── aucun résidu coûteuxRisques sandbox
| Risque | Prévention |
|---|---|
| Oubli de ressources | TTL, tags, rapport coût. |
| Credentials trop larges | Rôle sandbox isolé. |
| State confondu | Backend key explicite. |
| Coût élevé | Types petits, quotas, budgets. |
| Tests non représentatifs | Reproduire au moins les dépendances critiques. |
-test dans le nom ne suffit pas toujours.Tests de modules Terraform
Un module Terraform est une API d’infrastructure. Il faut tester son contrat : inputs, validations, outputs, naming, tags, sécurité par défaut et comportement sur plusieurs environnements.
Contrat à tester
| Élément | Test attendu |
|---|---|
| Inputs | Types corrects, validations utiles, defaults sûrs. |
| Outputs | Valeurs nécessaires exposées, pas de secrets inutiles. |
| Naming | Ressources nommées avec convention projet/env/composant. |
| Tags | Tags obligatoires présents partout. |
| Sécurité | Pas de port dangereux ouvert par défaut. |
| Lifecycle | Ressources critiques protégées si applicable. |
| Idempotence | Deuxième plan après apply ne doit pas montrer de diff inattendu. |
Structure de test module
modules/
network/
main.tf
variables.tf
outputs.tf
README.md
examples/
basic/
main.tf
terraform.tfvars
multi_az/
main.tf
terraform.tfvars
tests/
README.mdExemple d’example module
module "network" {
source = "../../"
project = "demo"
environment = "sandbox"
vpc_cidr = "10.50.0.0/16"
private_subnets = {
"a" = {
cidr_block = "10.50.1.0/24"
availability_zone = "eu-west-3a"
}
"b" = {
cidr_block = "10.50.2.0/24"
availability_zone = "eu-west-3b"
}
}
}Tests simples sans Terratest
cd modules/network/examples/basic
terraform init
terraform fmt -check -recursive
terraform validate
terraform plan -out=tfplan
terraform apply tfplan
terraform output
terraform plan
terraform destroyexamples/basic validable par CI.Terratest : tests d’intégration automatisés
Terratest permet d’écrire des tests en Go qui lancent Terraform, appliquent l’infrastructure, vérifient des outputs ou comportements réels, puis détruisent les ressources. C’est puissant, mais plus coûteux que les tests statiques.
Quand utiliser Terratest ?
| Cas | Pourquoi |
|---|---|
| Module réseau critique | Vérifier subnets, routes, outputs, connectivité. |
| Module load balancer | Tester endpoint, healthcheck, listener. |
| Module database | Vérifier backup, deletion protection, private access. |
| Module sécurité | Contrôler règles, ports, tags, IAM. |
| Module réutilisé par plusieurs équipes | Éviter régression lors des évolutions. |
Cycle Terratest
go test
│
▼
terraform init
│
▼
terraform apply
│
▼
Assertions
├── outputs
├── cloud resources
├── HTTP endpoint
├── tags
└── security rules
│
▼
terraform destroy
│
▼
test resultExemple Terratest simplifié
package test
import (
"testing"
"github.com/gruntwork-io/terratest/modules/terraform"
"github.com/stretchr/testify/assert"
)
func TestNetworkModule(t *testing.T) {
t.Parallel()
options := &terraform.Options{
TerraformDir: "../examples/basic",
Vars: map[string]interface{}{
"project": "demo",
"environment": "test",
},
}
defer terraform.Destroy(t, options)
terraform.InitAndApply(t, options)
vpcId := terraform.Output(t, options, "vpc_id")
assert.NotEmpty(t, vpcId)
}Précautions Terratest
| Risque | Prévention |
|---|---|
| Coût cloud | Sandbox dédiée, quotas, destroy systématique. |
| Tests lents | Limiter aux modules critiques. |
| Ressources résiduelles | Tags test, cleanup jobs, TTL. |
| Flaky tests | Timeouts raisonnables, retry contrôlé. |
| Credentials | Rôle dédié test, jamais prod. |
Tests sécurité IaC
Les tests sécurité IaC détectent les mauvaises pratiques avant l’apply : ports trop ouverts, stockage non chiffré, IAM trop permissif, logs désactivés, ressources publiques ou secrets potentiels.
Outils fréquents
| Outil | Usage |
|---|---|
| Checkov | Scan Terraform, cloud policies, Kubernetes, CI/CD. |
| tfsec | Scan sécurité Terraform simple et rapide. |
| Trivy config | Scan IaC, containers, dépendances. |
| TFLint | Lint Terraform et règles provider. |
| OPA / Conftest | Policy-as-code personnalisée. |
| Sentinel | Policy-as-code dans Terraform Cloud/Enterprise. |
Commandes scan
# Checkov
checkov -d .
# tfsec
tfsec .
# Trivy IaC
trivy config .
# TFLint
tflint --init
tflintContrôles sécurité à bloquer
| Risque | Exemple | Décision |
|---|---|---|
| SSH public | 0.0.0.0/0:22 | Bloquant en prod. |
| DB publique | Publicly accessible true. | Bloquant. |
| Bucket public | ACL ou policy ouverte. | Bloquant sauf exception validée. |
| IAM wildcard | Action: "*" | Review sécurité obligatoire. |
| Chiffrement absent | Storage non chiffré. | Bloquant selon données. |
| Logs désactivés | Audit ou access logs off. | À corriger. |
Politique d’exception
Exception security scan:
- Rule:
- Resource:
- Environment:
- Reason:
- Risk accepted by:
- Expiration date:
- Compensating control:
- Ticket:CI/CD : automatiser les tests Terraform
La CI/CD doit exécuter automatiquement les contrôles de base à chaque MR : formatage, validation, scan, plan, publication du plan, puis éventuellement tests sandbox pour les modules critiques.
Pipeline GitLab Terraform tests
stages:
- lint
- validate
- security
- plan
- integration
variables:
TF_IN_AUTOMATION: "true"
TF_INPUT: "false"
TF_ROOT: "infra/live/staging/app"
default:
image: hashicorp/terraform:1.6.6
before_script:
- cd "$TF_ROOT"
- terraform init
terraform_fmt:
stage: lint
script:
- terraform fmt -check -recursive
terraform_validate:
stage: validate
script:
- terraform validate
terraform_security:
stage: security
image: bridgecrew/checkov:latest
before_script: []
script:
- checkov -d infra
allow_failure: false
terraform_plan:
stage: plan
script:
- terraform plan -out=tfplan
- terraform show -no-color tfplan > plan.txt
artifacts:
paths:
- "$TF_ROOT/tfplan"
- "$TF_ROOT/plan.txt"
expire_in: 3 daysJob Terratest optionnel
terratest_network:
stage: integration
image: golang:1.22
before_script:
- apt-get update && apt-get install -y unzip
- cd modules/network/tests
script:
- go test -v -timeout 45m
rules:
- changes:
- modules/network/**/*
when: manualStratégie CI recommandée
| Pipeline | Tests |
|---|---|
| Merge request | fmt, validate, scan, plan. |
| Main | plan final, security scan, artifact. |
| Nightly | drift detection, scans complets. |
| Module release | examples + Terratest + documentation. |
| Production | plan, approval, apply manuel, post-checks. |
plan.txt comme artifact pour permettre une vraie revue humaine.Anti-patterns des tests Terraform
| Anti-pattern | Pourquoi c’est dangereux | Alternative professionnelle |
|---|---|---|
Se limiter à terraform validate | Ne détecte pas les erreurs de design ou sécurité. | Ajouter plan, scans, review et sandbox si critique. |
| Tester directement en production | Le premier vrai test peut casser le service. | Sandbox et staging. |
| Ne pas lire le plan | Destroy/replace peuvent passer inaperçus. | Plan artifact + review humaine. |
| Pas de tests de modules | Régressions sur modules partagés. | Examples validés + Terratest ciblé. |
| Terratest partout | Pipeline lent, coûteux et fragile. | Réserver aux modules critiques. |
| Sandbox sans destroy | Coût et ressources orphelines. | Destroy automatique, TTL, tags. |
| Scans sécurité en warning permanent | Les alertes sont ignorées. | Bloquer les risques critiques et gérer exceptions. |
| Variables différentes local/CI | Plan local non représentatif. | Standardiser tfvars, versions et provider lock. |
Mauvais modèle
Tests faibles
├── validate uniquement
├── pas de scan sécurité
├── pas de plan artifact
├── pas de sandbox
├── pas de tests modules
└── apply prod comme test finalBon modèle
Tests professionnels
├── fmt
├── validate
├── lint
├── security scan
├── plan artifact
├── review humaine
├── sandbox ciblée
├── Terratest modules critiques
└── post-checks productionChecklist Tests Terraform
Checklist avant MR
| Test | Commande / preuve |
|---|---|
| Format | terraform fmt -check -recursive |
| Init | terraform init |
| Validate | terraform validate |
| Plan | terraform plan -out=tfplan |
| Plan lisible | terraform show -no-color tfplan |
| Scan sécurité | Checkov, tfsec ou Trivy. |
| Destroy/replace | Absents ou justifiés. |
| Secrets | Aucun secret dans code, plan, outputs, artifacts. |
Checklist module
| Examples | Au moins examples/basic. |
| Inputs | Types, descriptions, validations. |
| Outputs | Utiles, non sensibles. |
| Tags | Tags obligatoires appliqués. |
| Security defaults | Pas d’ouverture dangereuse par défaut. |
| Lifecycle | Ressources critiques protégées. |
Checklist sandbox / intégration
| Point | Validation attendue |
|---|---|
| Compte sandbox | Isolé de production. |
| State sandbox | Backend distinct. |
| Credentials | Droits limités. |
| Apply | Ressources créées sans erreur. |
| Outputs | Valeurs cohérentes. |
| Post-check | Connectivité, healthcheck ou cloud checks OK. |
| Destroy | Nettoyage complet. |
| Coût | Aucune ressource résiduelle coûteuse. |
Mini-cheat-sheet
# Local
terraform fmt -check -recursive
terraform init
terraform validate
terraform plan -out=tfplan
terraform show -no-color tfplan
# Security
checkov -d .
tfsec .
trivy config .
tflint --init
tflint
# Sandbox
terraform apply tfplan
terraform output
curl -fsS https://sandbox.example.com/health/
terraform destroy
# Terratest
go test -v -timeout 45m
# Plan JSON
terraform show -json tfplan > plan.jsonFinOps : relier infrastructure, usage et responsabilité financière
Un changement Terraform peut créer des coûts invisibles : instance trop grosse, stockage oublié, logs trop verbeux, NAT gateway inutile, load balancer permanent, retention excessive, snapshots jamais nettoyés ou ressources sandbox non détruites.
Le rôle DevOps ne se limite pas à déployer. Il faut aussi comprendre le coût, expliquer les compromis, taguer correctement, détecter les dérives et rendre les dépenses visibles par environnement, service, équipe et projet.
Les questions FinOps à poser avant apply
| Question | Pourquoi | Signal attendu |
|---|---|---|
| Quelle ressource est créée ? | Chaque ressource a un modèle de coût. | Instance, DB, LB, NAT, volume, logs, bucket. |
| Est-ce permanent ou temporaire ? | Une sandbox oubliée coûte tous les mois. | TTL, auto-destroy ou owner clair. |
| Quelle taille est choisie ? | Le sizing impacte directement la facture. | Instance type, storage, IOPS, replicas. |
| Les tags sont-ils présents ? | Sans tags, impossible d’attribuer les coûts. | Project, Environment, Owner, CostCenter. |
| Y a-t-il un coût réseau ? | NAT, egress, inter-zone et LB peuvent coûter cher. | Trafic estimé et architecture validée. |
| Une alerte budget existe-t-elle ? | Détecter rapidement les dérives. | Budget, seuils, notification. |
Cycle FinOps appliqué à Terraform
Terraform change
│
▼
Plan review
├── ressources ajoutées
├── ressources modifiées
├── tailles / volumes
├── logs / retention
├── réseau / egress
└── tags
│
▼
Cost estimation
├── coût mensuel estimé
├── delta vs existant
├── risque de dérive
└── owner coût
│
▼
Apply contrôlé
│
▼
Suivi réel
├── budget alerts
├── dashboards coût
├── anomalie coût
└── optimisation continueFinOps en une phrase
| Sans FinOps | Avec FinOps |
|---|---|
| “Ça marche, donc c’est bon.” | “Ça marche, c’est dimensionné, tagué, surveillé et justifié.” |
| Coûts découverts en fin de mois. | Coûts anticipés avant apply. |
| Ressources sans owner. | Chaque ressource a projet, équipe et environnement. |
| Optimisation ponctuelle. | Optimisation continue intégrée au cycle DevOps. |
Cost drivers : ce qui fait réellement monter la facture
Les coûts cloud ne viennent pas seulement des machines. Le réseau, les logs, le stockage, les backups, les bases managées et les ressources oubliées peuvent représenter une part importante.
Principales sources de coût
| Famille | Exemples | Risque FinOps |
|---|---|---|
| Compute | VM, autoscaling, containers, nodes Kubernetes. | Surdimensionnement permanent. |
| Database | RDS, Cloud SQL, replicas, IOPS, stockage. | Coût élevé, difficile à réduire sans risque. |
| Network | NAT gateway, egress, inter-zone, load balancer. | Coûts invisibles liés au trafic. |
| Storage | Volumes, buckets, snapshots, backups. | Accumulation silencieuse. |
| Logs / Observabilité | Ingestion logs, retention, métriques custom. | Explosion si logs trop verbeux. |
| Environnements temporaires | Review apps, sandbox, tests Terratest. | Oubli de destruction. |
Exemples de pièges coûteux
- Une NAT gateway créée en dev alors qu’elle n’est pas nécessaire.
- Des logs debug envoyés en continu vers une plateforme payante.
- Une base de données staging dimensionnée comme la production.
- Des snapshots conservés indéfiniment sans policy de rétention.
- Des environnements de test créés par CI mais jamais détruits.
- Un load balancer par petite application au lieu d’une mutualisation réfléchie.
Tableau coût / risque / contrôle
| Ressource | Question à poser | Contrôle |
|---|---|---|
| Instance | La taille est-elle justifiée ? | CPU/RAM réels, autoscaling, rightsizing. |
| DB managée | Backup, replicas et IOPS sont-ils adaptés ? | Monitoring DB + politique prod/staging. |
| NAT | Le trafic sortant le justifie-t-il ? | Architecture réseau et volumes egress. |
| Logs | Le volume et la retention sont-ils maîtrisés ? | Niveaux log, sampling, retention. |
| Storage | Le cycle de vie supprime-t-il l’ancien ? | Lifecycle policy, archive, cleanup. |
| Sandbox | Existe-t-il une date d’expiration ? | TTL, auto-destroy, tag ExpireAt. |
Diagramme des coûts invisibles
Terraform apply
│
├── ressource principale visible
│ └── instance / DB / LB
│
└── coûts associés parfois oubliés
├── stockage attaché
├── snapshots
├── logs
├── trafic sortant
├── NAT
├── monitoring
├── backups
└── IP publiquesTags : base de l’attribution des coûts
Les tags permettent de savoir qui consomme quoi. Sans tags cohérents, impossible de répartir les coûts par équipe, service, environnement, produit ou client.
Tags obligatoires recommandés
| Tag | Exemple | Usage |
|---|---|---|
Project | ideo-platform | Regrouper les coûts par projet. |
Environment | dev, staging, prod | Comparer non-prod vs prod. |
Owner | platform-team | Responsabilité opérationnelle. |
CostCenter | engineering | Refacturation ou budget interne. |
ManagedBy | terraform | Distinguer IaC vs manuel. |
Criticality | low, high, critical | Prioriser optimisation et support. |
ExpireAt | 2026-05-31 | Nettoyage sandbox/review apps. |
Locals Terraform pour tags
locals {
common_tags = merge(
{
Project = var.project
Environment = var.environment
Owner = var.owner
CostCenter = var.cost_center
ManagedBy = "terraform"
},
var.extra_tags
)
}Application des tags
resource "aws_instance" "app" {
ami = var.ami_id
instance_type = var.instance_type
tags = merge(local.common_tags, {
Name = "${local.name_prefix}-app"
})
}Politique de tags
| Règle | Pourquoi |
|---|---|
| Tags obligatoires | Empêcher ressources orphelines financièrement. |
| Valeurs normalisées | Éviter prod, production, prd. |
| Owner réel | Quelqu’un doit répondre du coût. |
| CostCenter stable | Permet reporting et refacturation. |
| ExpireAt pour temporaire | Nettoyage automatique ou revue régulière. |
Contrôle CI possible
# Exemple principe : # Bloquer si une ressource taggable n'a pas les tags obligatoires : # - Project # - Environment # - Owner # - CostCenter # - ManagedBy
Revue du plan Terraform sous l’angle coût
La revue du plan ne doit pas seulement chercher les suppressions et les risques sécurité. Elle doit aussi identifier les ressources qui changent la facture.
Questions coût dans une review de plan
| Changement | Question FinOps |
|---|---|
| Nouvelle instance | Le type est-il adapté ? Peut-elle dormir hors horaires ? |
| Nouvelle DB | Backup, stockage, replicas et IOPS sont-ils justifiés ? |
| Nouveau load balancer | Peut-il être mutualisé ? Est-il permanent ? |
| Nouvelle NAT gateway | Le besoin réseau justifie-t-il ce coût fixe ? |
| Retention logs augmentée | Le volume d’ingestion est-il connu ? |
| Storage augmenté | Y a-t-il une lifecycle policy ? |
Résumé MR recommandé
Cost impact: - Environment: staging - New resources: 1 load balancer, 2 instances - Removed resources: none - Monthly cost impact: estimated +120 EUR/month - Main cost drivers: load balancer + compute - Tags: Project, Environment, Owner, CostCenter OK - Budget alert: existing staging budget - Cleanup: not temporary
Diagramme review coût
terraform plan
│
▼
Identifier ressources coûteuses
├── compute
├── DB
├── NAT
├── LB
├── logs
├── storage
└── egress
│
▼
Évaluer
├── coût mensuel
├── coût variable
├── coût fixe
├── owner
└── durée de vie
│
▼
Décision
├── OK
├── réduire sizing
├── mutualiser
├── ajouter TTL
└── refuser / revoir designDiff Terraform à surveiller
| Diff | Risque coût |
|---|---|
instance_type augmente | Coût compute permanent plus élevé. |
allocated_storage augmente | Coût stockage récurrent. |
backup_retention_period augmente | Coût backup/snapshot plus élevé. |
log_retention augmente | Coût observabilité. |
nat_gateway créé | Coût fixe + trafic. |
multi_az activé | Résilience accrue mais coût supérieur. |
Outils FinOps et estimation de coût
Plusieurs outils permettent d’estimer ou suivre les coûts liés à Terraform. Le bon choix dépend de la maturité équipe, du cloud utilisé et du niveau d’automatisation attendu.
Outils liés à Terraform
| Outil | Usage | Moment |
|---|---|---|
| Infracost | Estimation du coût depuis le plan Terraform. | MR / CI. |
| Terraform plan JSON | Analyse automatisée du diff. | MR / audit. |
| Policy-as-code | Bloquer ressources trop coûteuses ou non taguées. | CI/CD. |
| Cloud pricing calculator | Estimation manuelle d’architecture. | Design. |
| Cloud cost explorer | Suivi des dépenses réelles. | Exploitation. |
Exemple Infracost en CI
# Exemple conceptuel terraform plan -out=tfplan terraform show -json tfplan > plan.json infracost breakdown \ --path plan.json \ --format table infracost diff \ --path plan.json \ --format json \ --out-file infracost.json
Outils cloud natifs
| Cloud | Outils typiques |
|---|---|
| AWS | Cost Explorer, Budgets, Cost Anomaly Detection, CUR. |
| Azure | Cost Management, Budgets, Advisor. |
| GCP | Billing Reports, Budgets, Recommender, BigQuery export. |
| Kubernetes | Kubecost, OpenCost, metrics par namespace. |
| Multi-cloud | FinOps dashboards, BI, exports facturation. |
Architecture FinOps
Terraform plan
│
├── Infracost estimate
├── policy-as-code
└── MR comment
│
▼
Cloud billing
├── budgets
├── anomaly detection
├── cost explorer
└── billing export
│
▼
FinOps dashboard
├── coût par projet
├── coût par environnement
├── coût par équipe
└── dérives mensuellesBudgets, alertes et détection d’anomalies
Les budgets et alertes coût permettent de détecter une dérive avant la fin du mois. Ils doivent être définis par environnement, projet ou équipe, avec des seuils adaptés.
Seuils de budget recommandés
| Seuil | Signification | Action |
|---|---|---|
| 50% | Consommation normale à surveiller. | Notification faible. |
| 75% | Risque de dépassement. | Review projet/environnement. |
| 90% | Dépassement probable. | Action corrective ou validation owner. |
| 100% | Budget atteint. | Escalade owner / manager / FinOps. |
| Anomalie soudaine | Hausse anormale vs baseline. | Investigation immédiate. |
Exemple de politique budget
Budget policy: - Project: ideo-platform - Environment: staging - Monthly budget: 300 EUR - Warning: 75% - Critical: 100% - Owner: platform-team - Notification: Slack #finops-alerts - Review frequency: weekly - Action: identify top cost drivers and cleanup unused resources
Détection d’anomalie coût
Facture quotidienne
│
▼
Comparaison baseline
│
├── coût normal
├── hausse progressive
└── pic brutal
│
▼
Analyse
├── nouvelle ressource Terraform
├── trafic réseau
├── logs volumineux
├── DB storage
├── sandbox oubliée
└── incident applicatif
│
▼
Action
├── cleanup
├── resize
├── retention
├── rollback
└── validation ownerActions après alerte budget
| Observation | Action |
|---|---|
| Sandbox coûteuse | Destroy, ajouter TTL, automatiser cleanup. |
| Logs en hausse | Réduire debug, ajuster retention, filtrer bruit. |
| Compute surdimensionné | Rightsizing, autoscaling, horaires d’arrêt. |
| Storage ancien | Lifecycle policy, archivage, suppression validée. |
| Trafic sortant élevé | Analyser architecture réseau et cache. |
Design Terraform orienté coûts
Terraform peut intégrer des garde-fous FinOps : variables validées, tailles approuvées, tags obligatoires, rétention contrôlée, ressources temporaires avec expiration et protection contre certains choix coûteux.
Variables contrôlées
variable "instance_type" {
description = "Approved instance type."
type = string
validation {
condition = contains([
"t3.micro",
"t3.small",
"t3.medium"
], var.instance_type)
error_message = "Instance type is not approved."
}
}
variable "log_retention_days" {
description = "Log retention in days."
type = number
default = 14
validation {
condition = var.log_retention_days <= 30
error_message = "Log retention must be lower than or equal to 30 days."
}
}Defaults selon environnement
locals {
is_prod = var.environment == "prod"
default_instance_type = local.is_prod ? "t3.medium" : "t3.micro"
backup_retention_days = local.is_prod ? 14 : 3
log_retention_days = local.is_prod ? 30 : 7
}Tags + TTL pour ressources temporaires
locals {
common_tags = merge(
{
Project = var.project
Environment = var.environment
Owner = var.owner
CostCenter = var.cost_center
ManagedBy = "terraform"
},
var.temporary ? {
Temporary = "true"
ExpireAt = var.expire_at
} : {}
)
}Patterns FinOps Terraform
| Pattern | But |
|---|---|
| Approved sizes | Limiter instances non standards. |
| Environment defaults | Éviter staging/dev trop gros. |
| Mandatory tags | Attribuer les coûts. |
| TTL temporary | Nettoyer les ressources de test. |
| Retention by env | Limiter logs/backups non-prod. |
| Lifecycle policies | Archiver ou supprimer stockage ancien. |
FinOps dans la CI/CD Terraform
La CI/CD peut détecter les changements coûteux avant merge : estimation Infracost, contrôle des tags, blocage des tailles non approuvées, scan de ressources publiques, et commentaire automatique dans la merge request.
Pipeline FinOps type
Merge Request
│
▼
terraform fmt / validate
│
▼
terraform plan -out=tfplan
│
▼
plan.json
│
├── scan sécurité
├── contrôle tags
├── estimation coût
└── policy-as-code
│
▼
MR comment
├── delta coût
├── ressources coûteuses
├── tags manquants
└── risques FinOps
│
▼
Approval ou correctionExemple job coût
terraform_cost_estimate:
stage: plan
image: infracost/infracost:ci-0.10
script:
- terraform show -json tfplan > plan.json
- infracost breakdown --path plan.json --format table
dependencies:
- terraform_plan
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'Contrôles CI FinOps
| Contrôle | Décision possible |
|---|---|
| Tags obligatoires manquants | Bloquer la MR. |
| Instance type non approuvé | Bloquer ou demander approval. |
| Coût mensuel supérieur seuil | Approval FinOps / lead. |
| NAT gateway en dev | Warning ou justification obligatoire. |
| Retention logs trop longue | Correction demandée. |
| Sandbox sans ExpireAt | Bloquer. |
Exemple commentaire MR
FinOps review: - Monthly cost delta: +85 EUR - Main driver: new staging load balancer - Required tags: OK - Temporary resource: no - Budget impact: within staging budget - Recommendation: accepted if LB cannot be shared
FinOps en production : optimiser sans fragiliser
En production, l’optimisation coût doit respecter la fiabilité. Réduire une instance, diminuer les backups ou supprimer une redondance peut être dangereux si l’impact n’est pas compris.
Optimisations production raisonnables
| Optimisation | Condition | Vérification |
|---|---|---|
| Rightsizing compute | CPU/RAM faibles sur longue période. | p95 ressources, latence, erreurs. |
| Autoscaling | Charge variable. | Cooldown, min/max, tests de charge. |
| Réduire retention logs | Conformité compatible. | Besoin audit et investigation. |
| Lifecycle storage | Données anciennes peu consultées. | Politique archive/suppression validée. |
| Reserved / savings plans | Usage stable et prévisible. | Analyse historique. |
| Suppression ressources inutilisées | Owner confirme inutilité. | Plan de rollback ou snapshot si data. |
Workflow optimisation prod
Coût élevé détecté
│
▼
Identifier cost driver
├── compute
├── DB
├── network
├── storage
└── logs
│
▼
Analyser usage réel
├── 7 jours
├── 30 jours
├── pics
└── saisonnalité
│
▼
Proposer changement
├── gain attendu
├── risque
├── rollback
└── owner
│
▼
Apply contrôlé
│
▼
Surveillance post-changePost-check après optimisation
| Zone | Signal |
|---|---|
| Performance | Latence p95/p99 stable. |
| Disponibilité | Health checks et 5xx OK. |
| Capacité | CPU/RAM/DB connexions non saturées. |
| Coût | Diminution visible après période d’observation. |
| Alerting | Aucune nouvelle alerte critique. |
Anti-patterns Coûts & FinOps
| Anti-pattern | Pourquoi c’est dangereux | Alternative professionnelle |
|---|---|---|
| Créer sans estimer | Le coût est découvert après facturation. | Estimation coût avant apply. |
| Ressources non taguées | Impossible d’attribuer les dépenses. | Tags obligatoires contrôlés en CI. |
| Sandbox permanente | Coût continu pour ressource temporaire. | TTL, ExpireAt, cleanup automatique. |
| Staging identique prod sans besoin | Coût élevé inutile. | Parité fonctionnelle, sizing adapté. |
| Logs debug en continu | Explosion ingestion observabilité. | Niveaux log contrôlés et retention adaptée. |
| Surdimensionnement par peur | Gaspillage permanent. | Metrics, autoscaling, rightsizing. |
| Optimiser sans métriques | Risque de panne ou dégradation. | Analyse usage réel avant changement. |
| Supprimer sans owner | Risque de casser un service oublié. | Validation owner + plan de rollback. |
Mauvais modèle
Terraform apply
├── pas d'estimation coût
├── pas de tags
├── pas de budget
├── pas de TTL
├── logs illimités
└── review uniquement techniqueBon modèle
Terraform + FinOps
├── estimation en MR
├── tags obligatoires
├── budgets par env
├── alertes anomalies
├── TTL sandbox
├── retention contrôlée
└── owner coût identifiéChecklist Coûts & FinOps avant apply
Checklist review Terraform
| Point | Validation attendue |
|---|---|
| Ressources ajoutées | Liste claire des nouvelles ressources coûteuses. |
| Delta coût | Estimation mensuelle ou justification. |
| Tags | Project, Environment, Owner, CostCenter, ManagedBy. |
| Environment | Dev/staging/prod dimensionnés différemment. |
| Temporary | TTL ou ExpireAt si ressource temporaire. |
| Storage | Retention, snapshots et lifecycle compris. |
| Logs | Volume et retention maîtrisés. |
| Network | NAT, egress, LB et inter-zone évalués. |
| Budget | Alerte ou suivi coût existant. |
Checklist optimisation
| Métriques usage | CPU/RAM/DB/stockage analysés sur période suffisante. |
| Owner consulté | L’équipe responsable valide le changement. |
| Risque identifié | Performance, disponibilité, data, sécurité. |
| Rollback connu | Retour arrière ou mitigation documenté. |
| Post-check prévu | Métriques et alertes surveillées après apply. |
Checklist CI/CD FinOps
| Contrôle | Action |
|---|---|
| Plan artifact | Conserver plan lisible. |
| Plan JSON | Permettre analyse automatisée. |
| Cost estimate | Publier delta coût en MR. |
| Tags policy | Bloquer ressources sans tags. |
| Allowed sizes | Contrôler instance types et storage. |
| Temporary policy | Forcer ExpireAt sur sandbox/review apps. |
| Approval seuil | Demander validation si coût dépasse seuil. |
Mini-cheat-sheet
# Terraform plan cost flow terraform plan -out=tfplan terraform show -json tfplan > plan.json terraform show -no-color tfplan > plan.txt # Cost tools infracost breakdown --path plan.json checkov -d . trivy config . # Tags minimum Project Environment Owner CostCenter ManagedBy # Review questions - What is the monthly delta? - What is the main cost driver? - Is the resource temporary? - Are tags complete? - Is a budget alert configured? - Is the size justified by metrics?
La Merge Request infra est un contrat de changement
Une MR Terraform ne doit pas seulement contenir du HCL. Elle doit expliquer pourquoi le changement existe, ce qu’il modifie, quel environnement est touché, quel risque opérationnel il introduit, comment le plan a été validé et comment revenir en arrière.
Le reviewer doit pouvoir lire la MR sans deviner l’intention. Une bonne MR infra réduit les incidents parce qu’elle force la réflexion avant l’apply : impact, sécurité, coût, state, rollback, monitoring et fenêtre de production.
Ce qu’une MR infra doit répondre
| Question | Réponse attendue |
|---|---|
| Pourquoi ce changement ? | Besoin métier, dette technique, sécurité, fiabilité, coût, standardisation. |
| Quel environnement ? | Dev, staging, preprod, production, sandbox ou review app. |
| Quelles ressources ? | Network, compute, DB, IAM, DNS, LB, logs, monitoring, storage. |
| Quel impact ? | Disponibilité, sécurité, coût, performance, données, observabilité. |
| Quel plan Terraform ? | Add/change/destroy/replace clairement résumés. |
| Quel rollback ? | Revert, apply précédent, mitigation, feature flag, action manuelle contrôlée. |
Flux d’une MR infra propre
Branche infra
│
▼
Modification Terraform
│
▼
Pipeline MR
├── fmt
├── validate
├── security scan
├── terraform plan
├── cost estimate
└── plan artifact
│
▼
Description MR
├── contexte
├── impact
├── risques
├── rollback
├── post-checks
└── fenêtre prod si nécessaire
│
▼
Review
├── DevOps
├── SRE
├── sécurité si IAM/réseau
└── owner applicatif si impact métier
│
▼
Approval + merge
│
▼
Apply contrôléMR app vs MR infra
| MR applicative | MR infrastructure |
|---|---|
| Change le comportement du code. | Change la fondation d’exécution. |
| Rollback souvent image/version précédente. | Rollback parfois plus complexe : réseau, state, DB, IAM. |
| Tests unitaires/fonctionnels. | Plan, state, sécurité, coût, post-checks. |
| Risque bug métier. | Risque downtime, sécurité, coût, perte data. |
Template complet de Merge Request Terraform
Un template standard évite les oublis et donne aux nouveaux DevOps un cadre clair. Il doit être assez complet pour la production, mais pas au point de devenir bureaucratique pour les changements simples.
Template MR recommandé
## Context Why is this change needed? - Business / technical reason: - Related ticket: - Target environment: - Affected service: ## Scope What changes? - Terraform root: - Modules changed: - Resources affected: - Cloud account / region: ## Terraform plan summary - To add: - To change: - To destroy: - To replace: - Sensitive resources touched: ## Risk analysis - Availability impact: - Security impact: - Data impact: - Cost impact: - Operational complexity: ## Validation - terraform fmt: OK - terraform validate: OK - security scan: OK - terraform plan reviewed: OK - staging tested: yes / no / not applicable ## Rollback / mitigation - Rollback method: - Mitigation if rollback is not immediate: - Owner during deployment: ## Production window - Required: yes / no - Preferred window: - People required: ## Post-checks - Health checks: - Logs: - Metrics: - Alerts: - Business test: ## Notes for reviewers - Specific lines or resources to review: - Known limitations: - Questions:
Version courte pour petits changements
## Summary Short description of the infrastructure change. ## Environment dev / staging / prod ## Plan Add: Change: Destroy: Replace: ## Risk Low / Medium / High Reason: ## Validation - fmt OK - validate OK - plan reviewed - no unexpected destroy ## Rollback How to revert or mitigate. ## Post-check What to verify after apply.
Quand utiliser quel template ?
| Type de changement | Template |
|---|---|
| Tags, dashboard, alarme non critique | Version courte. |
| Compute, autoscaling, logs, stockage | Template complet conseillé. |
| Réseau, IAM, DB, DNS, load balancer | Template complet obligatoire. |
| Production avec risque downtime | Template complet + approval + fenêtre. |
| Import ou state operation | Template complet + mapping state/provider ID. |
Documenter le plan Terraform dans la MR
Le plan est le cœur de la validation. Le reviewer ne doit pas avoir à lire 800 lignes brutes pour comprendre le risque. La MR doit contenir un résumé humain du plan, avec les points sensibles.
Commandes de plan recommandées
terraform fmt -check -recursive terraform validate terraform plan -var-file="prod.tfvars" -out=tfplan terraform show -no-color tfplan > plan.txt terraform show -json tfplan > plan.json
Résumé de plan à mettre dans la MR
Terraform plan summary: - Environment: production - Terraform root: infra/live/prod/api - Resources to add: 2 - Resources to change: 1 - Resources to destroy: 0 - Resources to replace: 0 Sensitive areas: - Network: no public ingress added - IAM: no wildcard permission - Database: not touched - DNS: not touched - Cost impact: estimated +40 EUR/month Plan artifact: - plan.txt attached in pipeline artifacts
destroy ou replace doit être visible dans la description MR, pas caché dans l’artifact.Lecture du plan : symboles
| Symbole | Signification | Réaction reviewer |
|---|---|---|
+ | Création | Vérifier tags, coût, sécurité, naming. |
~ | Modification | Comprendre impact runtime. |
-/+ | Remplacement | Analyser downtime, identité, données. |
- | Suppression | Validation explicite obligatoire. |
<= | Data source lue | Vérifier dépendances et environnement. |
Zones sensibles à extraire
| Réseau | Security groups, routes, NAT, public/private subnets. |
| IAM | Policies, roles, bindings, wildcards, trust relationships. |
| Données | DB, buckets, volumes, backups, snapshots. |
| DNS / TLS | Records, certificats, validation domain. |
| Coûts | Instances, DB, LB, NAT, logs, storage. |
Analyse de risque dans une MR infra
L’analyse de risque permet de décider du niveau de review, de l’approval nécessaire, de la fenêtre de production et de la stratégie de rollback.
Grille de risque
| Risque | Exemples | Contrôle attendu |
|---|---|---|
| Faible | Tags, description, dashboard, alarme non critique. | Review simple. |
| Moyen | Compute size, autoscaling, log retention, non-prod. | Plan review + validation staging. |
| Élevé | Security group, load balancer, DNS, IAM limité. | Review senior + approval. |
| Critique | Database, state, KMS, network core, suppression prod. | Double approval + fenêtre + rollback documenté. |
Bloc “Risk analysis” prêt à coller
Risk analysis: - Availability impact: low / medium / high - Security impact: low / medium / high - Data impact: none / low / medium / high - Cost impact: none / low / medium / high - Rollback complexity: simple / moderate / complex - Production window required: yes / no Risk explanation: This change modifies ... The main risk is ... The mitigation is ...
Diagramme de décision
MR Terraform
│
▼
Touche production ?
│
├── Non
│ └── review standard
│
└── Oui
│
▼
Touche DB, IAM, réseau, DNS ou state ?
│
├── Oui
│ ├── review senior
│ ├── approval renforcé
│ ├── rollback documenté
│ └── fenêtre si nécessaire
│
└── Non
├── plan review
└── post-checksQuestions de risque obligatoires
| Peut-on provoquer un downtime ? | LB, DNS, network, compute, DB. |
| Peut-on exposer un service ? | Security group, firewall, public IP, IAM. |
| Peut-on perdre ou corrompre des données ? | DB, bucket, volume, backup, lifecycle. |
| Peut-on augmenter fortement la facture ? | Instance, DB, NAT, logs, storage. |
| Peut-on bloquer les prochains applies ? | State, backend, provider, import, lock. |
Rollback et mitigation dans une MR Terraform
Une MR infra doit expliquer comment revenir en arrière ou réduire l’impact si le changement provoque un incident. Pour Terraform, un rollback n’est pas toujours un simple revert Git.
Rollback par type de changement
| Changement | Rollback typique | Attention |
|---|---|---|
| Tag / metadata | Revert commit puis apply. | Faible risque. |
| Security group | Restaurer règle précédente. | Ne pas ouvrir trop large en urgence. |
| DNS | Restaurer ancien record. | TTL et propagation. |
| Load balancer | Restaurer listener/routing/target group. | Health checks et trafic réel. |
| IAM | Restaurer policy précédente. | Propagation et blast radius. |
| Database | Rollback souvent non trivial. | Backup, snapshot, mitigation, DBA. |
| State operation | Restaurer state backup ou state mv inverse. | Très sensible, review obligatoire. |
Bloc MR rollback
Rollback / mitigation: - Preferred rollback: Revert this MR and apply the previous Terraform plan. - If immediate rollback is unsafe: Apply a minimal mitigation: - restore previous security group rule - disable new listener rule - switch DNS back to previous target - Validation after rollback: - health endpoint OK - 5xx rate stable - latency p95 stable - no new critical alert - Owner during rollback: Platform team / on-call DevOps
Diagramme rollback
Incident après apply
│
▼
Identifier changement responsable
│
▼
Rollback simple possible ?
│
├── Oui
│ ├── revert commit
│ ├── terraform plan
│ ├── review du rollback plan
│ └── terraform apply
│
└── Non
├── mitigation minimale
├── correction ciblée
├── backup / restore si data
└── escalade expert
│
▼
Post-checks
├── health
├── logs
├── metrics
└── alertsCommandes de rollback contrôlé
# Revenir au commit précédent par revert git revert <commit_id> git push origin main # Générer un plan de rollback terraform plan -var-file="prod.tfvars" -out=tfplan terraform show -no-color tfplan > rollback-plan.txt # Appliquer seulement après review terraform apply tfplan
Comment reviewer une MR Terraform
Le reviewer ne doit pas seulement regarder la syntaxe. Il doit vérifier le plan, le state, les dépendances, les risques, les tags, les coûts, les secrets, la sécurité et la capacité de rollback.
Checklist reviewer
| Zone | À vérifier |
|---|---|
| Contexte | La raison du changement est claire. |
| Plan | Add/change/destroy/replace cohérents. |
| Environment | Bon root, bon backend, bons tfvars. |
| State | Pas de confusion dev/staging/prod. |
| Réseau | Pas d’ouverture large non justifiée. |
| IAM | Pas de wildcard ou privilège excessif. |
| Données | DB, buckets, volumes protégés. |
| Coûts | Ressources coûteuses justifiées et taguées. |
| Rollback | Réellement faisable et documenté. |
Commentaires reviewer utiles
Good review comments: - The plan shows a replacement of the load balancer. Is this expected? What is the downtime risk? - This security group opens port 5432 to a broad CIDR. Can we restrict it to the application security group? - The new database has deletion protection disabled. Is this intentional for production? - This resource is missing CostCenter and Owner tags. - Rollback mentions revert only. Can you add the exact validation steps after rollback?
Questions à poser
| “Pourquoi ce changement maintenant ?” | Valider le besoin. |
| “Que dit le plan exactement ?” | Éviter les surprises. |
| “Qu’est-ce qui peut casser ?” | Identifier le risque réel. |
| “Comment voit-on que c’est OK ?” | Définir les post-checks. |
| “Comment revient-on en arrière ?” | Valider la mitigation. |
Approval : qui doit valider quoi ?
Toutes les MR Terraform ne nécessitent pas le même niveau d’approbation. L’approval doit dépendre de l’environnement, du type de ressource et du risque.
Matrice d’approbation
| Changement | Reviewer requis | Approval |
|---|---|---|
| Dev non critique | DevOps ou pair technique. | 1 approval. |
| Staging compute/logs | DevOps + owner service si impact. | 1 approval. |
| Prod compute/autoscaling | DevOps senior ou SRE. | 1 à 2 approvals. |
| Prod réseau / LB / DNS | DevOps senior + owner applicatif. | Approval renforcé. |
| Prod IAM / sécurité | DevOps senior + sécurité. | Approval sécurité. |
| Prod DB / state | DevOps senior + DBA/SRE + owner. | Double approval + fenêtre. |
Critères Go / No-Go
| Critère | Go | No-Go |
|---|---|---|
| Plan | Compris et attendu. | Destroy/replace inexpliqué. |
| Rollback | Clair et réalisable. | Absent ou irréaliste. |
| Sécurité | Risque accepté ou absent. | Secret exposé, IAM trop large. |
| Monitoring | Post-checks définis. | Impact invisible. |
Flux approval production
MR ouverte
│
▼
Pipeline vert
│
├── fmt
├── validate
├── security scan
├── plan
└── cost estimate
│
▼
Review technique
│
▼
Review risque
├── réseau
├── IAM
├── data
├── state
└── coût
│
▼
Approval
│
▼
Merge
│
▼
Apply manuel protégéGitLab protections utiles
| Protected branches | Empêcher merge non autorisé vers main. |
| Merge request approvals | Forcer review selon règles. |
| CODEOWNERS | Assigner reviewers par dossier infra. |
| Protected environments | Limiter qui peut déployer production. |
| Required pipeline success | Interdire merge si tests échouent. |
CI/CD attendue pour une MR Terraform
La CI/CD doit produire les preuves nécessaires à la review : format, validation, scan sécurité, plan lisible, estimation coût et artifacts.
Pipeline MR recommandé
stages:
- lint
- validate
- security
- plan
- cost
variables:
TF_IN_AUTOMATION: "true"
TF_INPUT: "false"
TF_ROOT: "infra/live/staging/app"
default:
image: hashicorp/terraform:1.6.6
before_script:
- cd "$TF_ROOT"
- terraform init
terraform_fmt:
stage: lint
script:
- terraform fmt -check -recursive
terraform_validate:
stage: validate
script:
- terraform validate
terraform_plan:
stage: plan
script:
- terraform plan -out=tfplan
- terraform show -no-color tfplan > plan.txt
- terraform show -json tfplan > plan.json
artifacts:
paths:
- "$TF_ROOT/tfplan"
- "$TF_ROOT/plan.txt"
- "$TF_ROOT/plan.json"
expire_in: 3 daysContrôles CI à inclure
| Contrôle | But |
|---|---|
| fmt | Code standardisé. |
| validate | Syntaxe et configuration valides. |
| tflint | Qualité Terraform et règles provider. |
| checkov / trivy / tfsec | Risques sécurité IaC. |
| plan artifact | Review humaine complète. |
| plan JSON | Contrôles automatiques et coût. |
| infracost | Impact financier avant merge. |
Debug CI sécurisé
echo "Branch: $CI_COMMIT_BRANCH" echo "Environment: $CI_ENVIRONMENT_NAME" echo "Terraform root: $TF_ROOT" terraform --version # Vérifier présence sans exposer if [ -z "$AWS_ACCESS_KEY_ID" ]; then echo "AWS_ACCESS_KEY_ID is missing" exit 1 else echo "AWS_ACCESS_KEY_ID is present" fi
env, printenv ou echo $SECRET pour déboguer une MR infra.Exemples de MR infra bien documentées
Exemple 1 : ajout d’une alarme CloudWatch / monitoring
Summary: Add CPU and HTTP 5xx alerts for production API. Environment: production Plan: - Add: 2 monitoring alarms - Change: 0 - Destroy: 0 - Replace: 0 Risk: Low. No runtime resource is modified. Only monitoring resources are added. Validation: - terraform fmt OK - terraform validate OK - terraform plan reviewed - no destroy - alert names and thresholds checked Rollback: Revert MR and apply previous plan. Post-check: - Alarms visible in monitoring console - Notification channel receives test event
Exemple 2 : modification security group DB
Summary: Allow API service security group to reach PostgreSQL on port 5432. Environment: production Plan: - Add: 1 ingress rule - Change: 1 security group - Destroy: 0 - Replace: 0 Risk: Medium/high. Network access to DB is modified. No public CIDR is introduced. Source is restricted to API security group. Validation: - plan reviewed - no 0.0.0.0/0 - staging connectivity tested - DB logs monitored Rollback: Remove the ingress rule by reverting this MR. If urgent, apply minimal SG rule rollback. Post-check: - API can connect to DB - no new DB connection errors - 5xx stable
Exemple 3 : changement de taille instance
Summary: Increase staging worker instance type from t3.micro to t3.small. Environment: staging Reason: Current workers show sustained CPU saturation during batch tests. Plan: - Change: worker launch template instance_type - Replace: rolling replacement through autoscaling - Destroy: 0 direct unmanaged destroy Risk: Medium. Temporary capacity fluctuation during rollout. Cost impact: Estimated +25 EUR/month in staging. Rollback: Revert instance_type to t3.micro and apply. If saturation returns, reduce batch concurrency. Post-check: - workers healthy - queue backlog decreasing - CPU below 70% - no failed jobs
Exemple 4 : import ressource existante
Summary: Import existing production API security group into Terraform state. Environment: production Resource: - Terraform address: aws_security_group.api - Provider ID: sg-0abc123456789def0 - State key: prod/network/terraform.tfstate Plan: - Import only - Expected diff: tags normalization - Destroy: 0 - Replace: 0 Risk: Medium. Future plans may modify this SG if code is not aligned. Validation: - state backup created - terraform state show reviewed - plan reviewed - no unexpected rule deletion Rollback: terraform state rm aws_security_group.api if mapping is wrong, using state backup if needed.
Anti-patterns des Merge Requests infra
| Anti-pattern | Pourquoi c’est dangereux | Correction professionnelle |
|---|---|---|
| Description vide | Le reviewer doit deviner l’intention. | Template MR obligatoire. |
| “Juste un petit changement” | Minimise sans preuve. | Résumer le plan et le risque. |
| Plan non joint | Impossible de valider l’impact réel. | Artifact plan.txt obligatoire. |
| Destroy caché dans le plan | Suppression non relue. | Afficher destroy/replace dans la MR. |
| Rollback absent | Improvisation pendant incident. | Rollback ou mitigation documenté. |
| Pas de post-check | Apply réussi mais prod non vérifiée. | Health, logs, metrics, alertes. |
| Secrets dans logs MR | Fuite durable. | Variables protégées et debug sans valeurs. |
| Review purement syntaxique | Risque opérationnel ignoré. | Review plan, state, sécurité, coût. |
Mauvais modèle
MR infra faible
├── description vide
├── pas de plan résumé
├── pas de risk analysis
├── pas de rollback
├── pas de post-check
└── merge rapideBon modèle
MR infra professionnelle
├── contexte clair
├── plan résumé
├── risques explicités
├── rollback documenté
├── coût visible
├── checks CI
├── approval adapté
└── post-checks définisChecklist Merge Request infra
Checklist auteur de MR
| Point | Validation attendue |
|---|---|
| Contexte | Pourquoi le changement est nécessaire. |
| Périmètre | Environnement, root Terraform, ressources touchées. |
| Plan | Add/change/destroy/replace résumés. |
| Pipeline | fmt, validate, scan, plan OK. |
| Risque | Disponibilité, sécurité, data, coût, state. |
| Rollback | Procédure ou mitigation réaliste. |
| Post-checks | Health, logs, métriques, alertes, test métier. |
| Secrets | Aucun secret dans code, logs, plan, artifacts. |
| Cost | Impact coût mentionné si ressource coûteuse. |
Checklist reviewer
| Je comprends l’objectif. | Pas de contexte flou. |
| Je comprends le plan. | Aucun diff important ignoré. |
| Je vois le risque. | Réseau, IAM, DB, DNS, state, coût. |
| Je peux valider le rollback. | Pas de promesse vague. |
| Je sais quoi vérifier après apply. | Post-checks précis. |
Checklist production
| Question | Réponse attendue |
|---|---|
| La MR touche-t-elle production ? | Oui/non clairement indiqué. |
| Y a-t-il un destroy ? | Non ou explicitement justifié. |
| Y a-t-il un replace ? | Non ou downtime analysé. |
| La DB est-elle touchée ? | Si oui, backup/protection/review senior. |
| IAM ou réseau est-il modifié ? | Review sécurité ou senior. |
| Une fenêtre est-elle nécessaire ? | Oui si changement à risque. |
| L’apply sera-t-il manuel ? | Oui pour production. |
| Les dashboards sont-ils prêts ? | Oui si impact runtime. |
Mini-cheat-sheet MR infra
MR Terraform must include: - Context - Environment - Terraform root - Plan summary - Risk analysis - Security impact - Cost impact - Rollback / mitigation - Post-checks - Reviewers / approvals Commands: terraform fmt -check -recursive terraform validate terraform plan -out=tfplan terraform show -no-color tfplan > plan.txt terraform show -json tfplan > plan.json
Approvals & protections : empêcher l’erreur humaine en production
Les protections GitLab ne sont pas de la bureaucratie. Elles servent à éviter qu’un changement non relu, non testé, mal ciblé ou exécuté par la mauvaise personne modifie la production.
Pour l’infrastructure, le risque est plus élevé qu’une simple MR applicative : un mauvais apply Terraform peut modifier un security group, casser un DNS, supprimer une ressource, changer une policy IAM, exposer un service ou bloquer une base de données.
Les protections essentielles
| Protection | But | Exemple |
|---|---|---|
| Protected branches | Empêcher push direct ou merge non autorisé. | main, release/*. |
| Merge request approvals | Forcer une revue humaine avant merge. | 1 ou 2 approvals selon risque. |
| Protected environments | Limiter qui peut déployer vers production. | Seuls Maintainers/SRE peuvent lancer apply prod. |
| Protected variables | Limiter les secrets aux branches/tags protégés. | Credentials prod indisponibles en feature branch. |
| CODEOWNERS | Assigner automatiquement les bons reviewers. | Sécurité relit IAM, DBA relit DB. |
| Required pipeline success | Bloquer merge si CI échoue. | fmt, validate, scan, plan obligatoires. |
Chaîne de protection recommandée
Developer branch
│
▼
Merge Request
│
├── terraform fmt
├── terraform validate
├── security scan
├── terraform plan
└── cost estimate
│
▼
Approval rules
├── DevOps reviewer
├── Security reviewer if IAM/network
├── DBA reviewer if database
└── SRE reviewer if prod risk
│
▼
Merge to protected branch
│
▼
Production pipeline
├── protected variables
├── protected runner
├── protected environment
└── manual apply
│
▼
Audited production changePrincipe de défense en profondeur
| Couche | Protection |
|---|---|
| Git | Branches protégées, MR obligatoire. |
| CI | Pipeline obligatoire, tests et scans. |
| Review | Approvals et CODEOWNERS. |
| Secrets | Variables protected/scoped, OIDC, IAM minimal. |
| Deploy | Environment protégé, apply manuel. |
| Audit | Trace MR, pipeline, approver, job, plan. |
Branches protégées : contrôler le chemin vers production
Les branches protégées empêchent les push directs, limitent qui peut merger et garantissent que les changements passent par une MR, une CI et une review.
Politique de branches recommandée
| Branche | Usage | Protection |
|---|---|---|
feature/* | Travail individuel. | Pas de secrets prod, pas d’apply prod. |
develop | Intégration dev. | Pipeline requis selon équipe. |
release/* | Préparation staging/preprod. | Review + pipeline vert. |
main | Source officielle production. | Protected, MR only, approvals, pipeline success. |
hotfix/* | Correction urgente encadrée. | Review rapide mais obligatoire si prod. |
Règles à appliquer sur main
- Interdire le push direct.
- Autoriser le merge seulement aux Maintainers ou Owners.
- Exiger pipeline vert avant merge.
- Exiger une ou plusieurs approvals.
- Empêcher la suppression de la branche.
- Limiter les variables production aux branches protégées.
main doit représenter l’état validé, relu et déployable de l’infrastructure.Flux Git attendu
feature/infra-change
│
▼
Merge Request
│
├── pipeline MR
├── plan artifact
├── review
└── approval
│
▼
main protected
│
▼
Pipeline production
│
├── plan final
├── apply manual
└── protected environmentErreurs fréquentes
| Erreur | Risque | Correction |
|---|---|---|
Push direct sur main | Pas de review, pas de discussion, risque prod. | Protected branch + MR obligatoire. |
| Merge malgré CI rouge | Code infra non validé. | Require pipeline success. |
| Secrets prod disponibles sur feature branch | Fuite ou usage non autorisé. | Protected variables. |
| Maintainers trop nombreux | Trop de personnes peuvent merger prod. | Limiter rôles et auditer régulièrement. |
Environnements protégés : limiter qui peut déployer
Une branche protégée contrôle le code. Un environnement protégé contrôle le déploiement. Pour Terraform, cela signifie limiter qui peut lancer un apply sur staging ou production.
Modèle d’environnements
| Environnement | Déploiement autorisé par | Niveau de contrôle |
|---|---|---|
| development | Developers / DevOps selon équipe. | Souple, mais secrets limités. |
| staging | DevOps, Maintainers. | Contrôle intermédiaire. |
| preproduction | DevOps senior / SRE. | Proche production. |
| production | SRE, Maintainers autorisés, release managers. | Strict, approval + manual apply. |
Job apply production
terraform_apply_prod:
stage: apply
environment:
name: production
script:
- terraform apply tfplan
when: manual
allow_failure: false
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
tags:
- protected
- terraform
- prodChaîne environment protection
main protected
│
▼
pipeline production
│
▼
manual job apply_prod
│
├── environment: production
├── protected environment
├── protected variables
├── protected runner
└── authorized deployers only
│
▼
terraform apply productionÀ protéger explicitement
| Élément | Pourquoi |
|---|---|
| Environment production | Empêcher n’importe qui de lancer apply. |
| Runner production | Éviter exécution sur runner partagé non maîtrisé. |
| Variables production | Secrets accessibles seulement au contexte autorisé. |
| Artifacts de plan | Éviter manipulation ou plan obsolète. |
| State backend | Accès IAM limité et audité. |
Approval rules : adapter la validation au risque
Les règles d’approval doivent refléter la criticité du changement. Un tag non critique ne nécessite pas le même niveau de validation qu’un changement IAM, database, DNS ou network core.
Matrice d’approbation infra
| Type de MR | Approval minimum | Reviewer recommandé |
|---|---|---|
| Docs, tags, dashboard non critique | 1 | DevOps pair. |
| Compute non-prod | 1 | DevOps ou service owner. |
| Staging proche prod | 1 à 2 | DevOps + owner applicatif. |
| Production compute/autoscaling | 2 | DevOps senior + SRE. |
| Production network/DNS/LB | 2 | DevOps senior + service owner. |
| Production IAM/security | 2 + sécurité | Security reviewer obligatoire. |
| Production DB/state | 2 + expert | DBA/SRE + DevOps senior. |
Règle simple
Low risk: 1 reviewer Medium risk: 1 DevOps reviewer + plan artifact High risk: 2 reviewers + rollback documented Critical: 2 reviewers + expert approval + production window + post-checks
Décision approval par impact
MR Terraform
│
▼
Environment = production ?
│
├── No
│ └── standard approval
│
└── Yes
│
▼
Touches sensitive area ?
├── IAM
├── network
├── DNS
├── database
├── state
└── secrets
│
▼
Yes: expert reviewer required
No: standard prod reviewer
│
▼
Pipeline green + approval
│
▼
Merge / apply manualApproval ne doit pas être automatique
| Mauvaise validation | Bonne validation |
|---|---|
| “LGTM” sans lire le plan. | “Plan reviewed, no destroy, SG source restricted.” |
| Approval par habitude. | Approval avec risque compris. |
| Reviewer non compétent sur la zone. | Reviewer adapté : IAM, DB, réseau, SRE. |
| Approval malgré pipeline rouge. | Pipeline vert requis. |
Séparation des droits : éviter le super-pouvoir permanent
La séparation des droits réduit le risque d’erreur, de compromission et d’action non autorisée. Un développeur peut contribuer au code Terraform sans avoir le droit d’appliquer en production.
Modèle de rôles recommandé
| Rôle | Droits GitLab | Droits infra |
|---|---|---|
| Developer | Créer branches/MR. | Aucun apply prod. |
| DevOps | Reviewer, maintenir pipelines. | Apply dev/staging selon règles. |
| Maintainer | Merge sur branches protégées. | Apply prod si autorisé. |
| SRE / Release manager | Valider et déclencher prod. | Accès prod contrôlé et audité. |
| Security | Review IAM/secrets/network. | Pas forcément apply, mais approval sécurité. |
| Break-glass | Accès urgence temporaire. | Très contrôlé, journalisé, révocable. |
Séparer contribution et exécution
Developer
├── écrit Terraform
├── ouvre MR
└── lit le plan
Reviewer
├── relit code
├── relit plan
└── approuve
Authorized deployer
├── déclenche apply
├── surveille production
└── documente résultatLeast privilege GitLab + cloud
| Zone | Principe | Exemple |
|---|---|---|
| GitLab project | Accès minimum nécessaire. | Pas Maintainer pour tout le monde. |
| Protected branch | Merge limité. | Maintainers uniquement. |
| Protected environment | Deploy limité. | SRE / release managers. |
| Cloud IAM | Rôle CI limité. | Plan role ≠ apply role. |
| Secrets | Disponibles uniquement au contexte utile. | Prod variables sur main + prod env. |
Exemple de séparation plan/apply
terraform_plan_prod:
stage: plan
environment:
name: production
script:
- terraform plan -out=tfplan
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
terraform_apply_prod:
stage: apply
environment:
name: production
script:
- terraform apply tfplan
when: manual
rules:
- if: '$CI_COMMIT_BRANCH == "main"'Production : apply manuel, fenêtre et traçabilité
En production, l’apply Terraform doit être traité comme une opération contrôlée. Le pipeline doit empêcher l’exécution automatique non maîtrisée et fournir une trace complète.
Règles production
| Règle | Pourquoi |
|---|---|
| Apply manuel | Éviter modification prod automatique sans décision. |
| Pipeline vert | fmt, validate, plan et scans validés. |
| Approval avant merge | Review du plan et du risque. |
| Environment protégé | Seules personnes autorisées peuvent déployer. |
| Fenêtre si risque | Équipe disponible pour surveiller et rollback. |
| Post-checks | Vérifier que la prod fonctionne réellement. |
Runbook apply production
Before apply: - MR approved - pipeline green - plan reviewed - no unexpected destroy/replace - rollback documented - dashboards open - production window confirmed if needed During apply: - trigger manual job - monitor job logs - do not run concurrent apply After apply: - run health checks - check logs - check metrics - check alerts - document result
Timeline production
T-30 min
├── confirm approval
├── review latest plan
├── open dashboards
└── announce change
T0
├── trigger manual apply
└── monitor pipeline
T+5 min
├── verify cloud resources
├── healthcheck
└── logs
T+15 min
├── metrics
├── alerts
└── business smoke test
T+30 min
├── close change
└── document outcomePost-checks à exiger
| Zone | Validation |
|---|---|
| Application | Health endpoint OK. |
| HTTP | 5xx stables, latence p95/p99 stable. |
| Infrastructure | Resources healthy, no unexpected drift. |
| Database | Connexions, locks, slow queries OK. |
| Alerting | Aucune nouvelle alerte critique. |
| Security | Pas d’ouverture ou permission inattendue. |
CODEOWNERS : router les reviews aux bonnes personnes
CODEOWNERS permet d’assigner automatiquement des reviewers selon les fichiers modifiés. Pour l’infra, c’est très utile : les changements IAM, réseau, DB ou production doivent être relus par les bonnes personnes.
Exemple CODEOWNERS infra
# Global infrastructure owners /infra/ @platform-team # Production requires SRE review /infra/live/prod/ @sre-team @platform-leads # IAM and security-sensitive files /infra/modules/iam/ @security-team @platform-team /infra/**/iam*.tf @security-team # Network /infra/modules/network/ @network-team @platform-team /infra/**/security_group*.tf @platform-team # Databases /infra/modules/database/ @dba-team @sre-team /infra/**/rds*.tf @dba-team # CI templates /.gitlab/ci/ @devops-team /.gitlab-ci.yml @devops-team
Mapping fichiers → reviewers
| Fichiers modifiés | Reviewer attendu | Pourquoi |
|---|---|---|
infra/live/prod/** | SRE / platform lead | Impact production. |
modules/iam/** | Security | Risque privilèges. |
modules/network/** | Network / DevOps senior | Risque connectivité. |
modules/database/** | DBA / SRE | Risque data. |
.gitlab-ci.yml | DevOps | Risque pipeline/secrets. |
Pièges CODEOWNERS
| Trop de owners globaux | Les reviews deviennent symboliques. |
| Owners absents ou anciens | Blocage ou validation par mauvaises personnes. |
| Pas de règles par zone sensible | IAM/DB/réseau relus par personnes non expertes. |
| CODEOWNERS non obligatoire | Suggestion sans enforcement. |
Secrets, variables protégées et scopes
Les protections GitLab doivent empêcher qu’une branche non protégée, une MR externe, un runner partagé ou un job non prévu accède aux secrets production.
Variables GitLab à protéger
| Option | Usage | Exemple |
|---|---|---|
| Masked | Masquer dans les logs. | Tokens, passwords, cloud keys. |
| Protected | Disponible uniquement branches/tags protégés. | Credentials production. |
| Environment scope | Limiter à un environnement. | production, staging. |
| File variable | Stocker clé/certificat/kubeconfig en fichier. | Kubeconfig, private key. |
Mapping recommandé
DEV credentials: protected: false or limited environment scope: development STAGING credentials: protected: true if release branches are protected environment scope: staging PROD credentials: protected: true environment scope: production available only from main / protected tags
OIDC et credentials courts
GitLab protected job
│
▼
OIDC token
│
▼
Cloud IAM trust policy
├── project allowed
├── branch allowed
├── environment allowed
└── audience checked
│
▼
Temporary credentials
│
▼
Terraform plan/applyDebug sécurisé
# Good: check presence only if [ -z "$AWS_ACCESS_KEY_ID" ]; then echo "AWS_ACCESS_KEY_ID is missing" exit 1 else echo "AWS_ACCESS_KEY_ID is present" fi # Bad: exposes secrets env printenv echo "$AWS_SECRET_ACCESS_KEY" set -x
Audit : prouver qui a validé et qui a déployé
Une protection utile doit laisser une trace : qui a ouvert la MR, qui l’a approuvée, quel plan a été relu, qui a lancé l’apply, avec quels credentials, et quel résultat a été observé.
Éléments à auditer
| Élément | Preuve attendue |
|---|---|
| MR | Description, discussions, reviewers, approvals. |
| Pipeline | Jobs, logs, artifacts, statut, durée. |
| Plan Terraform | plan.txt, résumé add/change/destroy/replace. |
| Apply | Job manuel, déclencheur, environnement, heure. |
| Variables | Protected/scoped, pas de secret exposé. |
| Cloud audit | Rôle utilisé, API calls, ressources modifiées. |
| Post-checks | Health, logs, metrics, alertes, notes de changement. |
Questions d’audit post-change
- Who approved the MR? - Was the pipeline green before merge? - Which plan artifact was reviewed? - Who triggered production apply? - Which protected environment was used? - Which cloud role executed the change? - Were there unexpected destroy/replace actions? - Were post-checks completed? - Was rollback documented?
Audit trail idéal
MR approved
│
├── approver identity
├── plan artifact
├── discussion history
└── risk acceptance
│
▼
Pipeline apply
│
├── manual trigger user
├── protected environment
├── protected runner
└── job logs
│
▼
Cloud audit
│
├── assumed role
├── API calls
├── resources changed
└── timestamp
│
▼
Post-change evidence
├── health checks
├── metrics
├── logs
└── incident/change ticketÀ conserver
| Plan artifact | Preuve du changement prévu. |
| Pipeline logs | Preuve d’exécution. |
| MR discussion | Preuve de décision et review. |
| Cloud audit logs | Preuve des actions réelles. |
| Change ticket | Contexte métier et opérationnel. |
Anti-patterns approvals & protections
| Anti-pattern | Pourquoi c’est dangereux | Alternative professionnelle |
|---|---|---|
| Tout le monde Maintainer | Trop de personnes peuvent merger ou déployer. | Rôles minimaux et revue périodique. |
| Push direct sur main | Contourne MR, CI et review. | Protected branch + MR obligatoire. |
| Approval symbolique | Personne ne lit réellement le plan. | Approval avec checklist et responsabilité. |
| Apply prod automatique | Change prod sans décision humaine immédiate. | Manual apply + environment protégé. |
| Secrets prod sur branches non protégées | Fuite ou usage non autorisé. | Protected + environment scoped variables. |
| Runner partagé pour production | Surface d’attaque plus large. | Runner protégé dédié infra/prod. |
| CODEOWNERS obsolète | Mauvais reviewers ou blocages. | Maintenance régulière. |
| Pas d’audit des permissions | Droits accumulés avec le temps. | Review trimestrielle des accès. |
Mauvais modèle
GitLab non protégé
├── push direct main
├── variables prod globales
├── apply automatique
├── runner partagé
├── approval symbolique
└── pas de CODEOWNERSBon modèle
GitLab protégé
├── protected branches
├── MR obligatoire
├── pipeline vert requis
├── approval rules
├── CODEOWNERS
├── protected variables
├── protected environment
└── manual apply prodChecklist Approvals & protections
Checklist GitLab project
| Contrôle | Validation attendue |
|---|---|
Protected branch main | Push direct interdit, merge limité. |
| Pipeline success required | Pas de merge si CI rouge. |
| Approval rules | Nombre d’approvals adapté au risque. |
| CODEOWNERS | Reviewers par zone sensible. |
| Protected environment | Production déployable seulement par autorisés. |
| Protected variables | Secrets prod limités aux contextes protégés. |
| Protected runners | Jobs prod sur runners maîtrisés. |
| Audit accès | Maintainers et deployers revus régulièrement. |
Checklist MR production
| Description claire | Contexte, scope, risque, rollback. |
| Plan artifact | plan.txt disponible. |
| Destroy/replace | Absents ou justifiés explicitement. |
| Approval expert | Présent si IAM, réseau, DB, state. |
| Post-checks | Health, logs, metrics, alertes. |
Checklist sécurité des droits
| Question | Réponse attendue |
|---|---|
Qui peut merger sur main ? | Liste courte et justifiée. |
| Qui peut lancer apply prod ? | Personnes explicitement autorisées. |
| Les secrets prod sont-ils protégés ? | Masked, protected, scoped production. |
| Le runner prod est-il dédié ? | Oui, ou risque accepté et documenté. |
| Les rôles cloud sont-ils minimaux ? | Least privilege, pas admin permanent. |
| Les accès sont-ils revus ? | Revue périodique et suppression des anciens accès. |
Mini-cheat-sheet
Must have: - Protected branch main - No direct push to main - Required pipeline success - MR approvals - CODEOWNERS for sensitive paths - Protected production environment - Manual apply for production - Protected and scoped variables - Protected runner for production - Regular access review Sensitive paths: infra/live/prod/** infra/modules/iam/** infra/modules/network/** infra/modules/database/** .gitlab-ci.yml
