Terraform Import : Intégrer vos Ressources Existantes dans votre Code IaC

Importez vos ressources cloud existantes dans Terraform. Commande terraform import, import block (v1.5+), outils Terraformer et aztfexport, stratégie de migration progressive.

Vous avez adopté Terraform pour vos nouveaux projets, mais que faire de toute cette infrastructure créée manuellement via la console AWS, Azure ou GCP ? Des dizaines, voire des centaines de ressources existent déjà en production — des VPC, des instances EC2, des bases de données RDS, des buckets S3 — le tout créé à la main, au fil des années, sans aucune trace de code.

C'est précisément le problème que résout terraform import. Cette fonctionnalité permet d'intégrer des ressources cloud existantes dans votre state Terraform, pour ensuite les gérer entièrement via l'Infrastructure as Code. Dans cet article, nous allons explorer en profondeur le processus d'import, des commandes de base jusqu'aux nouvelles fonctionnalités de Terraform 1.5+ avec les blocs import, en passant par les outils d'aide et les stratégies de migration à grande échelle.

Diagramme - Terraform Import : Intégrer vos Ressources Existantes dans votre Code IaC

Pourquoi Importer vos Ressources Existantes ?

Avant de plonger dans le comment, comprenons le pourquoi. L'import de ressources existantes dans Terraform répond à plusieurs besoins critiques.

Les motivations principales

  • Traçabilité et audit : savoir exactement quelle infrastructure existe, qui l'a modifiée et quand, grâce à l'historique Git
  • Reproductibilité : pouvoir recréer un environnement identique pour le staging, le DR ou une autre région
  • Cohérence : éviter le "shadow IT" où des ressources non documentées existent dans le cloud
  • Prévention des drifts : détecter quand quelqu'un modifie manuellement une ressource qui devrait être gérée par le code
  • Collaboration : permettre à toute l'équipe de comprendre et modifier l'infrastructure via des Pull Requests
  • Conformité : répondre aux exigences réglementaires qui imposent une gestion documentée de l'infrastructure

Le défi de l'import

Il faut comprendre une limitation fondamentale : terraform import n'importe que le state, pas le code. Autrement dit, la commande enregistre la ressource existante dans le fichier state de Terraform, mais vous devez écrire manuellement le code HCL correspondant. C'est un processus en plusieurs étapes qui demande de la rigueur.

La Commande terraform import : Les Bases

La commande terraform import est disponible depuis les premières versions de Terraform. Son fonctionnement est simple mais demande une préparation minutieuse.

Syntaxe de base

# Syntaxe générale
terraform import [options] ADRESSE_RESSOURCE ID_RESSOURCE

# Exemples concrets
terraform import aws_instance.web_server i-0abc123def456789
terraform import aws_vpc.main vpc-0abc123def456789
terraform import aws_s3_bucket.assets mon-bucket-assets
terraform import aws_db_instance.production mon-instance-rds
terraform import aws_security_group.web sg-0abc123def456789

L'adresse de la ressource correspond au bloc resource dans votre code Terraform (par exemple aws_instance.web_server). L'ID de la ressource est l'identifiant unique de la ressource dans le cloud (par exemple l'ID d'une instance EC2).

Trouver l'ID d'une ressource

Chaque type de ressource a son propre format d'ID pour l'import. La documentation du provider Terraform indique toujours l'ID attendu :

# AWS - Les IDs varient selon le type de ressource
# EC2 Instance : ID de l'instance
terraform import aws_instance.example i-0abc123def456789

# S3 Bucket : nom du bucket
terraform import aws_s3_bucket.example mon-bucket

# RDS Instance : identifiant de l'instance
terraform import aws_db_instance.example mon-instance-rds

# IAM Role : nom du rôle
terraform import aws_iam_role.example mon-role

# Security Group : ID du security group
terraform import aws_security_group.example sg-0abc123def456789

# Route 53 Record : zone_id_type_name (format composé)
terraform import aws_route53_record.example Z0123456789_example.com_A

# Ressources avec des IDs composés
terraform import aws_route_table_association.example subnet-0abc123/rtb-0def456

Le Processus d'Import Étape par Étape

L'import de ressources suit un processus rigoureux en plusieurs étapes. Prenons un exemple concret : importer une instance EC2 existante.

