Un module est un ensemble de fichiers Terraform dans un répertoire. Ils permettent d’encapsuler et réutiliser de l’infrastructure.


Appeler un module (bloc module)

module "NOM" {
  source  = "CHEMIN_OU_REGISTRY"
  version = "~> X.Y"     # obligatoire pour le registry public
 
  # Inputs du module (correspondent aux variables du module)
  variable_1 = valeur_1
  variable_2 = valeur_2
}

Types de sources :

# Module local (chemin relatif)
module "vpc" {
  source = "./modules/vpc"
}
 
# Registry public Terraform (registry.terraform.io)
module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "~> 5.0"
}
 
# GitHub
module "vpc" {
  source = "github.com/terraform-aws-modules/terraform-aws-vpc"
}
 
# Sous-dossier d'un repo Git
module "vpc" {
  source = "git::https://github.com/org/repo.git//modules/vpc?ref=v2.0"
}
 
# Registry Terraform Enterprise / privé
module "vpc" {
  source  = "app.terraform.io/mon-org/vpc/aws"
  version = "~> 1.0"
}

Accéder aux outputs d’un module

module "vpc" {
  source = "./modules/vpc"
  cidr   = "10.0.0.0/16"
}
 
resource "aws_instance" "web" {
  subnet_id = module.vpc.private_subnet_ids[0]   # ← module.NOM.OUTPUT
  vpc_security_group_ids = [module.vpc.sg_id]
}

Passer des variables entre modules

module "database" {
  source = "./modules/rds"
 
  vpc_id     = module.vpc.vpc_id               # output du module vpc
  subnet_ids = module.vpc.private_subnet_ids   # output du module vpc
  env        = var.env                         # variable racine
}
 
module "application" {
  source = "./modules/ecs"
 
  db_endpoint = module.database.endpoint       # output du module database
  db_password = module.database.password
}

Créer un module

Structure d’un module :

modules/vpc/
├── main.tf        ← ressources (aws_vpc, aws_subnet, etc.)
├── variables.tf   ← inputs du module
├── outputs.tf     ← ce que le module expose
├── versions.tf    ← required_providers (optionnel)
└── README.md      ← documentation (recommandé)

variables.tf (inputs) :

variable "vpc_cidr" {
  description = "CIDR block du VPC"
  type        = string
  default     = "10.0.0.0/16"
}
 
variable "env" {
  description = "Environnement"
  type        = string
 
  validation {
    condition     = contains(["dev","staging","prod"], var.env)
    error_message = "Environnement invalide."
  }
}
 
variable "availability_zones" {
  description = "Liste des AZs"
  type        = list(string)
}

main.tf :

resource "aws_vpc" "this" {
  cidr_block = var.vpc_cidr
 
  tags = {
    Name        = "vpc-${var.env}"
    Environment = var.env
  }
}
 
resource "aws_subnet" "private" {
  for_each = toset(var.availability_zones)
 
  vpc_id            = aws_vpc.this.id
  availability_zone = each.value
  cidr_block        = cidrsubnet(var.vpc_cidr, 8, index(var.availability_zones, each.value))
}

outputs.tf :

output "vpc_id" {
  description = "ID du VPC créé"
  value       = aws_vpc.this.id
}
 
output "private_subnet_ids" {
  description = "IDs des subnets privés"
  value       = [for s in aws_subnet.private : s.id]
}
 
output "vpc_cidr" {
  description = "CIDR du VPC"
  value       = aws_vpc.this.cidr_block
}

Meta-arguments disponibles dans module

module "servers" {
  source = "./modules/server"
 
  # count
  count = var.env == "prod" ? 3 : 1
 
  # for_each
  for_each = var.regions
  region   = each.value
 
  # depends_on
  depends_on = [module.networking]
 
  # providers (passer un provider aliasé au module)
  providers = {
    aws = aws.us-east
  }
}

Module Registry public — bonnes pratiques

# Utiliser des modules maintenus par la communauté
module "eks" {
  source  = "terraform-aws-modules/eks/aws"
  version = "~> 20.0"   # ← toujours épingler la version
 
  cluster_name    = "mon-cluster"
  cluster_version = "1.29"
  vpc_id          = module.vpc.vpc_id
  subnet_ids      = module.vpc.private_subnet_ids
}
 
module "rds" {
  source  = "terraform-aws-modules/rds/aws"
  version = "~> 6.0"
 
  identifier = "ma-bdd"
  engine     = "postgres"
  ...
}

En relation avec