TerraformDevOpsIaCAWS

Terraform remote state : partager l'état entre équipes

22 août 2026 · Sphinx-Digital

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.