Étape 1 : Identifier la ressource à importer

Commencez par recenser les informations sur la ressource existante via la console AWS ou l'AWS CLI :

# Obtenir les détails de l'instance EC2
aws ec2 describe-instances --instance-ids i-0abc123def456789 --output json

# Résultat (simplifié)
{
  "Reservations": [{
    "Instances": [{
      "InstanceId": "i-0abc123def456789",
      "InstanceType": "t3.large",
      "ImageId": "ami-0abcdef1234567890",
      "SubnetId": "subnet-0abc123",
      "VpcId": "vpc-0def456",
      "SecurityGroups": [
        {"GroupId": "sg-0abc123", "GroupName": "web-server-sg"}
      ],
      "Tags": [
        {"Key": "Name", "Value": "prod-web-server"},
        {"Key": "Environment", "Value": "production"}
      ],
      "KeyName": "prod-key",
      "IamInstanceProfile": {
        "Arn": "arn:aws:iam::123456789012:instance-profile/web-server-profile"
      }
    }]
  }]
}

Étape 2 : Écrire le bloc resource minimal

Créez un bloc resource dans votre code Terraform. À ce stade, un bloc minimal suffit :

# imported_resources.tf
resource "aws_instance" "web_server" {
  # Les attributs seront complétés après l'import
  # Pour l'instant, un bloc vide ou minimal suffit
  ami           = "ami-0abcdef1234567890"
  instance_type = "t3.large"
}

Étape 3 : Exécuter terraform import

# S'assurer que terraform init a été exécuté
terraform init

# Importer la ressource
terraform import aws_instance.web_server i-0abc123def456789

# Sortie attendue
# aws_instance.web_server: Importing from ID "i-0abc123def456789"...
# aws_instance.web_server: Import prepared!
#   Prepared aws_instance for import
# aws_instance.web_server: Refreshing state... [id=i-0abc123def456789]
# 
# Import successful!
# 
# The resources that were imported are shown above.

Étape 4 : Exécuter terraform plan et ajuster le code

C'est l'étape la plus importante et la plus laborieuse. Après l'import, exécutez terraform plan pour voir les différences entre votre code et l'état réel de la ressource :

terraform plan

# Le plan va montrer des changements car votre code ne reflète pas
# encore tous les attributs de la ressource importée

Vous devez alors ajuster votre code pour qu'il corresponde exactement à l'état réel. L'objectif est d'obtenir un terraform plan sans aucun changement :

# imported_resources.tf - Version complète après ajustement
resource "aws_instance" "web_server" {
  ami                    = "ami-0abcdef1234567890"
  instance_type          = "t3.large"
  subnet_id              = "subnet-0abc123"
  vpc_security_group_ids = [aws_security_group.web.id]
  key_name               = "prod-key"
  iam_instance_profile   = "web-server-profile"

  root_block_device {
    volume_type           = "gp3"
    volume_size           = 50
    encrypted             = true
    delete_on_termination = true
  }

  metadata_options {
    http_endpoint               = "enabled"
    http_tokens                 = "required"
    http_put_response_hop_limit = 1
  }

  tags = {
    Name        = "prod-web-server"
    Environment = "production"
  }

  lifecycle {
    # Empêcher la destruction accidentelle d'une ressource importée
    prevent_destroy = true
  }
}

Étape 5 : Vérifier avec terraform plan

terraform plan

# Sortie souhaitée :
# No changes. Your infrastructure matches the configuration.
#
# Terraform has compared your real infrastructure against your
# configuration and found no differences, so no changes are needed.

Si le plan indique encore des changements, ajustez votre code ou utilisez ignore_changes pour les attributs qui ne doivent pas être gérés par Terraform :

resource "aws_instance" "web_server" {
  # ... attributs ...

  lifecycle {
    prevent_destroy = true
    ignore_changes = [
      # Ignorer les changements faits en dehors de Terraform
      user_data,
      ami,  # Si l'AMI est gérée par un autre processus
    ]
  }
}

Import Block : La Révolution de Terraform 1.5+

Depuis Terraform 1.5 (sorti en juin 2023), une nouvelle approche d'import est disponible : les blocs import. Cette fonctionnalité transforme radicalement le workflow d'import en le rendant déclaratif et planifiable.

