Variables et Outputs
Objectifs du chapitre
- Déclarer et utiliser des variables
- Comprendre les types de variables
- Passer des valeurs aux variables
- Exporter des outputs
1 - Input Variables
Déclaration de base
# variables.tf
variable "region" {
description = "AWS region"
type = string
default = "eu-west-1"
}
variable "instance_type" {
description = "Type d'instance EC2"
type = string
default = "t2.micro"
}
variable "instance_count" {
description = "Nombre d'instances"
type = number
default = 1
}
variable "enable_monitoring" {
description = "Activer le monitoring"
type = bool
default = false
}
Utilisation
# main.tf
provider "aws" {
region = var.region
}
resource "aws_instance" "web" {
count = var.instance_count
ami = data.aws_ami.ubuntu.id
instance_type = var.instance_type
monitoring = var.enable_monitoring
}
2 - Types de variables
Types primitifs
variable "string_var" {
type = string
default = "hello"
}
variable "number_var" {
type = number
default = 42
}
variable "bool_var" {
type = bool
default = true
}
Collections
# Liste
variable "availability_zones" {
type = list(string)
default = ["eu-west-1a", "eu-west-1b", "eu-west-1c"]
}
# Map
variable "tags" {
type = map(string)
default = {
Environment = "Production"
Team = "DevOps"
}
}
# Set
variable "allowed_ips" {
type = set(string)
default = ["10.0.0.1", "10.0.0.2"]
}
Types structurels
# Object
variable "instance_config" {
type = object({
ami = string
instance_type = string
tags = map(string)
})
default = {
ami = "ami-12345678"
instance_type = "t2.micro"
tags = {
Name = "default"
}
}
}
# Tuple
variable "mixed_config" {
type = tuple([string, number, bool])
default = ["hello", 42, true]
}
# Liste d'objets
variable "servers" {
type = list(object({
name = string
type = string
port = number
}))
default = [
{ name = "web", type = "t2.micro", port = 80 },
{ name = "api", type = "t2.small", port = 8080 }
]
}
3 - Validation des variables
Règles de validation
variable "instance_type" {
type = string
description = "Type d'instance EC2"
validation {
condition = can(regex("^t[23]\\.", var.instance_type))
error_message = "Instance type must be t2.* or t3.*"
}
}
variable "environment" {
type = string
description = "Environnement de déploiement"
validation {
condition = contains(["dev", "staging", "production"], var.environment)
error_message = "Environment must be dev, staging, or production."
}
}
variable "port" {
type = number
description = "Port de l'application"
validation {
condition = var.port >= 1 && var.port <= 65535
error_message = "Port must be between 1 and 65535."
}
}
Validations multiples
variable "bucket_name" {
type = string
validation {
condition = length(var.bucket_name) >= 3
error_message = "Bucket name must be at least 3 characters."
}
validation {
condition = length(var.bucket_name) <= 63
error_message = "Bucket name must not exceed 63 characters."
}
validation {
condition = can(regex("^[a-z0-9][a-z0-9.-]*[a-z0-9]$", var.bucket_name))
error_message = "Bucket name must start and end with lowercase letter or number."
}
}
4 - Passer des valeurs
Méthodes par ordre de priorité
Fichier terraform.tfvars
# terraform.tfvars
region = "eu-west-1"
instance_type = "t3.micro"
instance_count = 3
environment = "production"
tags = {
Project = "MyApp"
Environment = "Production"
Team = "Platform"
}
Fichier .tfvars personnalisé
# production.tfvars
environment = "production"
instance_type = "t3.large"
instance_count = 5
# staging.tfvars
environment = "staging"
instance_type = "t3.small"
instance_count = 2
# Utilisation
terraform plan -var-file="production.tfvars"
terraform apply -var-file="staging.tfvars"
Variables d'environnement
# Format: TF_VAR_<variable_name>
export TF_VAR_region="eu-west-1"
export TF_VAR_instance_type="t3.micro"
export TF_VAR_environment="production"
# Utilisation
terraform plan
Ligne de commande
# Une variable
terraform plan -var="instance_type=t3.large"
# Plusieurs variables
terraform apply \
-var="instance_type=t3.large" \
-var="instance_count=5" \
-var="environment=production"
5 - Variables sensibles
Marquer comme sensitive
variable "db_password" {
description = "Database password"
type = string
sensitive = true
}
variable "api_key" {
description = "API key for external service"
type = string
sensitive = true
}
Comportement
# Le plan masque les valeurs sensibles
Terraform will perform the following actions:
# aws_db_instance.main will be created
+ resource "aws_db_instance" "main" {
+ password = (sensitive value)
}
Bonnes pratiques
# ✅ Ne jamais mettre de default pour les secrets
variable "db_password" {
type = string
sensitive = true
# Pas de default!
}
# ✅ Utiliser avec des fichiers tfvars (ignorés par git)
# secrets.tfvars (dans .gitignore)
db_password = "super_secret_password"
6 - Local Values
Déclaration
locals {
# Valeur simple
environment = "production"
# Valeur calculée
name_prefix = "${var.project}-${local.environment}"
# Tags communs
common_tags = {
Environment = local.environment
Project = var.project
ManagedBy = "Terraform"
}
# Transformation
instance_ids = [for i in aws_instance.web : i.id]
# Conditionnelle
enable_logging = local.environment == "production" ? true : false
}
Utilisation
resource "aws_instance" "web" {
ami = data.aws_ami.ubuntu.id
instance_type = var.instance_type
tags = merge(local.common_tags, {
Name = "${local.name_prefix}-web"
})
}
resource "aws_s3_bucket" "logs" {
count = local.enable_logging ? 1 : 0
bucket = "${local.name_prefix}-logs"
tags = local.common_tags
}
Différence variables vs locals
7 - Outputs
Déclaration de base
# outputs.tf
output "instance_id" {
description = "ID de l'instance EC2"
value = aws_instance.web.id
}
output "public_ip" {
description = "IP publique de l'instance"
value = aws_instance.web.public_ip
}
output "public_dns" {
description = "DNS public de l'instance"
value = aws_instance.web.public_dns
}
Outputs avec expressions
# Liste d'IDs
output "instance_ids" {
description = "IDs de toutes les instances"
value = aws_instance.web[*].id
}
# Map d'IPs
output "instance_ips" {
description = "IPs par nom"
value = {
for instance in aws_instance.web :
instance.tags["Name"] => instance.public_ip
}
}
# Valeur conditionnelle
output "load_balancer_dns" {
description = "DNS du load balancer"
value = var.create_lb ? aws_lb.main[0].dns_name : null
}
Outputs sensibles
output "db_password" {
description = "Database password"
value = random_password.db.result
sensitive = true
}
# Affichage
# Outputs:
# db_password = <sensitive>
Dépendances d'outputs
output "connection_string" {
description = "Connection string pour la base de données"
value = "postgresql://${var.db_user}:${random_password.db.result}@${aws_db_instance.main.endpoint}"
sensitive = true
# Assurer que la ressource existe avant l'output
depends_on = [aws_db_instance.main]
}
8 - Outputs entre modules
Module enfant
# modules/vpc/outputs.tf
output "vpc_id" {
description = "ID du VPC"
value = aws_vpc.main.id
}
output "public_subnet_ids" {
description = "IDs des subnets publics"
value = aws_subnet.public[*].id
}
output "private_subnet_ids" {
description = "IDs des subnets privés"
value = aws_subnet.private[*].id
}
Module parent
# main.tf
module "vpc" {
source = "./modules/vpc"
cidr_block = "10.0.0.0/16"
}
# Utilisation des outputs du module
resource "aws_instance" "web" {
subnet_id = module.vpc.public_subnet_ids[0]
# ...
}
# Re-export des outputs
output "vpc_id" {
value = module.vpc.vpc_id
}
9 - Voir les outputs
Commandes
# Voir tous les outputs après apply
terraform output
# Un output spécifique
terraform output instance_id
# Format JSON
terraform output -json
# Valeur brute (sans quotes)
terraform output -raw public_ip
Exemple de sortie
$ terraform output
instance_id = "i-0123456789abcdef0"
public_ip = "54.123.45.67"
public_dns = "ec2-54-123-45-67.eu-west-1.compute.amazonaws.com"
$ terraform output -json
{
"instance_id": {
"sensitive": false,
"type": "string",
"value": "i-0123456789abcdef0"
},
"public_ip": {
"sensitive": false,
"type": "string",
"value": "54.123.45.67"
}
}
10 - Bonnes pratiques
Variables
# ✅ Toujours ajouter une description
variable "instance_type" {
description = "Type d'instance EC2 à utiliser"
type = string
default = "t2.micro"
}
# ✅ Utiliser la validation
variable "environment" {
type = string
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "Invalid environment."
}
}
# ✅ Marquer les secrets comme sensitive
variable "db_password" {
type = string
sensitive = true
}
Outputs
# ✅ Description claire
output "load_balancer_url" {
description = "URL du load balancer pour accéder à l'application"
value = "https://${aws_lb.main.dns_name}"
}
# ✅ Exporter ce qui est utile
output "deployment_info" {
value = {
vpc_id = module.vpc.vpc_id
instance_ids = aws_instance.web[*].id
lb_dns = aws_lb.main.dns_name
}
}
Résumé
Points clés
- Les variables rendent la configuration paramétrable
- Utilisez la validation pour les contraintes
- Marquez les secrets comme sensitive
- Les locals simplifient le code
- Les outputs exposent les valeurs importantes
Exercices pratiques
- Créez des variables pour environnement (dev/staging/prod)
- Ajoutez de la validation sur les variables
- Utilisez des locals pour les tags communs
- Exportez les informations importantes via outputs