Suite de ma série sur la certification Terraform Associate, après le module sur le workflow. Le quatrième objectif de l’exam guide, “Read and write configuration”, est le plus dense. Celui-ci couvre les resources, les data sources, le système de types et les expressions conditionnelles, ainsi que la gestion des sensitive data.
Resources
Le bloc resource est l’unité de base de la configuration : c’est lui qui déclare une ressource gérée par Terraform (créée, modifiée et détruite selon le state).
resource "aws_instance" "web" {
ami = "ami-0abcd1234"
instance_type = "t3.micro"
}
Les types de ressources disponibles dépendent des providers installés.
aws_instanceest le type de ressource,webest le nom local : ensemble ils forment l’adresseaws_instance.web, utilisée pour y référer ailleurs dans la configuration ou en CLI (terraform state show aws_instance.web).Les méta-arguments s’appliquent à n’importe quel type de resource, indépendamment du provider.
Ils déterminent comment Terraform crée et gère la ressource, par exemple :
count: crée N instances de la ressource, indexées (aws_instance.web[0]).for_each: crée une instance par élément d’une map ou d’un set, indexées par clé (aws_instance.web["a"]) — plus robuste quecountquand la liste peut changer, car ça évite de décaler les index existants.depends_on: force une dépendance explicite quand Terraform ne peut pas la déduire des références entre arguments.lifecycle: bloc imbriqué pour affiner le comportement (create_before_destroy,prevent_destroy,ignore_changes).
Data sources
Terraform peut aller chercher des données auprès d’un large éventail de data sources : API, autres workspaces Terraform, outputs de fonctions… Ce fetch dynamique rend la configuration plus flexible, mais ne crée ni ne modifie aucune ressource.
data "aws_ami" "web" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["amzn2-ami-hvm-*-x86_64-gp2"]
}
}
resource "aws_instance" "web" {
ami = data.aws_ami.web.id
instance_type = "t3.micro"
}
- Terraform tente d’interroger les data sources dès la phase de plan, mais peut différer la lecture à la phase d’apply selon la configuration.
- Ajouter un argument
depends_onà un bloc data force Terraform à différer la lecture jusqu’à l’apply. - On peut ajouter des blocs
preconditionetpostcondition. - On peut ajouter les méta-arguments
countetfor_eachaux blocs data pour créer plusieurs instances de la data source. - La syntaxe
data.<TYPE>.<LABEL>.<ATTRIBUTE>permet de référencer les attributs d’une data resource ailleurs dans la configuration.
Types
Terraform a son propre système de types, utilisé notamment pour contraindre les variables (variable "x" { type = ... }) et pour typer les valeurs manipulées dans la configuration.
- Primitifs :
string,number,bool. - Collections (éléments d’un seul type) :
list(type),set(type),map(type). - Structurels (éléments de types différents, structure fixe) :
object({ ... }),tuple([...]).
variable "instance_type" {
type = string
default = "t3.micro"
}
variable "tags" {
type = map(string)
default = {}
}
variable "network" {
type = object({
cidr_block = string
az_count = number
})
}
Terraform effectue des conversions implicites quand c’est possible (une list sans type déclaré est inférée, un number peut être converti en string dans une interpolation), mais déclarer le type explicitement sur les variables reste la meilleure protection contre une valeur mal formée passée en entrée d’un module.
Références
On peut référencer les ressources dans notre configuration de plusieurs façons.
Références de ressources
Une adresse de ressource :
[chemin de module][spec de ressource]
Chemin de module
module.nom_module[index de module]
Chemin de module complexe
module.foo[0].module.bar[“a”]
Chemin de spec de ressource
type_de_ressource.nom_ressource[index d’instance]
Valeurs pas encore connues
Quand Terraform planifie des changements pour appliquer la configuration, certaines valeurs ne peuvent pas être renseignées immédiatement car elles sont décidées dynamiquement par le système distant.
Ces valeurs inconnues apparaissent dans la sortie de terraform plan sous la forme (known after apply).
Variables & outputs
Les modules Terraform communiquent entre eux via des inputs et des outputs. Les variables permettent de paramétrer un module pour que d’autres utilisateurs puissent fournir des valeurs personnalisées au runtime.
Outputs
Ils exposent des données d’un module, permettant d’exporter des informations sur l’infrastructure. La valeur d’un bloc output s’apparente à une valeur de retour dans d’autres langages de programmation.
output "instance_public_ip" {
description = "IP publique de l'instance web"
value = aws_instance.web.public_ip
}
Locals
Les locals permettent de définir et réutiliser des expressions au sein d’un module.
locals {
name_prefix = "${var.project}-${var.environment}"
common_tags = {
project = var.project
env = var.environment
}
}
resource "aws_instance" "web" {
ami = "ami-0abcd1234"
instance_type = "t3.micro"
tags = local.common_tags
}
Types complexes
Un type complexe regroupe plusieurs valeurs en une seule.
Collection
list(...): une séquence de valeurs identifiées par des entiers consécutifs à partir de zéro.map(...): une collection de valeurs où chacune est identifiée par un label de type string.set(...): une collection de valeurs uniques, sans identifiant secondaire ni ordre.
variable "azs" {
type = list(string)
default = ["eu-west-1a", "eu-west-1b"]
}
variable "tags" {
type = map(string)
default = { env = "prod", team = "infra" }
}
variable "allowed_ports" {
type = set(number)
default = [80, 443]
}
Types structurels
object(...): un ensemble d’attributs nommés ayant chacun leur propre type (ex :object({ name=string, age=number })).tuple(...): une séquence d’éléments identifiés par des entiers consécutifs à partir de zéro, chaque élément ayant son propre type (ex :tuple([string, number, bool])).
variable "network" {
type = object({
cidr_block = string
az_count = number
})
default = {
cidr_block = "10.0.0.0/16"
az_count = 2
}
}
Any
anyest rarement le bon type à utiliser. Toujours spécifier le type exact, sauf en cas de données réellement dynamiques.
Validation de la configuration
terraform validate
La validation permet de vérifier que la configuration Terraform fonctionne comme prévu.
Moyens de validation
Terraform propose plusieurs moyens de valider la configuration :
- Les validations de variables d’input vérifient les paramètres de la configuration au moment du plan.
- Les preconditions s’assurent qu’une resource, data source ou output individuel respecte les exigences avant que Terraform ne tente de la créer.
- Les postconditions vérifient que Terraform a produit les resources et data sources avec les propriétés attendues.
- Les checks permettent de valider que l’infrastructure se comporte comme prévu sans bloquer les opérations Terraform selon leur résultat.
resource "aws_instance" "web" {
ami = "ami-0abcd1234"
instance_type = "t3.micro"
lifecycle {
precondition {
condition = data.aws_ami.web.architecture == "x86_64"
error_message = "L'AMI doit être en x86_64."
}
postcondition {
condition = self.public_ip != ""
error_message = "L'instance doit avoir une IP publique."
}
}
}
check "site_up" {
data "http" "homepage" {
url = "https://${aws_instance.web.public_ip}"
}
assert {
condition = data.http.homepage.status_code == 200
error_message = "Le site ne répond pas en HTTP 200."
}
}
Checks
Le bloc check sert à valider l’infrastructure en dehors du cycle de vie habituel des ressources. Il s’exécute en dernière étape d’un plan ou d’un apply, une fois que Terraform a planifié ou provisionné l’infrastructure. Quand l’assertion d’un bloc check échoue, Terraform émet un warning et poursuit l’opération en cours.
Il permet de :
- Valider des resources, data sources, variables ou outputs de la configuration.
- Valider le comportement de l’infrastructure dans son ensemble.
- Vérifier la configuration de l’infrastructure sans bloquer les opérations.
- Effectuer une validation continue dans HCP Terraform.
Workflow de validation
Terraform valide les différents aspects de la configuration le plus tôt possible. En général, l’ordre d’exécution est le suivant :
Gérer les données sensibles
Terraform peut avoir besoin d’accéder à des données sensibles (credentials cloud, tokens API, autres secrets) pour provisionner l’infrastructure. Terraform stocke le state dans un fichier en clair, qui inclut toute valeur secrète définie dans la configuration.
Argument sensitive
L’argument sensitive sur un bloc variable ou output permet de masquer ces valeurs dans les logs du CLI Terraform et dans l’UI HCP Terraform.
Argument ephemeral
Les valeurs ephemeral sont disponibles au runtime d’une opération, mais Terraform les omet des fichiers de state et de plan.
Quand les utiliser ?
sensitive | ephemeral | |
|---|---|---|
| Où l’utiliser | Bloc variable ou output | Bloc variable, output d’un module enfant, bloc ephemeral, argument write-only, provider, provisioner/connection |
| Effet sur le state/plan | Reste dans le state, mais masqué dans les logs CLI et l’UI HCP Terraform | Jamais persisté dans le state ni le plan |
| Effet sur l’affichage | Valeur remplacée par (sensitive value) dans le plan/apply | Valeur disponible uniquement au runtime de l’opération |
| Portée d’usage | Utilisable partout où la variable/output est référencé | Restreint aux contextes ephemeral listés ci-dessus |
| Cas d’usage typique | Mot de passe affiché dans un output | Token temporaire passé à un provider ou une resource |
Arguments write-only
Les arguments write-only permettent de passer de façon sécurisée des valeurs temporaires aux managed resources de Terraform pendant une opération, sans les persister dans le state ou les fichiers de plan.
resource "aws_db_instance" "db" {
identifier = "app-db"
password_wo = var.db_password
password_wo_version = 1
}
variable "db_password" {
type = string
ephemeral = true
}
Bonnes pratiques de sécurité
Si des valeurs sensibles sont stockées dans un fichier de state, il est recommandé de mettre en place des mesures de sécurité supplémentaires :
- Stocker le state à distance.
- Chiffrer le state au repos.
- Utiliser des contrôles d’accès pour limiter qui peut accéder au state.
- Utiliser des logs d’audit pour tracer les accès au state dans le temps.
Ce que je retiens
countvsfor_each:for_eachévite le décalage d’index quand la liste change, à privilégier dès que les éléments sont identifiables par une clé stable.- Preconditions, postconditions et checks ne servent pas la même chose : les deux premières bloquent le plan/apply sur une resource précise, les checks valident l’infrastructure globalement sans bloquer.
sensitivemasque l’affichage,ephemeralévite la persistance : seulephemeralgarantit qu’une valeur n’atterrit jamais dans le state ou le plan.
Prochaine étape de la série : les modules.
