Les meta-arguments modifient le comportement des blocs resource et module. Ils sont fournis par Terraform lui-même (pas par le provider).


count — créer N copies d’une ressource

resource "TYPE" "NOM" {
  count = NUMBER
 
  # Accès à l'index de la copie courante : count.index (commence à 0)
}
# Créer 3 instances identiques
resource "aws_instance" "web" {
  count         = 3
  ami           = var.ami
  instance_type = "t3.micro"
 
  tags = {
    Name = "web-${count.index}"   # web-0, web-1, web-2
  }
}
 
# Références aux instances créées :
# aws_instance.web[0].id
# aws_instance.web[1].public_ip
# aws_instance.web[*].id    ← tous les IDs (splat)
 
# count conditionnel (créer ou ne pas créer)
resource "aws_cloudwatch_alarm" "cpu" {
  count = var.env == "prod" ? 1 : 0   # créé uniquement en prod
 
  alarm_name = "high-cpu"
  ...
}

Limites de count :

  • Le nombre doit être connu avant l’apply (pas de valeur dynamique issue d’une autre ressource)
  • Si on retire un élément du milieu, Terraform renumérote et recrée tout → préférer for_each

for_each — créer une ressource par élément d’une collection

resource "TYPE" "NOM" {
  for_each = MAP_OU_SET
 
  # Accès à la clé : each.key
  # Accès à la valeur : each.value
}
# for_each avec un set de strings
resource "aws_s3_bucket" "env" {
  for_each = toset(["dev", "staging", "prod"])
  bucket   = "mon-bucket-${each.key}"
}
# Crée : aws_s3_bucket.env["dev"], aws_s3_bucket.env["staging"], aws_s3_bucket.env["prod"]
 
# for_each avec un map d'objets
locals {
  servers = {
    web = { instance_type = "t3.micro",  ami = "ami-abc" }
    api = { instance_type = "t3.small",  ami = "ami-def" }
    db  = { instance_type = "t3.medium", ami = "ami-ghi" }
  }
}
 
resource "aws_instance" "servers" {
  for_each = local.servers
 
  instance_type = each.value.instance_type
  ami           = each.value.ami
 
  tags = {
    Name = each.key   # "web", "api", "db"
  }
}
 
# Références :
# aws_instance.servers["web"].id
# aws_instance.servers["api"].public_ip
 
# for_each avec une liste de maps
resource "aws_security_group_rule" "rules" {
  for_each = { for rule in var.ingress_rules : rule.port => rule }
 
  type        = "ingress"
  from_port   = each.value.port
  to_port     = each.value.port
  protocol    = each.value.protocol
  cidr_blocks = each.value.cidr_blocks
}

count vs for_each :

countfor_each
Identifiantindex numérique (0, 1, 2…)clé string
Suppression d’un élémentRenumérote → recrée les suivants ⚠️Supprime seulement l’élément ciblé ✅
Cas d’usageN copies identiquesRessources différentes par configuration

depends_on — forcer une dépendance explicite

Terraform calcule automatiquement les dépendances via les références. depends_on sert pour les dépendances implicites non visibles dans le code.

resource "TYPE" "NOM" {
  depends_on = [RESSOURCE_1, RESSOURCE_2, MODULE]
}
# Terraform ne peut pas déduire que l'instance a besoin de l'IAM role
resource "aws_instance" "app" {
  ami           = var.ami
  instance_type = "t3.micro"
 
  # L'instance a besoin que le role IAM soit créé AVANT
  # mais aucune référence directe n'existe dans les attributs
  depends_on = [aws_iam_role_policy.app_policy]
}
 
# Forcer l'ordre entre modules
module "database" {
  source = "./modules/database"
}
 
module "application" {
  source     = "./modules/application"
  depends_on = [module.database]   # l'app démarre APRÈS la BDD
}

provider — spécifier un provider aliasé

resource "TYPE" "NOM" {
  provider = PROVIDER.ALIAS
}
# Configuration de deux providers AWS
provider "aws" {
  alias  = "primary"
  region = "eu-west-1"
}
 
provider "aws" {
  alias  = "backup"
  region = "us-east-1"
}
 
# Ressource dans la région primaire
resource "aws_s3_bucket" "primary" {
  provider = aws.primary
  bucket   = "mon-bucket-primary"
}
 
# Ressource dans la région de backup
resource "aws_s3_bucket" "backup" {
  provider = aws.backup
  bucket   = "mon-bucket-backup"
}

lifecycle — contrôler le cycle de vie d’une ressource

resource "TYPE" "NOM" {
  lifecycle {
    create_before_destroy = true|false
    prevent_destroy       = true|false
    ignore_changes        = [ATTRIBUT, ...]
    replace_triggered_by  = [RESSOURCE_OU_ATTRIBUT, ...]
    precondition { ... }
    postcondition { ... }
  }
}
resource "aws_instance" "web" {
  ami           = var.ami
  instance_type = "t3.micro"
 
  lifecycle {
    # Créer la nouvelle instance AVANT de détruire l'ancienne
    # → zero downtime lors d'un remplacement
    create_before_destroy = true
 
    # Bloquer terraform destroy (protection des ressources critiques)
    prevent_destroy = true
 
    # Ignorer les changements sur ces attributs
    # (utile quand des systèmes externes modifient ces valeurs)
    ignore_changes = [
      tags["LastModified"],   # tag mis à jour automatiquement
      user_data,              # user_data géré en dehors de Terraform
    ]
  }
}
 
# replace_triggered_by : recréer quand une autre ressource change
resource "aws_autoscaling_group" "app" {
  launch_template {
    id      = aws_launch_template.app.id
    version = aws_launch_template.app.latest_version
  }
 
  lifecycle {
    replace_triggered_by = [
      aws_launch_template.app.latest_version
    ]
  }
}
 
# Precondition / Postcondition (TF 1.2+)
resource "aws_instance" "web" {
  ami           = data.aws_ami.ubuntu.id
  instance_type = var.instance_type
 
  lifecycle {
    precondition {
      condition     = data.aws_ami.ubuntu.architecture == "x86_64"
      error_message = "L'AMI doit être x86_64."
    }
 
    postcondition {
      condition     = self.public_ip != ""
      error_message = "L'instance doit avoir une IP publique."
    }
  }
}

En relation avec