Syntaxe du bloc import

# imports.tf
import {
  to = aws_instance.web_server
  id = "i-0abc123def456789"
}

import {
  to = aws_vpc.main
  id = "vpc-0abc123def456789"
}

import {
  to = aws_s3_bucket.assets
  id = "mon-bucket-assets"
}

import {
  to = aws_security_group.web
  id = "sg-0abc123def456789"
}

Les avantages par rapport à terraform import

  • Planifiable : terraform plan montre l'import avant de l'exécuter
  • Déclaratif : les imports sont du code versionnable dans Git
  • Batch : importer plusieurs ressources en un seul terraform apply
  • Réversible : supprimer le bloc import pour annuler (avant le apply)
  • Génération de code : avec -generate-config-out, Terraform peut générer le code HCL

Génération automatique du code (Terraform 1.5+)

La fonctionnalité la plus excitante est la génération automatique de code. Terraform peut examiner la ressource importée et générer le bloc HCL correspondant :

# Écrire les blocs import sans écrire les blocs resource
# imports.tf
import {
  to = aws_instance.web_server
  id = "i-0abc123def456789"
}

# Générer le code automatiquement
terraform plan -generate-config-out=generated_resources.tf

# Terraform va :
# 1. Lire la ressource depuis AWS
# 2. Générer le fichier generated_resources.tf avec le code HCL
# 3. Afficher le plan d'import

Le fichier généré ressemble à ceci :

# generated_resources.tf (généré automatiquement)
resource "aws_instance" "web_server" {
  ami                         = "ami-0abcdef1234567890"
  associate_public_ip_address = false
  availability_zone           = "eu-west-1a"
  cpu_core_count              = 2
  cpu_threads_per_core        = 2
  disable_api_stop            = false
  disable_api_termination     = false
  ebs_optimized               = true
  iam_instance_profile        = "web-server-profile"
  instance_type               = "t3.large"
  key_name                    = "prod-key"
  monitoring                  = false
  subnet_id                   = "subnet-0abc123"
  vpc_security_group_ids      = ["sg-0abc123"]

  capacity_reservation_specification {
    capacity_reservation_preference = "open"
  }

  metadata_options {
    http_endpoint               = "enabled"
    http_put_response_hop_limit = 1
    http_tokens                 = "required"
    instance_metadata_tags      = "disabled"
  }

  root_block_device {
    delete_on_termination = true
    encrypted             = true
    iops                  = 3000
    throughput            = 125
    volume_size           = 50
    volume_type           = "gp3"
  }

  tags = {
    Environment = "production"
    Name        = "prod-web-server"
  }

  tags_all = {
    Environment = "production"
    Name        = "prod-web-server"
  }
}

Workflow complet avec les blocs import

# 1. Écrire les blocs import
cat > imports.tf <<'EOF'
import {
  to = aws_instance.web_server
  id = "i-0abc123def456789"
}
EOF

# 2. Générer le code (optionnel mais recommandé)
terraform plan -generate-config-out=generated.tf

# 3. Nettoyer et ajuster le code généré
# Remplacer les valeurs hardcodées par des variables
# Supprimer les attributs calculés inutiles
# Ajouter des lifecycle rules si nécessaire

# 4. Vérifier le plan
terraform plan
# Doit afficher : "1 to import, 0 to add, 0 to change, 0 to destroy"

# 5. Appliquer l'import
terraform apply

# 6. Supprimer les blocs import (ils ne sont plus nécessaires)
rm imports.tf

# 7. Vérifier que tout est clean
terraform plan
# Doit afficher : "No changes"

Limites de l'Import Terraform

L'import Terraform, bien qu'essentiel, a des limitations qu'il est important de connaître pour éviter les mauvaises surprises.

Limitations techniques

  • Pas tous les attributs sont importés : certains attributs en écriture seule (comme les mots de passe) ne peuvent pas être lus depuis l'API du cloud et ne seront pas dans le state
  • Pas de support pour toutes les ressources : certaines ressources de certains providers ne supportent pas encore l'import
  • Relations complexes : les dépendances entre ressources ne sont pas automatiquement détectées ; vous devez les reconstruire manuellement dans le code
  • Modules : importer dans un module nécessite d'utiliser le chemin complet comme module.vpc.aws_subnet.public[0]
  • for_each et count : l'import dans des ressources avec for_each ou count nécessite une syntaxe spécifique

