Module 1 – Infrastructure as Code avec Terraform & Terragrunt

Structurez vos modules Terraform, Terragrunt et pipelines (fmt, validate, plan), avec backend distant, linting et estimation de coûts.

Première étape : industrialiser l’infrastructure. Ce module couvre Terraform, Terragrunt et les bonnes pratiques pour gérer des environnements multi-cloud avec tests et gouvernance.

Objectifs

  • Structurer un repository Terraform modulaire compatible multi-environnements.
  • Configurer un backend distant, le verrouillage d’état et les pipelines de validation.
  • Automatiser les tests (tflint, tfsec, terraform-docs) et la promotion via Terragrunt.

1. Architecture du dépôt

infra/
├── modules/
│   ├── network/
│   ├── compute/
│   └── observability/
├── envs/
│   ├── dev/
│   │   └── terragrunt.hcl
│   ├── staging/
│   └── prod/
└── global/
    └── s3-backend.tf

Chaque module expose variables.tf, outputs.tf, README.md généré avec terraform-docs.

2. Backend & locking

Exemple AWS (S3 + DynamoDB) :

terraform {
  backend "s3" {
    bucket         = "devops-training-tfstate"
    key            = "global/terraform.tfstate"
    region         = "eu-west-3"
    dynamodb_table = "devops-training-lock"
    encrypt        = true
  }
}

Provisionnez le bucket via AWS CLI ou Terraform bootstrap, appliquez ensuite terraform init.

3. Terragrunt

# envs/staging/terragrunt.hcl
include {
  path = find_in_parent_folders()
}
terraform {
  source = "../../modules/network"
}
inputs = {
  environment = "staging"
  cidr_block  = "10.40.0.0/16"
}

Fichier racine :

# terragrunt.hcl à la racine
generate "provider" {
  path      = "provider.tf"
  if_exists = "overwrite"
  contents  = <

4. Qualité & tests

pip install pre-commit
cat <<'EOF' > .pre-commit-config.yaml
repos:
  - repo: https://github.com/antonbabenko/pre-commit-terraform
    rev: v1.90.1
    hooks:
      - id: terraform_fmt
      - id: terraform_tflint
      - id: terraform_tfsec
      - id: terraform_docs
EOF
pre-commit install

Ajoutez terraform validate et terraform plan dans vos pipelines.

5. Pipelines (exemple GitLab CI)

stages:
  - fmt
  - validate
  - plan
fmt:
  stage: fmt
  image: hashicorp/terraform:1.6.3
  script:
    - terraform fmt -check -recursive
validate:
  stage: validate
  image: alpine/terragrunt:1.5
  script:
    - terragrunt init
    - terragrunt validate
plan:
  stage: plan
  image: alpine/terragrunt:1.5
  script:
    - terragrunt plan -out plan.tfplan
  artifacts:
    paths:
      - plan.tfplan

Ajoutez un job apply déclenché manuellement (when: manual) pour staging/prod.

6. Lab guidé

  1. Initialiser le backend S3/DynamoDB (ou équivalent Azure/GCP).
  2. Créer les modules network (VPC + subnets) et compute (EC2 ou VM). Exporter les outputs nécessaires.
  3. Configurer Terragrunt pour envs/dev et envs/staging.
  4. Exécuter terragrunt run-all plan puis terragrunt run-all apply (dev uniquement).
  5. Mettre en place une pipeline (GitHub Actions / GitLab / Jenkins) exécutant fmt + validate + plan.

Challenge optionnel

  • Intégrer infracost pour estimer les coûts sur chaque plan.
  • Packager un module privé (Terraform Registry interne) et l’utiliser via source = "app.terraform.io/my-org/network/aws".
  • Automatiser le déploiement d’un account landing zone multi régions à l’aide de Terragrunt stacks.

Solution détaillée

  1. Backend opérationnel : terraform init doit créer/mettre à jour .terraform. aws dynamodb scan --table-name devops-training-lock affiche les verrous lors d’un plan ou apply.
  2. Plan Terragrunt : terragrunt run-all plan renvoie 0 changement en staging (si pas appliqué) ou liste les ressources à créer. Vérifiez que les chemins d’état sont uniques (terragrunt state pull | jq '.resources | length').
  3. Pipeline : la CI doit afficher trois jobs verts. Fichiers terraform fmt ne doivent pas générer de diff. Ajoutez un badge “Terraform fmt/validate” au README.
  4. Infracost (challenge) : la sortie JSON partage les coûts. Exemple :
    Total monthly cost change: +$43.25
    

    Documentez ces chiffres dans docs/finops.md.

  5. Outputs : terraform output -state=dev/terraform.tfstate renvoie les IDs créés. Capturez-les dans le journal.

Avant de passer au module 2, supprimez l’infrastructure (terragrunt run-all destroy sur dev) pour valider le cycle complet.

Pièges fréquents

  • Oublier de définir unique_state_filename dans Terragrunt → collisions de state.
  • Mélanger variables sensibles dans terraform.tfvars commités. Utilisez dotenv ou Vault.
  • Ne pas verrouiller les versions (required_version, required_providers) : vous risquez des changements non maîtrisés.

Ressources complémentaires

Checklist

  • ✅ Backend distant et verrouillage configurés.
  • ✅ Modules Terraform documentés et testés.
  • ✅ Terragrunt gère au moins deux environnements.
  • ✅ Pipeline CI exécute fmt + validate + plan (et publie artefacts).