Les blocs HCL sont les éléments de base d’une configuration Terraform. Chaque bloc a un type, zéro ou plusieurs labels, et un corps d’attributs.


resource — déclarer une ressource gérée

resource "TYPE_PROVIDER" "NOM_LOCAL" {
  # attributs de la ressource
}
# Instance EC2
resource "aws_instance" "web" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t3.micro"
 
  tags = {
    Name        = "web-server"
    Environment = var.env
  }
}
 
# Bucket S3
resource "aws_s3_bucket" "data" {
  bucket = "mon-bucket-${var.env}"
}
 
# Référencer une ressource depuis une autre :
# aws_instance.web.id          ← attribut calculé après création
# aws_instance.web.public_ip   ← IP publique
# aws_s3_bucket.data.arn       ← ARN du bucket

data — lire une ressource existante (read-only)

Les data sources interrogent des ressources déjà existantes sans les gérer.

data "TYPE_PROVIDER" "NOM_LOCAL" {
  # filtres
}
# Récupérer l'AMI Amazon Linux 2 la plus récente
data "aws_ami" "amazon_linux" {
  most_recent = true
  owners      = ["amazon"]
 
  filter {
    name   = "name"
    values = ["amzn2-ami-hvm-*-x86_64-gp2"]
  }
}
 
# Utiliser la data source :
resource "aws_instance" "web" {
  ami = data.aws_ami.amazon_linux.id   # ← référence avec préfixe data.
}
 
# Récupérer un VPC existant
data "aws_vpc" "main" {
  tags = {
    Environment = "prod"
  }
}
 
# Récupérer les subnets dans ce VPC
data "aws_subnets" "private" {
  filter {
    name   = "vpc-id"
    values = [data.aws_vpc.main.id]
  }
}

variable — déclarer une variable d’entrée

variable "NOM" {
  description = "..."
  type        = TYPE       # optionnel mais recommandé
  default     = VALEUR     # rend la variable optionnelle
  sensitive   = true|false # masque dans les logs
  validation { ... }       # règle de validation personnalisée
  nullable    = true|false # autoriser null
}
variable "region" {
  description = "Région AWS de déploiement"
  type        = string
  default     = "eu-west-1"
}
 
variable "instance_count" {
  description = "Nombre d'instances"
  type        = number
  default     = 2
}
 
variable "env" {
  description = "Environnement cible"
  type        = string
 
  validation {
    condition     = contains(["dev", "staging", "prod"], var.env)
    error_message = "L'environnement doit être dev, staging ou prod."
  }
}
 
variable "db_password" {
  description = "Mot de passe BDD"
  type        = string
  sensitive   = true     # masqué dans terraform plan et les logs
}
 
variable "tags" {
  description = "Tags communs"
  type        = map(string)
  default     = {}
}
 
variable "allowed_ports" {
  description = "Ports autorisés"
  type        = list(number)
  default     = [80, 443]
}

Passer des valeurs :

terraform apply -var="env=prod"
terraform apply -var-file=prod.tfvars
export TF_VAR_env=prod   # variable d'environnement

output — déclarer une valeur de sortie

output "NOM" {
  description = "..."
  value       = EXPRESSION
  sensitive   = true|false
  depends_on  = [...]
}
output "instance_ip" {
  description = "IP publique de l'instance"
  value       = aws_instance.web.public_ip
}
 
output "db_endpoint" {
  description = "Endpoint de la base de données"
  value       = aws_db_instance.main.endpoint
  sensitive   = true   # masqué sauf avec terraform output -raw
}
 
# Output d'un objet complexe
output "vpc_info" {
  description = "Informations VPC"
  value = {
    id   = aws_vpc.main.id
    cidr = aws_vpc.main.cidr_block
  }
}

locals — valeurs locales calculées

Les locals permettent de nommer des expressions réutilisées pour éviter la répétition.

locals {
  NOM = EXPRESSION
}
locals {
  # Préfixe commun
  prefix = "${var.project}-${var.env}"
 
  # Tags communs à toutes les ressources
  common_tags = merge(var.tags, {
    Project     = var.project
    Environment = var.env
    ManagedBy   = "Terraform"
  })
 
  # Liste de ports calculée
  api_ports = var.env == "prod" ? [443] : [80, 443, 8080]
 
  # Calculer un CIDR
  private_subnets = [for i in range(3) : cidrsubnet(var.vpc_cidr, 8, i)]
}
 
# Utilisation :
resource "aws_instance" "web" {
  tags = local.common_tags                    # ← préfixe local.
}
 
resource "aws_s3_bucket" "data" {
  bucket = "${local.prefix}-data"
}

provider — configurer un provider

provider "NOM" {
  # attributs de configuration
}
provider "aws" {
  region  = var.region
  profile = "mon-profil-aws"    # profil ~/.aws/credentials
 
  default_tags {
    tags = local.common_tags
  }
}
 
# Provider aliasé (multi-région / multi-compte)
provider "aws" {
  alias   = "us-east"
  region  = "us-east-1"
  profile = "prod-account"
}
 
# Utilisation d'un provider aliasé
resource "aws_instance" "us_server" {
  provider = aws.us-east    # ← référence l'alias
  ami      = "ami-abc123"
  ...
}

terraform — configuration du projet

terraform {
  required_version = ">= 1.5"
 
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
 
  # Backend de stockage du state
  backend "s3" {
    bucket         = "mon-state-bucket"
    key            = "prod/terraform.tfstate"
    region         = "eu-west-1"
    dynamodb_table = "terraform-locks"
    encrypt        = true
  }
}

En relation avec