Module 1 : Introduction Ă Terraform
Durée estimée : 45 minutes
Objectifs du Module
Ă la fin de ce module, vous serez capable de :
- Comprendre le concept d'Infrastructure as Code
- Ăcrire du code HCL (HashiCorp Configuration Language)
- Expliquer le rĂŽle des providers
- Gérer le state Terraform
- Exécuter le workflow plan/apply/destroy
1. Infrastructure as Code (IaC)

1.1 Le ProblĂšme de la Gestion Manuelle

1.2 La Solution : Infrastructure as Code
graph TB
subgraph "Infrastructure as Code"
CODE["đ Code (HCL, YAML)"]
VCS["đ Git Repository"]
CICD["đ CI/CD Pipeline"]
TF["đ§ Terraform"]
INFRA["đïž Infrastructure"]
CODE --> VCS
VCS --> CICD
CICD --> TF
TF -->|"API"| INFRA
end
subgraph "Bénéfices"
B1["â
Reproductible"]
B2["â
Versionné"]
B3["â
Code Review"]
B4["â
Audit trail"]
B5["â
Rapide"]
end
INFRA --> B1
INFRA --> B2
INFRA --> B3
INFRA --> B4
INFRA --> B5
style CODE fill:#9C27B0,color:#fff
style B1 fill:#4caf50,color:#fff
style B2 fill:#4caf50,color:#fff
1.3 Terraform vs Autres Outils IaC
| Outil | Type | Approche | Multi-Cloud | State |
|---|---|---|---|---|
| Terraform | DĂ©claratif | Plan â Apply | â Oui | Oui |
| Ansible | ImpĂ©ratif/DĂ©claratif | Tasks sĂ©quentielles | â Oui | Non |
| Pulumi | ImpĂ©ratif | Code rĂ©el (Python, Go) | â Oui | Oui |
| CloudFormation | DĂ©claratif | Stacks | â AWS only | Oui (implicite) |
| ARM/Bicep | DĂ©claratif | Templates | â Azure only | Oui (implicite) |
Pourquoi Terraform pour ACI ?
- Provider officiel Cisco pour ACI
- Déclaratif : on décrit l'état souhaité
- Plan : prévisualisation avant application
- Multi-plateforme : ACI + Cloud + autres
2. Concepts Fondamentaux Terraform

2.1 Architecture Terraform

graph TB
subgraph "Terraform Core"
TF["đ§ Terraform CLI"]
PARSER["đ HCL Parser"]
GRAPH["đ Dependency Graph"]
PLAN["đ Plan Engine"]
end
subgraph "Providers"
P_ACI["đ ACI Provider"]
P_AWS["âïž AWS Provider"]
P_AZURE["âïž Azure Provider"]
end
subgraph "State"
STATE["đŸ terraform.tfstate"]
end
subgraph "Infrastructure"
ACI["đ ACI Fabric"]
AWS["âïž AWS"]
AZURE["âïž Azure"]
end
TF --> PARSER --> GRAPH --> PLAN
PLAN --> P_ACI --> ACI
PLAN --> P_AWS --> AWS
PLAN --> P_AZURE --> AZURE
PLAN <--> STATE
style TF fill:#9C27B0,color:#fff
style P_ACI fill:#2196F3,color:#fff
2.2 Concepts Clés
| Concept | Description | Exemple |
|---|---|---|
| Provider | Plugin pour communiquer avec une API | aci, aws, azurerm |
| Resource | Objet d'infrastructure à créer | aci_tenant, aws_instance |
| Data Source | Lecture d'info existante (read-only) | data.aci_tenant.existing |
| Variable | ParamÚtre d'entrée | var.tenant_name |
| Output | Valeur de sortie | output.tenant_dn |
| Module | Groupe de ressources réutilisable | module.tenant |
| State | Ătat actuel de l'infrastructure | terraform.tfstate |
2.3 Workflow Terraform

sequenceDiagram
participant User as đ€ Utilisateur
participant TF as đ§ Terraform
participant State as đŸ State
participant API as đ API (ACI)
User->>TF: terraform init
TF->>TF: Télécharge providers
User->>TF: terraform plan
TF->>State: Lit l'état actuel
TF->>API: Interroge l'API
TF->>User: Affiche les changements prévus
User->>TF: terraform apply
TF->>API: Applique les changements
API->>TF: Confirme
TF->>State: Met Ă jour le state
User->>TF: terraform destroy
TF->>API: Supprime les ressources
TF->>State: Met Ă jour le state
3. Le Langage HCL
3.1 Syntaxe de Base
# Commentaire sur une ligne
/*
Commentaire
multi-lignes
*/
# Bloc de configuration
resource "type_ressource" "nom_local" {
argument1 = "valeur"
argument2 = 42
argument3 = true
bloc_nested {
nested_arg = "valeur"
}
}
3.2 Types de Données
# String
name = "mon-tenant"
# Number
vlan_id = 100
# Boolean
enabled = true
# List
vlans = [100, 101, 102]
# Map
tags = {
environment = "production"
owner = "network-team"
}
# Object
config = {
name = "web-server"
port = 443
enabled = true
}
3.3 Références et Interpolation
# Référence à une variable
tenant_name = var.tenant_name
# Référence à une ressource
vrf_dn = aci_vrf.production.id
# Référence à un data source
existing_tenant = data.aci_tenant.existing.id
# Interpolation dans une string
description = "Tenant for ${var.environment} environment"
# Fonctions
upper_name = upper(var.tenant_name)
3.4 Exemple Complet
# variables.tf
variable "tenant_name" {
description = "Nom du tenant ACI"
type = string
default = "Demo-Tenant"
}
variable "environment" {
description = "Environnement (dev, staging, prod)"
type = string
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "Environment must be dev, staging, or prod."
}
}
# main.tf
terraform {
required_providers {
aci = {
source = "CiscoDevNet/aci"
version = "~> 2.0"
}
}
}
provider "aci" {
username = var.apic_username
password = var.apic_password
url = var.apic_url
insecure = true
}
resource "aci_tenant" "main" {
name = var.tenant_name
description = "Tenant for ${var.environment}"
annotation = "orchestrator:terraform"
}
# outputs.tf
output "tenant_dn" {
description = "DN du tenant créé"
value = aci_tenant.main.id
}
4. Le State Terraform

4.1 Qu'est-ce que le State ?
graph TB
subgraph "State = Source of Truth"
STATE["đŸ terraform.tfstate"]
subgraph "Contenu"
MAPPING["đ Mapping code â ressources rĂ©elles"]
META["đ MĂ©tadonnĂ©es (ID, attributs)"]
DEPS["đ DĂ©pendances"]
end
end
CODE["đ Code HCL"]
INFRA["đïž Infrastructure RĂ©elle"]
CODE --> STATE
STATE --> INFRA
STATE --> MAPPING
STATE --> META
STATE --> DEPS
style STATE fill:#FF9800800800,color:#fff
4.2 State Local vs Remote
graph TB
subgraph "State Local (défaut)"
LOCAL["đ» terraform.tfstate<br/>sur votre machine"]
PROBLEM1["â Pas de collaboration"]
PROBLEM2["â Risque de perte"]
PROBLEM3["â Pas de locking"]
end
subgraph "State Remote (recommandé)"
REMOTE["âïž Backend distant<br/>(S3, Azure Blob, GCS, Consul)"]
BENEFIT1["â
Collaboration équipe"]
BENEFIT2["â
Sauvegardé"]
BENEFIT3["â
Locking"]
end
LOCAL --> PROBLEM1
LOCAL --> PROBLEM2
LOCAL --> PROBLEM3
REMOTE --> BENEFIT1
REMOTE --> BENEFIT2
REMOTE --> BENEFIT3
style LOCAL fill:#f44336,color:#fff
style REMOTE fill:#4caf50,color:#fff
4.3 Configuration Backend Remote
# backend.tf
terraform {
backend "s3" {
bucket = "worldline-terraform-state"
key = "aci/production/terraform.tfstate"
region = "eu-west-3"
encrypt = true
dynamodb_table = "terraform-locks"
}
}
# Alternative : Azure Blob
terraform {
backend "azurerm" {
resource_group_name = "terraform-state-rg"
storage_account_name = "wltfstate"
container_name = "tfstate"
key = "aci/production/terraform.tfstate"
}
}
# Alternative : Terraform Cloud
terraform {
cloud {
organization = "worldline"
workspaces {
name = "aci-production"
}
}
}
4.4 Commandes State
# Lister les ressources dans le state
terraform state list
# Afficher une ressource spécifique
terraform state show aci_tenant.main
# Déplacer une ressource (renommage)
terraform state mv aci_tenant.old aci_tenant.new
# Supprimer du state (sans supprimer la ressource)
terraform state rm aci_tenant.imported
# Importer une ressource existante dans le state
terraform import aci_tenant.existing uni/tn-MyTenant
5. Commandes Essentielles
5.1 Workflow Principal
# 1. Initialisation (télécharge providers, configure backend)
terraform init
# 2. Validation syntaxique
terraform validate
# 3. Formatage du code
terraform fmt
# 4. Plan (prévisualisation des changements)
terraform plan
# 5. Application des changements
terraform apply
# 6. Application automatique (CI/CD)
terraform apply -auto-approve
# 7. Destruction de l'infrastructure
terraform destroy
5.2 Lecture du Plan
Terraform will perform the following actions:
# aci_tenant.main will be created
+ resource "aci_tenant" "main" {
+ id = (known after apply)
+ name = "Demo-Tenant"
+ description = "Tenant for production"
+ annotation = "orchestrator:terraform"
}
# aci_vrf.production will be created
+ resource "aci_vrf" "production" {
+ id = (known after apply)
+ name = "VRF-Prod"
+ tenant_dn = (known after apply)
}
Plan: 2 to add, 0 to change, 0 to destroy.
| Symbole | Signification |
|---|---|
+ |
Ressource à créer |
- |
Ressource Ă supprimer |
~ |
Ressource Ă modifier |
-/+ |
Ressource à recréer (destroy + create) |
5.3 Options Utiles
# Plan avec sortie dans un fichier
terraform plan -out=tfplan
# Apply depuis un fichier plan
terraform apply tfplan
# Plan ciblé sur une ressource
terraform plan -target=aci_tenant.main
# Variables en ligne de commande
terraform apply -var="tenant_name=MyTenant"
# Fichier de variables
terraform apply -var-file="production.tfvars"
# Refresh du state (sync avec l'API)
terraform refresh
6. Exercice Pratique
6.1 Premier Projet Terraform
Exercice : Hello Terraform
Créez votre premier projet Terraform qui affiche un message.
Structure :
Solution
variables.tf
main.tf
terraform {
required_version = ">= 1.0"
}
locals {
greeting = "Hello, ${var.name}!"
timestamp = timestamp()
}
outputs.tf
output "greeting" {
description = "Message de bienvenue"
value = local.greeting
}
output "timestamp" {
description = "Heure d'exécution"
value = local.timestamp
}
Exécution :
Résultat attendu :
7. Bonnes Pratiques
7.1 Structure de Projet
projet-terraform/
âââ main.tf # Ressources principales
âââ variables.tf # DĂ©claration des variables
âââ outputs.tf # Valeurs de sortie
âââ providers.tf # Configuration des providers
âââ backend.tf # Configuration du state remote
âââ versions.tf # Contraintes de versions
âââ terraform.tfvars # Valeurs des variables (non versionnĂ©)
âââ modules/ # Modules rĂ©utilisables
âââ tenant/
âââ main.tf
âââ variables.tf
âââ outputs.tf
7.2 Conventions de Nommage
| ĂlĂ©ment | Convention | Exemple |
|---|---|---|
| Fichiers | snake_case.tf | main.tf, aci_tenant.tf |
| Resources | snake_case | aci_tenant.production |
| Variables | snake_case | var.tenant_name |
| Outputs | snake_case | output.tenant_dn |
| Modules | kebab-case (dossier) | modules/aci-tenant |
7.3 RĂšgles d'Or
Ă faire
- â Versionner le code (Git)
- â Utiliser un backend remote
- â SĂ©parer les environnements (workspaces ou dossiers)
- â Utiliser des modules pour la rĂ©utilisation
- â Documenter les variables
- â
Valider avec
terraform validateetterraform fmt
à éviter
- â Commit le state (
terraform.tfstate) - â Commit les secrets (
terraform.tfvarsavec credentials) - â
terraform applysansterraform plan - â Modifier manuellement le state
- â Hardcoder les valeurs sensibles
8. Quiz de Validation
Question 1
Quelle commande permet de prévisualiser les changements sans les appliquer ?
Réponse
terraform plan
Cette commande compare l'état désiré (code) avec l'état actuel (state + API) et affiche les changements prévus.
Question 2
Qu'est-ce que le state Terraform et pourquoi est-il important ?
Réponse
Le state est un fichier JSON qui maintient la correspondance entre : - Le code HCL (état désiré) - Les ressources réelles (état actuel)
Il permet à Terraform de : - Savoir ce qui existe déjà - Calculer les changements nécessaires - Gérer les dépendances entre ressources
Question 3
Pourquoi utiliser un backend remote pour le state ?
Réponse
- Collaboration : Plusieurs personnes peuvent travailler sur la mĂȘme infra
- Locking : Ăvite les modifications concurrentes
- Sécurité : State sauvegardé, chiffré
- Pas de perte : Ne dépend pas d'une machine locale
Question 4
Que signifie le symbole ~ dans un plan Terraform ?
Réponse
Modification in-place : la ressource va ĂȘtre modifiĂ©e sans ĂȘtre supprimĂ©e et recréée.
Exemples :
- + = création
- - = suppression
- ~ = modification
- -/+ = remplacement (destroy + create)
9. Résumé
| Concept | Description |
|---|---|
| IaC | Gérer l'infrastructure comme du code versionné |
| HCL | Langage déclaratif de Terraform |
| Provider | Plugin pour communiquer avec une API |
| Resource | Objet d'infrastructure à gérer |
| State | Mapping entre code et ressources réelles |
| Plan | Prévisualisation des changements |
| Apply | Application des changements |
Exercice : Ă Vous de Jouer
Mise en Pratique
Objectif : Créer votre premier projet Terraform avec gestion du state et variables
Contexte : Vous devez initialiser un projet Terraform pour préparer l'automatisation d'une infrastructure ACI. Ce projet doit suivre les bonnes pratiques : séparation des fichiers, variables typées, et configuration du backend remote.
Tùches à réaliser :
- Créer la structure de fichiers recommandée (main.tf, variables.tf, outputs.tf, versions.tf)
- Configurer le backend S3 ou Azure Blob pour le state remote
- Déclarer des variables avec validation pour : nom du tenant, environnement (dev/staging/prod), région
- Initialiser le projet et vérifier la configuration
CritĂšres de validation :
- [ ] Le projet s'initialise sans erreur avec
terraform init - [ ] La validation syntaxique passe avec
terraform validate - [ ] Le formatage est correct avec
terraform fmt -check - [ ] Les variables ont des validations fonctionnelles
- [ ] Le backend remote est configurĂ© (mĂȘme si non accessible pour le test)
Solution
Structure du projet :
versions.tf
terraform {
required_version = ">= 1.0"
required_providers {
aci = {
source = "CiscoDevNet/aci"
version = "~> 2.13"
}
}
}
variables.tf
variable "tenant_name" {
description = "Nom du tenant ACI"
type = string
validation {
condition = can(regex("^[a-zA-Z][a-zA-Z0-9_-]{0,63}$", var.tenant_name))
error_message = "Le nom du tenant doit commencer par une lettre et contenir maximum 64 caractĂšres."
}
}
variable "environment" {
description = "Environnement de déploiement"
type = string
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "L'environnement doit ĂȘtre dev, staging ou prod."
}
}
variable "region" {
description = "Région du datacenter"
type = string
default = "eu-west"
}
backend.tf
terraform {
backend "s3" {
bucket = "worldline-terraform-state"
key = "aci/infrastructure/terraform.tfstate"
region = "eu-west-3"
encrypt = true
dynamodb_table = "terraform-locks"
}
}
# Alternative Azure
# terraform {
# backend "azurerm" {
# resource_group_name = "terraform-state-rg"
# storage_account_name = "wltfstate"
# container_name = "tfstate"
# key = "aci.terraform.tfstate"
# }
# }
main.tf
locals {
common_tags = {
environment = var.environment
managed_by = "terraform"
region = var.region
}
tenant_description = "Tenant ${var.tenant_name} - Environment: ${var.environment}"
}
outputs.tf
output "tenant_name" {
description = "Nom du tenant configuré"
value = var.tenant_name
}
output "environment" {
description = "Environnement de déploiement"
value = var.environment
}
output "configuration_summary" {
description = "Résumé de la configuration"
value = {
tenant = var.tenant_name
environment = var.environment
region = var.region
tags = local.common_tags
}
}
terraform.tfvars
Commandes de validation :
# Initialisation
terraform init
# Validation
terraform validate
# Formatage
terraform fmt
# Plan (sans provider configuré, affichera les outputs)
terraform plan
Résultat attendu :
Toutes les commandes doivent s'exĂ©cuter sans erreur. Le projet est structurĂ© correctement et prĂȘt Ă recevoir la configuration du provider ACI.
Navigation
| Précédent | Suivant |
|---|---|
| â Introduction | Module 2 : Architecture Cisco ACI â |
Navigation
| â Programme | Module 2 : Architecture Cisco ACI â |