Import avec for_each et count

# Import avec count
terraform import 'aws_subnet.public[0]' subnet-0abc123
terraform import 'aws_subnet.public[1]' subnet-0def456

# Import avec for_each
terraform import 'aws_subnet.public["eu-west-1a"]' subnet-0abc123
terraform import 'aws_subnet.public["eu-west-1b"]' subnet-0def456

Avec les blocs import :

import {
  to = aws_subnet.public["eu-west-1a"]
  id = "subnet-0abc123"
}

import {
  to = aws_subnet.public["eu-west-1b"]
  id = "subnet-0def456"
}

Limitations de la génération de code

  • Le code généré est souvent verbeux avec des attributs inutiles
  • Les références entre ressources sont remplacées par des valeurs littérales
  • Les variables et locals ne sont pas créés automatiquement
  • Les modules ne sont pas générés ; tout est en ressources plates

Outils d'Aide à l'Import

Pour les migrations à grande échelle, la commande terraform import manuelle est fastidieuse. Heureusement, plusieurs outils communautaires automatisent le processus.

Terraformer (Google)

Terraformer est un outil open source développé par Google qui génère automatiquement le code Terraform et le state à partir d'une infrastructure existante :

# Installation
brew install terraformer

# Importer toutes les instances EC2
terraformer import aws --resources=ec2_instance --regions=eu-west-1

# Importer un ensemble de ressources
terraformer import aws \
  --resources=vpc,subnet,security_group,ec2_instance,s3 \
  --regions=eu-west-1 \
  --profile=production

# Importer avec des filtres
terraformer import aws \
  --resources=ec2_instance \
  --filter="Name=tags.Environment;Value=production" \
  --regions=eu-west-1

Terraformer génère une structure de répertoires avec le code HCL et les fichiers state :

generated/
└── aws/
    ├── ec2_instance/
    │   ├── instance.tf
    │   ├── outputs.tf
    │   ├── provider.tf
    │   └── terraform.tfstate
    ├── vpc/
    │   ├── vpc.tf
    │   ├── outputs.tf
    │   ├── provider.tf
    │   └── terraform.tfstate
    └── s3/
        ├── s3_bucket.tf
        ├── outputs.tf
        ├── provider.tf
        └── terraform.tfstate

aztfexport (Microsoft)

Pour Azure, Microsoft fournit aztfexport, un outil dédié à l'export des ressources Azure vers Terraform :

# Installation
brew install aztfexport

# Exporter un resource group entier
aztfexport resource-group mon-resource-group

# Exporter une ressource spécifique
aztfexport resource /subscriptions/.../resourceGroups/.../providers/Microsoft.Compute/virtualMachines/ma-vm

# Mode interactif
aztfexport resource-group mon-resource-group --non-interactive=false

gcloud terraform vet (Google Cloud)

Pour GCP, l'outil gcloud propose des fonctionnalités d'export :

# Exporter un projet GCP
gcloud beta resource-config bulk-export \
  --resource-format=terraform \
  --project=mon-projet-gcp

Stratégie de Migration Progressive

Migrer une infrastructure entière vers Terraform ne se fait pas en un jour. Voici une stratégie éprouvée pour une migration progressive et sûre.

Phase 1 : Inventaire et priorisation

# Lister toutes les ressources existantes
aws resourcegroupstaggingapi get-resources \
  --region eu-west-1 \
  --output json > inventory.json

# Compter par type de ressource
aws resourcegroupstaggingapi get-resources \
  --region eu-west-1 \
  --query 'ResourceTagMappingList[].ResourceARN' \
  --output text | \
  sed 's/.*://; s/\/.*//' | sort | uniq -c | sort -rn

Priorisez les ressources par criticité et dépendance :

  1. Réseau (VPC, subnets, security groups) : fondation de tout le reste
  2. IAM (rôles, politiques) : nécessaire pour les autres ressources
  3. Stockage (S3, EBS) : données persistantes
  4. Base de données (RDS, DynamoDB) : critique mais complexe à migrer
  5. Compute (EC2, ECS, Lambda) : souvent le plus volumineux
  6. DNS et certificats : Route 53, ACM

