Leçon 3 / 6
Leçon 03 · Partie 1 — Les fondations

Providers et ressources

Les providers : des plugins qui parlent aux APIs

Terraform ne sait pas nativement comment créer une instance AWS, un bucket Azure ou un dépôt GitHub. Ce sont les providers qui font le lien entre Terraform et les APIs des différentes plateformes.

Un provider est un plugin (écrit en Go) qui expose les ressources et data sources d'un service. Il traduit tes blocs HCL en appels API concrets.

☁️

Cloud public

AWS, Azure, Google Cloud, OVH, DigitalOcean… Chaque cloud a son provider officiel maintenu par l'éditeur.

hashicorp/aws · hashicorp/azurerm
🔧

Infrastructure

Kubernetes, Helm, Docker, VMware… Pour gérer des ressources dans ta propre infrastructure.

hashicorp/kubernetes · kreuzwerker/docker
🛠️

Outils et services

GitHub, GitLab, Datadog, PagerDuty, Vault… Pour piloter des outils DevOps en Infrastructure as Code.

integrations/github · hashicorp/vault
🧩

Utilitaires

Random, TLS, Local, Time… Des providers sans API externe, utiles pour générer des valeurs ou manipuler des fichiers locaux.

hashicorp/random · hashicorp/tls

Déclarer un provider

On déclare les providers requis dans un bloc terraform avec required_providers, puis on les configure dans un bloc provider.

versions.tf
# Déclarer les providers requis et leurs versions
terraform {
  required_version = ">= 1.0"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
    random = {
      source  = "hashicorp/random"
      version = ">= 3.1"
    }
  }
}
main.tf
# Configurer le provider AWS
provider "aws" {
  region = "eu-west-3"   # Paris
}
💡

Le contrainte de version ~> 5.0 signifie « compatible avec 5.x, mais pas 6.0 ». Toujours fixer les versions pour garantir la reproductibilité des déploiements.

Le registre Terraform

Tous les providers officiels et communautaires sont publiés sur registry.terraform.io. C'est la source de vérité pour :

  • Trouver le nom exact d'un provider (hashicorp/aws, integrations/github…)
  • Consulter la documentation de chaque ressource et data source
  • Vérifier les versions disponibles et les changelogs
  • Trouver des modules réutilisables publiés par la communauté
Terminal
# Télécharger les providers déclarés dans required_providers
terraform init

# Les plugins sont téléchargés dans .terraform/providers/
# Un fichier .terraform.lock.hcl est créé pour figer les versions exactes

Les ressources : la syntaxe de base

Une ressource représente un composant d'infrastructure que Terraform va créer, modifier ou détruire. La syntaxe est toujours :

Syntaxe générale
resource "TYPE_RESSOURCE" "NOM_LOCAL" {
  attribut1 = valeur1
  attribut2 = valeur2
  # ...
}

# Exemple concret : un bucket S3
resource "aws_s3_bucket" "mon_bucket" {
  bucket = "mon-bucket-unique-2024"
}

# Exemple : une instance EC2
resource "aws_instance" "web" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t3.micro"

  tags = {
    Name = "MonServeurWeb"
  }
}

Le type (aws_instance) détermine quel objet est créé via le provider. Le nom local (web) sert uniquement à référencer cette ressource dans le reste du code Terraform — il n'apparaît pas dans AWS.

Les data sources : lire sans créer

Un data source permet de lire des informations sur une ressource existante sans la créer ni la gérer. C'est utile pour récupérer des valeurs dynamiques (ID d'une AMI, ARN d'un certificat, liste de zones de disponibilité…).

main.tf
# Récupérer la dernière AMI Amazon Linux 2023
data "aws_ami" "amazon_linux" {
  most_recent = true
  owners      = ["amazon"]

  filter {
    name   = "name"
    values = ["al2023-ami-*-x86_64"]
  }
}

# Utiliser l'AMI récupérée dans une ressource
resource "aws_instance" "web" {
  ami           = data.aws_ami.amazon_linux.id
  instance_type = "t3.micro"
}
💡

La syntaxe pour référencer un data source est data.<type>.<nom>.<attribut>. Pour une ressource, pas besoin du préfixe data. : <type>.<nom>.<attribut>.

Références entre ressources

Les ressources peuvent se référencer mutuellement grâce à la syntaxe <type>.<nom>.<attribut>. Terraform résout automatiquement l'ordre de création.

main.tf
# Un VPC
resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"
}

# Un subnet qui référence l'ID du VPC
resource "aws_subnet" "main" {
  vpc_id     = aws_vpc.main.id        # référence au VPC ci-dessus
  cidr_block = "10.0.1.0/24"
}

# Une instance EC2 dans ce subnet
resource "aws_instance" "web" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t3.micro"
  subnet_id     = aws_subnet.main.id  # référence au subnet
}

Dépendances implicites vs depends_on

Quand tu références un attribut d'une ressource dans une autre, Terraform crée une dépendance implicite : il sait qu'il doit créer le VPC avant le subnet.

Parfois, une dépendance existe sans référence directe d'attribut. Dans ce cas, on utilise depends_on pour la déclarer explicitement.

main.tf
# Politique IAM
resource "aws_iam_role_policy" "app_policy" {
  name   = "app-policy"
  role   = aws_iam_role.app.id
  policy = "..."
}

# L'instance doit attendre que la politique soit créée,
# mais ne référence pas directement son attribut
resource "aws_instance" "app" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t3.micro"

  depends_on = [aws_iam_role_policy.app_policy]
}
⚠️

Bonne pratique : utilise depends_on en dernier recours. Préfère toujours les références directes d'attributs qui créent des dépendances implicites — le code est plus lisible et moins fragile.

Exemple complet : VPC + subnet + EC2

Voici un exemple réaliste qui assemble toutes les notions vues : providers, ressources, data sources et références croisées.

main.tf
# ── Provider ──────────────────────────────────────────
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

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

# ── Data source : dernière AMI Amazon Linux ───────────
data "aws_ami" "amazon_linux" {
  most_recent = true
  owners      = ["amazon"]
  filter {
    name   = "name"
    values = ["al2023-ami-*-x86_64"]
  }
}

# ── Réseau ────────────────────────────────────────────
resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"
  tags = { Name = "vpc-lab" }
}

resource "aws_subnet" "main" {
  vpc_id            = aws_vpc.main.id      # dépendance implicite
  cidr_block        = "10.0.1.0/24"
  availability_zone = "eu-west-3a"
  tags = { Name = "subnet-lab" }
}

# ── Serveur ───────────────────────────────────────────
resource "aws_instance" "web" {
  ami           = data.aws_ami.amazon_linux.id  # depuis data source
  instance_type = "t3.micro"
  subnet_id     = aws_subnet.main.id            # dépendance implicite

  tags = { Name = "web-lab" }
}
// À retenir
  • Un provider est un plugin qui expose les ressources d'une API (AWS, Azure, GitHub…). On le déclare dans required_providers avec une version.
  • Le registre Terraform (registry.terraform.io) liste tous les providers et leur documentation.
  • Une ressource se déclare avec resource "type" "nom_local" {}. Le type vient du provider, le nom local est libre.
  • Un data source (data "type" "nom" {}) lit une ressource existante sans la créer.
  • Les références (aws_subnet.main.id) créent des dépendances implicites. depends_on sert pour les dépendances sans référence directe.