Aller au contenu principal

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

  1. Créez des variables pour environnement (dev/staging/prod)
  2. Ajoutez de la validation sur les variables
  3. Utilisez des locals pour les tags communs
  4. Exportez les informations importantes via outputs

← Ressources | State Management →