Phase 2 : Import par couches

Importez par couches en commençant par les fondations :

# Couche 1 : Réseau
# network/imports.tf
import {
  to = aws_vpc.main
  id = "vpc-0abc123"
}

import {
  to = aws_subnet.public["eu-west-1a"]
  id = "subnet-0abc123"
}

import {
  to = aws_subnet.public["eu-west-1b"]
  id = "subnet-0def456"
}

import {
  to = aws_subnet.private["eu-west-1a"]
  id = "subnet-0ghi789"
}

import {
  to = aws_subnet.private["eu-west-1b"]
  id = "subnet-0jkl012"
}

import {
  to = aws_internet_gateway.main
  id = "igw-0abc123"
}

import {
  to = aws_nat_gateway.main
  id = "nat-0abc123"
}

import {
  to = aws_route_table.public
  id = "rtb-0abc123"
}

import {
  to = aws_route_table.private
  id = "rtb-0def456"
}
# Générer le code pour la couche réseau
cd network/
terraform plan -generate-config-out=generated_network.tf

# Nettoyer, ajuster, tester
terraform plan  # Vérifier : 0 changes

terraform apply  # Importer

Phase 3 : Vérification et stabilisation

Après chaque lot d'imports :

# Vérifier qu'il n'y a aucun changement prévu
terraform plan

# Si des changements apparaissent :
# 1. Ajuster le code pour correspondre à l'état réel
# 2. OU utiliser ignore_changes si l'attribut est géré ailleurs
# 3. OU accepter le changement si c'est une normalisation souhaitée

# Vérifier le state
terraform state list
terraform state show aws_vpc.main

Phase 4 : Refactoring progressif

Une fois importé, le code est souvent brut. Refactorisez progressivement :

# Avant : valeurs hardcodées issues de l'import
resource "aws_instance" "web" {
  ami           = "ami-0abcdef1234567890"
  instance_type = "t3.large"
  subnet_id     = "subnet-0abc123"
}

# Après : variables et références
resource "aws_instance" "web" {
  ami           = var.ami_id
  instance_type = var.instance_type
  subnet_id     = module.networking.private_subnet_ids[0]

  tags = merge(local.common_tags, {
    Name = "${var.project}-${var.environment}-web"
    Role = "webserver"
  })
}

Exemple Pratique Complet : Import d'une Infrastructure AWS

Voici un exemple complet et réaliste d'import d'une infrastructure AWS existante composée d'un VPC, d'un security group, d'une instance EC2 et d'un bucket S3.

Étape 1 : Recenser les ressources existantes

# Lister les VPCs
aws ec2 describe-vpcs --query 'Vpcs[*].[VpcId,CidrBlock,Tags[?Key==`Name`].Value|[0]]' --output table

# Résultat :
# | vpc-0abc123 | 10.0.0.0/16 | prod-vpc |

# Lister les Security Groups du VPC
aws ec2 describe-security-groups \
  --filters "Name=vpc-id,Values=vpc-0abc123" \
  --query 'SecurityGroups[*].[GroupId,GroupName]' \
  --output table

# Lister les instances EC2
aws ec2 describe-instances \
  --filters "Name=vpc-id,Values=vpc-0abc123" \
  --query 'Reservations[*].Instances[*].[InstanceId,InstanceType,State.Name,Tags[?Key==`Name`].Value|[0]]' \
  --output table

# Lister les buckets S3
aws s3 ls

Étape 2 : Créer la structure du projet

mkdir -p import-project
cd import-project

# Créer les fichiers de base
touch providers.tf imports.tf variables.tf
# providers.tf
terraform {
  required_version = ">= 1.7.0"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.30"
    }
  }

  backend "s3" {
    bucket         = "mon-entreprise-terraform-state"
    key            = "imported/prod/terraform.tfstate"
    region         = "eu-west-1"
    encrypt        = true
    dynamodb_table = "terraform-state-lock"
  }
}

provider "aws" {
  region = "eu-west-1"
}

Étape 3 : Écrire les blocs import

# imports.tf
import {
  to = aws_vpc.prod
  id = "vpc-0abc123"
}

