Par défaut, Terraform stocke son state dans un fichier terraform.tfstate local. Dès qu’une deuxième personne ou un pipeline CI touche la même infrastructure, c’est la recette pour des conflits et des corruptions de state. Le remote state résout ça structurellement.
Pourquoi le state local est dangereux en équipe
Le state Terraform contient la représentation exacte de votre infrastructure : IDs de ressources, valeurs sensibles, dépendances. Si deux personnes appliquent en parallèle depuis leur machine, l’une écrase le state de l’autre — et Terraform perd la trace de la moitié de l’infrastructure.
Backend S3 + DynamoDB : la solution de référence sur AWS
# versions.tf
terraform {
required_version = ">= 1.6"
backend "s3" {
bucket = "sphinx-digital-terraform-state"
key = "production/networking/terraform.tfstate"
region = "eu-west-1"
encrypt = true
kms_key_id = "arn:aws:kms:eu-west-1:123456789:key/abc-def"
# Verrouillage via DynamoDB
dynamodb_table = "terraform-state-lock"
}
}
S3 stocke le state (versionné, chiffré). DynamoDB gère le verrou : quand quelqu’un lance un apply, une entrée est créée dans DynamoDB. Tout autre apply concurrent voit le verrou et attend ou abandonne.
Créer l’infrastructure du backend (à faire une seule fois)
# bootstrap/main.tf — à appliquer avec un state local temporaire
resource "aws_s3_bucket" "terraform_state" {
bucket = "sphinx-digital-terraform-state"
}
resource "aws_s3_bucket_versioning" "state" {
bucket = aws_s3_bucket.terraform_state.id
versioning_configuration {
status = "Enabled" # historique de toutes les versions du state
}
}
resource "aws_s3_bucket_server_side_encryption_configuration" "state" {
bucket = aws_s3_bucket.terraform_state.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "aws:kms"
kms_master_key_id = aws_kms_key.terraform.arn
}
}
}
resource "aws_s3_bucket_public_access_block" "state" {
bucket = aws_s3_bucket.terraform_state.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
resource "aws_dynamodb_table" "terraform_lock" {
name = "terraform-state-lock"
billing_mode = "PAY_PER_REQUEST"
hash_key = "LockID"
attribute {
name = "LockID"
type = "S"
}
}
Organiser les states par périmètre
Un seul state pour toute l’infrastructure est risqué — un apply sur les VPCs peut bloquer les déploiements applicatifs. Découpez par périmètre :
states/
├── networking/ → VPC, subnets, peering
│ └── terraform.tfstate
├── security/ → IAM, Security Groups partagés
│ └── terraform.tfstate
├── databases/ → RDS, ElastiCache
│ └── terraform.tfstate
└── applications/
├── api/ → ECS service, ALB
│ └── terraform.tfstate
└── workers/
└── terraform.tfstate
# Chaque périmètre a sa clé unique dans le backend
backend "s3" {
bucket = "sphinx-digital-terraform-state"
key = "production/networking/terraform.tfstate" # ← clé unique
}
Partager des valeurs entre states avec remote_state
Le périmètre applications/api a besoin de l’ID du VPC créé dans networking. Plutôt que de dupliquer la valeur, utilisez terraform_remote_state :
# Dans networking/outputs.tf
output "vpc_id" {
value = aws_vpc.main.id
}
output "private_subnet_ids" {
value = [for s in aws_subnet.private : s.id]
}
# Dans applications/api/main.tf
data "terraform_remote_state" "networking" {
backend = "s3"
config = {
bucket = "sphinx-digital-terraform-state"
key = "production/networking/terraform.tfstate"
region = "eu-west-1"
}
}
resource "aws_ecs_service" "api" {
network_configuration {
subnets = data.terraform_remote_state.networking.outputs.private_subnet_ids
}
}
Sécurité du state : il contient des secrets
Le state Terraform stocke en clair les valeurs de toutes vos ressources — y compris les mots de passe RDS, les clés d’accès, les certificats. Plusieurs protections à mettre en place :
# IAM policy stricte : seuls les rôles CI/CD et admins accèdent au bucket
resource "aws_s3_bucket_policy" "state" {
bucket = aws_s3_bucket.terraform_state.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Deny"
Principal = "*"
Action = "s3:*"
Resource = "${aws_s3_bucket.terraform_state.arn}/*"
Condition = {
StringNotLike = {
"aws:PrincipalArn" = [
"arn:aws:iam::123456789:role/terraform-ci",
"arn:aws:iam::123456789:role/terraform-admin"
]
}
}
}
]
})
}
Gérer un state corrompu ou verrouillé
# Voir l'état du verrou
terraform force-unlock <LOCK_ID>
# Si une ressource a été supprimée manuellement et crée des erreurs
terraform state rm aws_instance.web
# Importer une ressource existante qui n'est pas dans le state
terraform import aws_instance.web i-0abc123def456789
# Voir ce qui est dans le state actuel
terraform state list
terraform state show aws_vpc.main
Notre formation Terraform couvre le remote state et la gestion multi-équipes avec des ateliers sur des environnements AWS réels.