~/wiki

Terraform

Mis à jour le 2026-08-07Confiance : medium
terraformiacinfrastructuredevopscloudhcl

Infrastructure décrite en fichiers, appliquée de façon idempotente. On décrit l'état voulu, Terraform calcule les opérations pour y arriver.

Le cycle

terraform init       # télécharge les providers, configure le backend
terraform fmt        # reformate le HCL
terraform validate   # vérifie la syntaxe et les références
terraform plan       # ce qui va changer, sans rien faire
terraform apply      # applique après confirmation
terraform destroy    # supprime tout ce qui est géré
terraform plan
Terraform will perform the following actions:

  # aws_s3_bucket.artifacts will be created
  + resource "aws_s3_bucket" "artifacts" {
      + bucket = "monprojet-artifacts"
      + id     = (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.

Toujours lire le plan avant d'appliquer. La ligne à surveiller est le nombre de destroy : un changement anodin peut provoquer un remplacement de ressource.

Structure d'un projet

main.tf         ressources
variables.tf    entrées
outputs.tf      sorties
providers.tf    providers et versions
terraform.tfvars   valeurs (à ne pas committer si secrets)
terraform {
  required_version = ">= 1.9"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"        # >= 5.0, < 6.0
    }
  }
  backend "s3" {
    bucket = "mon-tfstate"
    key    = "prod/terraform.tfstate"
    region = "eu-west-3"
  }
}

provider "aws" {
  region = var.region
}

Le backend distant est le premier réflexe en équipe : sans lui, le fichier d'état vit sur un poste et deux personnes qui appliquent en même temps se marchent dessus.

Variables et sorties

variable "region" {
  type        = string
  default     = "eu-west-3"
  description = "Région AWS"
}

variable "instance_count" {
  type = number
  validation {
    condition     = var.instance_count > 0
    error_message = "Il faut au moins une instance."
  }
}

output "bucket_url" {
  value = aws_s3_bucket.artifacts.bucket_domain_name
}

output "db_password" {
  value     = random_password.db.result
  sensitive = true      # masqué dans les logs
}
terraform apply -var="region=eu-west-1"
terraform apply -var-file="prod.tfvars"
TF_VAR_region=eu-west-1 terraform apply

Ressources et références

resource "aws_s3_bucket" "artifacts" {
  bucket = "${var.project}-artifacts"

  tags = {
    Environment = var.env
    ManagedBy   = "terraform"
  }
}

resource "aws_s3_bucket_versioning" "artifacts" {
  bucket = aws_s3_bucket.artifacts.id     # crée la dépendance implicite
  versioning_configuration {
    status = "Enabled"
  }
}

Le graphe de dépendances se déduit des références. depends_on ne sert que pour les dépendances invisibles.

Boucles et conditions

resource "aws_instance" "worker" {
  count         = var.instance_count
  ami           = data.aws_ami.ubuntu.id
  instance_type = "t3.micro"
  tags = { Name = "worker-${count.index}" }
}

resource "aws_s3_bucket" "per_env" {
  for_each = toset(["dev", "staging", "prod"])
  bucket   = "monprojet-${each.key}"
}

locals {
  is_prod = var.env == "prod"
  size    = local.is_prod ? "t3.large" : "t3.micro"
}

Préférer for_each à count : avec count, supprimer un élément au milieu décale les index et Terraform détruit puis recrée tout ce qui suit.

Data sources

data "aws_ami" "ubuntu" {
  most_recent = true
  owners      = ["099720109477"]
  filter {
    name   = "name"
    values = ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"]
  }
}

État

terraform state list
terraform state show aws_s3_bucket.artifacts
terraform import aws_s3_bucket.artifacts mon-bucket-existant
terraform state rm aws_s3_bucket.artifacts     # oublie sans détruire
terraform refresh

import sert à reprendre la main sur une ressource créée à la main dans la console.

Modules

module "network" {
  source = "./modules/network"
  cidr   = "10.0.0.0/16"
}

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "5.8.1"
  name    = "prod"
}

# module.network.subnet_ids pour lire une sortie

Cibler et forcer

terraform plan -target=aws_s3_bucket.artifacts     # dépannage, pas une habitude
terraform apply -replace=aws_instance.worker[0]    # recrée une ressource
terraform apply -auto-approve                      # CI uniquement

Pièges

Le .tfstate contient des secrets en clair : jamais dans git, toujours dans un backend chiffré. Un terraform destroy sur le mauvais workspace est irréversible. Et le plan n'est valide qu'à l'instant où il est produit — si quelqu'un modifie l'infra à la main entre-temps, l'apply diverge.

See also