import {
  to = aws_security_group.web
  id = "sg-0def456"
}

import {
  to = aws_instance.web_server
  id = "i-0ghi789"
}

import {
  to = aws_s3_bucket.assets
  id = "prod-company-assets"
}

Étape 4 : Générer et ajuster le code

# Initialiser Terraform
terraform init

# Générer le code
terraform plan -generate-config-out=generated.tf

# Examiner le code généré
cat generated.tf

Nettoyez ensuite le code généré pour le rendre maintenable :

# main.tf (version nettoyée du code généré)
locals {
  environment = "prod"
  project     = "mon-projet"

  common_tags = {
    Environment = local.environment
    Project     = local.project
    ManagedBy   = "terraform"
  }
}

resource "aws_vpc" "prod" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_support   = true
  enable_dns_hostnames = true

  tags = merge(local.common_tags, {
    Name = "${local.project}-${local.environment}-vpc"
  })

  lifecycle {
    prevent_destroy = true
  }
}

resource "aws_security_group" "web" {
  name        = "web-server-sg"
  description = "Security group pour les serveurs web"
  vpc_id      = aws_vpc.prod.id

  ingress {
    description = "HTTP"
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    description = "HTTPS"
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    description = "SSH depuis le VPN"
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["10.10.0.0/16"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = merge(local.common_tags, {
    Name = "${local.project}-${local.environment}-web-sg"
  })
}

resource "aws_instance" "web_server" {
  ami                    = "ami-0abcdef1234567890"
  instance_type          = "t3.large"
  subnet_id              = "subnet-0abc123"  # À remplacer par une référence après import du subnet
  vpc_security_group_ids = [aws_security_group.web.id]
  key_name               = "prod-key"

  root_block_device {
    volume_type           = "gp3"
    volume_size           = 50
    encrypted             = true
    delete_on_termination = true
  }

  tags = merge(local.common_tags, {
    Name = "${local.project}-${local.environment}-web"
    Role = "webserver"
  })

  lifecycle {
    prevent_destroy = true
    ignore_changes  = [ami]  # L'AMI sera mise à jour par un autre processus
  }
}

resource "aws_s3_bucket" "assets" {
  bucket = "prod-company-assets"

  tags = merge(local.common_tags, {
    Name = "prod-company-assets"
  })

  lifecycle {
    prevent_destroy = true
  }
}

resource "aws_s3_bucket_versioning" "assets" {
  bucket = aws_s3_bucket.assets.id

  versioning_configuration {
    status = "Enabled"
  }
}

resource "aws_s3_bucket_server_side_encryption_configuration" "assets" {
  bucket = aws_s3_bucket.assets.id

  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm = "AES256"
    }
  }
}

Étape 5 : Valider et appliquer

# Vérifier le plan
terraform plan

# Résultat attendu :
# Plan: 4 to import, 0 to add, 0 to change, 0 to destroy.

# Appliquer l'import
terraform apply

# Vérifier post-import
terraform plan
# Résultat : No changes. Your infrastructure matches the configuration.

# Supprimer les blocs import (plus nécessaires après l'apply)
rm imports.tf

# Vérification finale
terraform plan
# Résultat : No changes.

Import en Masse : Stratégies et Scripts

Pour les migrations à grande échelle avec des centaines de ressources, l'automatisation est indispensable.

Script d'import automatisé

#!/bin/bash
# import_resources.sh
# Script pour générer les blocs import à partir d'un inventaire AWS

set -euo pipefail

REGION="eu-west-1"
OUTPUT_FILE="imports.tf"

echo "# Blocs import générés automatiquement" > "$OUTPUT_FILE"
echo "# Date : $(date)" >> "$OUTPUT_FILE"
echo "" >> "$OUTPUT_FILE"

# Importer les VPCs
echo "=== Import des VPCs ==="
aws ec2 describe-vpcs --region "$REGION" \
  --query 'Vpcs[*].[VpcId,Tags[?Key==`Name`].Value|[0]]' \
  --output text | while read -r vpc_id vpc_name; do

  resource_name=$(echo "$vpc_name" | tr '-' '_' | tr '[:upper:]' '[:lower:]')
  cat >> "$OUTPUT_FILE" <> "$OUTPUT_FILE" <> "$OUTPUT_FILE" <

Pipeline CI/CD pour l'import

# .gitlab-ci.yml pour la migration
stages:
  - inventory
  - generate
  - review
  - import

inventory:
  stage: inventory
  script:
    - ./scripts/import_resources.sh
  artifacts:
    paths:
      - imports.tf

generate:
  stage: generate
  script:
    - terraform init
    - terraform plan -generate-config-out=generated.tf
  artifacts:
    paths:
      - generated.tf
      - imports.tf

review:
  stage: review
  script:
    - echo "Revue manuelle du code généré requise"
    - cat generated.tf
  when: manual

import:
  stage: import
  script:
    - terraform init
    - terraform apply -auto-approve
  when: manual
  dependencies:
    - generate

Bonnes Pratiques pour l'Import

Checklist avant l'import

  • Avoir un remote backend configuré et fonctionnel
  • Faire un snapshot ou backup de l'infrastructure existante
  • Documenter toutes les ressources à importer avec leurs IDs
  • Planifier l'import par couches (réseau, puis IAM, puis compute, etc.)
  • Tester d'abord sur un environnement non-production
  • Informer l'équipe que des imports sont en cours (pour éviter les modifications manuelles pendant l'import)

Checklist après l'import

  • Vérifier que terraform plan ne montre aucun changement
  • Nettoyer le code généré (remplacer les valeurs hardcodées par des variables)
  • Ajouter prevent_destroy sur les ressources critiques
  • Configurer ignore_changes pour les attributs gérés ailleurs
  • Supprimer les blocs import après le apply
  • Commiter le code nettoyé et le fichier .terraform.lock.hcl
  • Mettre en place une détection de drift régulière

Pièges à éviter

  • Ne jamais importer sans lire la documentation du provider : chaque ressource a un format d'ID spécifique
  • Ne pas importer et modifier en même temps : d'abord importer avec un plan clean, puis modifier dans des commits séparés
  • Attention aux ressources avec des dépendances : importer dans le bon ordre pour que les références fonctionnent
  • Ne pas oublier les ressources associées : un bucket S3 a souvent des policies, du versioning, du chiffrement en ressources séparées dans Terraform
  • Tester avec terraform plan avant chaque apply : un plan qui montre des destructions après un import signifie que votre code ne correspond pas à la réalité

Conclusion

L'import de ressources existantes dans Terraform est une étape incontournable pour toute organisation qui adopte l'Infrastructure as Code progressivement. Que vous utilisiez la commande classique terraform import, les nouveaux blocs import de Terraform 1.5+, ou des outils comme Terraformer et aztfexport, le processus suit toujours le même schéma : identifier, importer, ajuster, valider.

Les points clés à retenir sont les suivants. Commencez par les couches fondamentales (réseau, IAM) avant les ressources applicatives. Utilisez les blocs import avec -generate-config-out pour accélérer le processus. Nettoyez toujours le code généré pour le rendre maintenable. Ajoutez prevent_destroy sur les ressources critiques. Validez chaque lot avec terraform plan avant de passer au suivant.

La migration vers l'IaC est un investissement qui porte ses fruits sur le long terme. Chaque ressource importée est une ressource de plus qui bénéficie de la traçabilité, de la reproductibilité et de la collaboration offertes par Terraform et le workflow GitOps.

Cet article conclut notre série approfondie sur Terraform. Vous disposez maintenant de toutes les connaissances nécessaires pour gérer votre infrastructure de manière professionnelle, des bonnes pratiques à l'intégration Kubernetes en passant par la migration de l'existant. Bonne infrastructure as code !

Vous vous êtes abonné avec succès à CodeClan
Parfait ! Ensuite, complétez le paiement pour obtenir un accès complet à tout le contenu premium.
Erreur ! Impossible de s'inscrire. Lien invalide.
Bienvenue ! Vous vous êtes connecté avec succès.
Erreur ! Impossible de se connecter. Veuillez réessayer.
Succès ! Votre compte est entièrement activé, vous avez maintenant accès à tout le contenu.
Erreur ! Le paiement Stripe a échoué.
Succès ! Vos informations de facturation sont mises à jour.
Erreur ! La mise à jour des informations de facturation a échoué.