Terraform from Scratch: HCL, Provider en de Plan-Apply-Destroy-cyclus
In 2026 heeft de markt voor Infrastructuur als Code een zodanige volwassenheid bereikt dat het negeren van Terraform gelijk staat aan SQL schrijven zonder de transacties te kennen: technisch mogelijk, maar professioneel riskant. HashiCorp's Terraform houdt vandaag de dag de 32,8% marktaandeel onder IaC-tools, met meer dan 4 miljoen maandelijkse providerinstallaties op register.terraform.io. Deze gids neemt je mee vanaf het begin naar een werkende opstelling op AWS en Azure, met een goed begrip van de Plan-Apply-Destroy-cyclus waardoor kostbare productiefouten worden vermeden.
De vraag die ik het vaakst hoor van ontwikkelaars die IaC benaderen is: “Omdat ik niet alleen maar gebruik bash-scripts of de AWS-console?”. Het antwoord ligt in het concept van declaratieve infrastructuur: Je vertelt het niet aan Terraform als creëer de hulpbronnen, zegt u welke staat je wilt bereiken. Terraform houdt zich bezig met het begrijpen van de volgorde van bewerkingen, het beheren van de afhankelijkheden tussen hulpbronnen en het garanderen van idempotentie.
Wat je gaat leren
- Installeer Terraform en configureer tfenv om meerdere versies te verwerken
- HCL-syntaxis: blokken, attributen, expressies en ingebouwde functies
- Configureer de AWS-provider en Azure-provider met veilige authenticatie
- De volledige levenscyclus:
terraform init,plan,apply,destroy - Het statusbestand begrijpen: wat het is, waar het zich bevindt, waarom het nooit handmatig mag worden gewijzigd
- Structureer een Terraform-project vanaf het begin op een schaalbare manier
- Variabelen, locals en output: organiseer de configuratie op een professionele manier
Vereisten en installatie
Voordat we de eerste regel van HCL schrijven, gaan we eerst de omgeving professioneel opzetten. De meest voorkomende beginnersfout is het wereldwijd installeren van Terraform met een pakketbeheerder en dan merk je dat je vastzit aan een specifieke versie. De juiste oplossing is tfenv, de versiebeheerder voor Terraform (equivalent van nvm voor Node.js).
# Installa tfenv (macOS/Linux)
git clone https://github.com/tfutils/tfenv.git ~/.tfenv
echo 'export PATH="$HOME/.tfenv/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
# Installa l'ultima versione stabile di Terraform
tfenv install latest
tfenv use latest
# Verifica installazione
terraform version
# Output: Terraform v1.9.x on linux_amd64
# Installa una versione specifica se il progetto la richiede
tfenv install 1.8.5
tfenv use 1.8.5
# Lista versioni installate
tfenv list
Voor Windows de aanbevolen aanpak in 2026 en WSL2 met Ubuntu of Chocolatey:
# Windows con Chocolatey
choco install terraform
# Oppure scarica il binario da releases.hashicorp.com
# e aggiungilo al PATH manualmente
Installeer ook de VS Code-plug-in HashiCorp Terraform (ID: hashicorp.terraform):
biedt syntaxisaccentuering, automatische aanvulling, go-to-definitie voor providers en integratie
met terraform fmt. Het is de meest robuuste IDE-ervaring die beschikbaar is voor HCL.
HCL: HashiCorp-configuratietaal
HCL (HashiCorp Configuration Language) is een speciaal ontworpen declaratieve taal
voor de configuratie van infrastructuren. Het is geen programmeertaal voor algemene doeleinden:
heeft geen imperatieve lus (use for_each e count), kent geen uitzonderingen,
Het heeft geen asynchrone I/O. Dit is een functies, geen limiet: eenvoud vermindert de
toevallige complexiteit van configuraties.
Het basisbestand van elk Terraform-project e main.tf. De gemeenschappelijke conventie
en scheid de configuratie in deze bestanden:
progetto-terraform/
├── main.tf # Risorse principali
├── variables.tf # Dichiarazione variabili
├── outputs.tf # Output values
├── versions.tf # Required providers e terraform block
├── locals.tf # Valori locali computati
└── terraform.tfvars # Valori delle variabili (non committare se contiene segreti)
Hier is de basisstructuur van HCL met de basisbloktypen:
# versions.tf — blocco terraform: configura il comportamento del core
terraform {
required_version = ">= 1.8.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.100"
}
}
}
# variables.tf — dichiarazione variabili di input
variable "environment" {
description = "Nome dell'ambiente (dev, staging, prod)"
type = string
default = "dev"
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "L'ambiente deve essere dev, staging o prod."
}
}
variable "aws_region" {
description = "AWS Region dove deployare le risorse"
type = string
default = "eu-west-1"
}
variable "instance_count" {
description = "Numero di istanze EC2 da creare"
type = number
default = 2
}
variable "tags" {
description = "Tag comuni da applicare a tutte le risorse"
type = map(string)
default = {
ManagedBy = "Terraform"
Project = "demo"
}
}
# locals.tf — valori computati a partire da variabili
locals {
# Naming convention uniforme
name_prefix = "${var.environment}-${var.tags["Project"]}"
# Merge tag comuni con tag specifici per risorsa
common_tags = merge(var.tags, {
Environment = var.environment
CreatedAt = timestamp()
})
}
Configureer de AWS-provider
I aanbieder zijn plug-ins waarmee Terraform kan communiceren met externe API's: AWS, Azure, GCP, Kubernetes, GitHub, Datadog – vrijwel elke dienst heeft een Terraform-provider. De AWS-provider is het meest volwassen, met ondersteuning voor meer dan 1200 resourcetypen.
Voor AWS-authenticatie, Gebruik nooit een hardgecodeerde toegangssleutel in HCL-code. De AWS-provider ondersteunt de volgende modi, in volgorde van prioriteit:
# main.tf — configurazione provider AWS
provider "aws" {
region = var.aws_region
# NON fare questo in produzione:
# access_key = "AKIA..." # MAI
# secret_key = "..." # MAI
# Metodo consigliato 1: assume role (best practice per CI/CD)
# assume_role {
# role_arn = "arn:aws:iam::123456789:role/TerraformRole"
# }
# I tag di default vengono applicati a tutte le risorse
default_tags {
tags = local.common_tags
}
}
# Configurazione autenticazione (fuori da main.tf)
# La best practice e usare il file ~/.aws/credentials oppure
# variabili di ambiente:
# export AWS_ACCESS_KEY_ID="..."
# export AWS_SECRET_ACCESS_KEY="..."
# export AWS_DEFAULT_REGION="eu-west-1"
#
# In produzione: IAM Instance Profile o OIDC con GitHub Actions
Laten we nu de eerste AWS-bronnen maken: een VPC met publieke en private subnetten:
# main.tf — prime risorse AWS
# Data source: recupera gli AZ disponibili nella region
data "aws_availability_zones" "available" {
state = "available"
}
# VPC principale
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "${local.name_prefix}-vpc"
}
}
# Subnet pubblica (una per AZ)
resource "aws_subnet" "public" {
count = min(length(data.aws_availability_zones.available.names), 2)
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet(aws_vpc.main.cidr_block, 8, count.index)
availability_zone = data.aws_availability_zones.available.names[count.index]
map_public_ip_on_launch = true
tags = {
Name = "${local.name_prefix}-public-${count.index + 1}"
Tier = "Public"
}
}
# Subnet privata
resource "aws_subnet" "private" {
count = min(length(data.aws_availability_zones.available.names), 2)
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet(aws_vpc.main.cidr_block, 8, count.index + 10)
availability_zone = data.aws_availability_zones.available.names[count.index]
tags = {
Name = "${local.name_prefix}-private-${count.index + 1}"
Tier = "Private"
}
}
# Internet Gateway per le subnet pubbliche
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id
tags = {
Name = "${local.name_prefix}-igw"
}
}
# Route table pubblica
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.main.id
}
tags = {
Name = "${local.name_prefix}-rt-public"
}
}
# Associazione route table - subnet pubblica
resource "aws_route_table_association" "public" {
count = length(aws_subnet.public)
subnet_id = aws_subnet.public[count.index].id
route_table_id = aws_route_table.public.id
}
# outputs.tf — valori di output
output "vpc_id" {
description = "ID della VPC creata"
value = aws_vpc.main.id
}
output "public_subnet_ids" {
description = "IDs delle subnet pubbliche"
value = aws_subnet.public[*].id
}
output "private_subnet_ids" {
description = "IDs delle subnet private"
value = aws_subnet.private[*].id
}
De cyclus Plan-Toepassen-Vernietigen
De levenscyclus van Terraform bestaat uit vier fundamentele opdrachten. Begrijp ze grondig Het is essentieel om de meest voorkomende ongelukken in de productie te voorkomen.
terraform init
# Inizializza il working directory:
# - Scarica i provider (plugin binaries)
# - Configura il backend per lo state
# - Installa i moduli referenziati
terraform init
# Output atteso:
# Initializing the backend...
# Initializing provider plugins...
# - Finding hashicorp/aws versions matching "~> 5.0"...
# - Installing hashicorp/aws v5.54.1...
# Terraform has been successfully initialized!
# Upgrade dei provider all'ultima versione compatibile
terraform init -upgrade
# Ricrea il .terraform.lock.hcl (file di lock dei provider)
terraform providers lock -platform=linux_amd64 -platform=darwin_amd64
Het .terraform.lock.hcl-bestand
Het bestand .terraform.lock.hcl moet worden vastgelegd in de repository.
Het zorgt ervoor dat alle teamleden en de CI-pijplijn exact dezelfde gebruiken
providers-versie, waarbij "werkt op mijn machine" voor infrastructuur wordt vermeden.
De map .terraform/ in plaats daarvan gaat het naar de .gitignore.
terraform plan
# Genera il piano di esecuzione (DRY RUN)
terraform plan
# Salva il piano in un file binario (consigliato per CI/CD)
terraform plan -out=tfplan
# Specifica le variabili inline
terraform plan -var="environment=staging" -var="instance_count=3"
# Usa un file di variabili
terraform plan -var-file="staging.tfvars"
# Output tipico di plan:
# Terraform will perform the following actions:
#
# # aws_vpc.main will be created
# + resource "aws_vpc" "main" {
# + arn = (known after apply)
# + cidr_block = "10.0.0.0/16"
# + enable_dns_hostnames = true
# ...
# }
#
# Plan: 8 to add, 0 to change, 0 to destroy.
Het symbool + duidt op schepping, ~ bewerking ter plaatse,
-/+ vernietigen en opnieuw creëren (downtime forceren), - vernietiging.
Lees de gemarkeerde blokken altijd goed door -/+:
ze betekenen dat de bron opnieuw moet worden aangemaakt, wat vaak downtime of gegevensverlies veroorzaakt.
terraform van toepassing
# Applica le modifiche (chiede conferma interattiva)
terraform apply
# Applica il piano salvato (NON chiede conferma - usare in CI/CD)
terraform apply tfplan
# Auto-approve per ambienti non critici (attento in prod!)
terraform apply -auto-approve
# Apply con variabili
terraform apply -var="environment=prod" -var-file="prod.tfvars"
# Output dopo apply:
# Apply complete! Resources: 8 added, 0 changed, 0 destroyed.
#
# Outputs:
# vpc_id = "vpc-0123456789abcdef0"
# public_subnet_ids = [
# "subnet-0abc123def456gh78",
# "subnet-0def456abc789ij01",
# ]
terraform vernietigen
# Distrugge TUTTE le risorse gestite dallo state corrente
terraform destroy
# Destroy con auto-approve (ATTENZIONE: irreversibile)
terraform destroy -auto-approve
# Distrugge solo una risorsa specifica (con grande cautela)
terraform destroy -target=aws_subnet.public[0]
# In produzione, preferisci eliminare le risorse dal codice
# e fare terraform apply: Terraform le distruggerà correttamente
Antipatroon: terraformvernietiging in productie
Nooit rennen terraform destroy zonder herstelplan.
De beste praktijk is om de bron uit de HCL-code te verwijderen en uit te voeren terraform apply:
je krijgt hetzelfde resultaat, maar met een expliciet plan dat je eerst kunt beoordelen.
Sommige organisaties blokkeren de mogelijkheid om vernietiging uit te voeren op IAM-beleidsniveau
op productieomgevingen.
Configureer de Azure-provider
De aanbieder azuurblauw beheert Azure-resources. In tegenstelling tot AWS, Azure gebruikt Service Principal of Managed Identity voor verificatie.
# versions.tf aggiornato con provider Azure
terraform {
required_version = ">= 1.8.0"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.100"
}
}
}
# Configurazione provider Azure
provider "azurerm" {
features {
resource_group {
prevent_deletion_if_contains_resources = true
}
key_vault {
purge_soft_delete_on_destroy = false
recover_soft_deleted_key_vaults = true
}
}
# Autenticazione via variabili d'ambiente (consigliato)
# ARM_CLIENT_ID, ARM_CLIENT_SECRET, ARM_TENANT_ID, ARM_SUBSCRIPTION_ID
# oppure Azure CLI: az login
}
# Risorse Azure di base
resource "azurerm_resource_group" "main" {
name = "${local.name_prefix}-rg"
location = "West Europe"
tags = local.common_tags
}
resource "azurerm_virtual_network" "main" {
name = "${local.name_prefix}-vnet"
address_space = ["10.1.0.0/16"]
location = azurerm_resource_group.main.location
resource_group_name = azurerm_resource_group.main.name
tags = local.common_tags
}
resource "azurerm_subnet" "public" {
name = "public-subnet"
resource_group_name = azurerm_resource_group.main.name
virtual_network_name = azurerm_virtual_network.main.name
address_prefixes = ["10.1.1.0/24"]
}
resource "azurerm_subnet" "private" {
name = "private-subnet"
resource_group_name = azurerm_resource_group.main.name
virtual_network_name = azurerm_virtual_network.main.name
address_prefixes = ["10.1.2.0/24"]
}
Variabelen, lokale waarden en gegevensbronnen
Een goed gebruik van variabelen, lokale waarden en gegevensbronnen onderscheidt een Terraform-configuratie professional vanuit een ad-hocscript. Hier zijn de basispatronen:
# Tipi di variabili in HCL
# Stringa semplice
variable "app_name" {
type = string
default = "myapp"
}
# Numero con validazione
variable "min_instances" {
type = number
default = 1
validation {
condition = var.min_instances >= 1 && var.min_instances <= 10
error_message = "Il numero di istanze deve essere tra 1 e 10."
}
}
# Lista di stringhe
variable "allowed_cidr_blocks" {
type = list(string)
default = ["10.0.0.0/8"]
}
# Map di stringhe
variable "database_config" {
type = map(string)
default = {
engine = "postgres"
version = "15.4"
size = "db.t3.medium"
}
}
# Oggetto con schema tipizzato
variable "network_config" {
type = object({
vpc_cidr = string
subnet_count = number
enable_nat = bool
})
default = {
vpc_cidr = "10.0.0.0/16"
subnet_count = 2
enable_nat = false
}
}
# Locals: valori computati (non input dall'utente)
locals {
# Concatenazioni
full_name = "${var.environment}-${var.app_name}"
# Condizionale ternario
instance_type = var.environment == "prod" ? "t3.medium" : "t3.micro"
# Ciclo su lista (for expression)
subnet_cidrs = [
for i in range(var.network_config.subnet_count) :
cidrsubnet(var.network_config.vpc_cidr, 8, i)
]
# Map transformation
tag_map = {
for k, v in var.database_config :
"db_${k}" => v
}
}
# Data sources: recuperano informazioni da risorse esistenti
# non gestite da questo state
# AMI Amazon Linux 2023 piu recente
data "aws_ami" "amazon_linux" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["al2023-ami-*-x86_64"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
}
# Account ID corrente (utile per ARN)
data "aws_caller_identity" "current" {}
# Uso nei resource:
# ami = data.aws_ami.amazon_linux.id
# account_id = data.aws_caller_identity.current.account_id
Het staatsdossier: het hart van Terraform
Het bestand terraform.tfstate is de "bron van de waarheid" van Terraform: breng elk bezit in kaart
gedefinieerd in HCL naar zijn echte tegenhanger in de cloud. Begrijpen hoe het werkt is essentieel
vermijd de ernstigste problemen.
// Struttura semplificata di terraform.tfstate
{
"version": 4,
"terraform_version": "1.9.0",
"serial": 42,
"lineage": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"outputs": {
"vpc_id": {
"value": "vpc-0123456789abcdef0",
"type": "string"
}
},
"resources": [
{
"mode": "managed",
"type": "aws_vpc",
"name": "main",
"provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
"instances": [
{
"schema_version": 1,
"attributes": {
"id": "vpc-0123456789abcdef0",
"cidr_block": "10.0.0.0/16",
"enable_dns_hostnames": true,
...
}
}
]
}
]
}
Gouden regels voor het staatsdossier
- Bewerk nooit
terraform.tfstatehandmatig - Nooit plegen vermeld het in uw Git-repository (voeg het toe aan
.gitignore) - Gebruik in teams altijd een externe backend met vergrendeling (zie artikel 03 van de serie)
- De staat kan het in bedwang houden geheimen in de openbaarheid (RDS-wachtwoord, inloggegevens): Behandel dit als gevoelige gegevens
- Vóór risicovolle operaties, voer een handmatige back-up uit:
terraform state pull > backup.tfstate
Commando's voor staatsinspectie
# Lista tutte le risorse gestite dallo state
terraform state list
# Mostra i dettagli di una risorsa specifica
terraform state show aws_vpc.main
# Rinomina una risorsa nello state (senza toccare l'infrastruttura)
terraform state mv aws_subnet.public aws_subnet.public_new
# Rimuove una risorsa dallo state (Terraform non la gestirà piu)
# La risorsa rimane nel cloud ma non è piu "owned" da Terraform
terraform state rm aws_subnet.private[0]
# Importa una risorsa esistente nello state
# (vedi articolo 03 per dettagli)
terraform import aws_vpc.main vpc-0123456789abcdef0
# Mostra l'output senza fare apply
terraform output vpc_id
terraform output -json # tutti gli output in formato JSON
Aanbevolen projectstructuur
Voor echte projecten wordt de enkele directorystructuur al snel onbeheersbaar. Hier zijn twee algemene patronen voor het organiseren van een Terraform-infrastructuur in productie:
# Pattern 1: Organizzazione per ambiente
infra/
├── modules/ # Moduli riusabili
│ ├── networking/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── outputs.tf
│ └── compute/
│ ├── main.tf
│ ├── variables.tf
│ └── outputs.tf
├── environments/
│ ├── dev/
│ │ ├── main.tf # Usa i moduli
│ │ ├── variables.tf
│ │ ├── terraform.tfvars # Valori specifici per dev
│ │ └── versions.tf
│ ├── staging/
│ │ └── ...
│ └── prod/
│ └── ...
└── .gitignore # Esclude .terraform/, *.tfstate
# Pattern 2: Terragrunt (wrapper per DRY)
infra/
├── terragrunt.hcl # Config globale
├── modules/
│ └── networking/
├── live/
│ ├── dev/
│ │ └── networking/
│ │ └── terragrunt.hcl
│ └── prod/
│ └── networking/
│ └── terragrunt.hcl
Beste praktijken om aan de slag te gaan
Na het zien van de theorie, volgen hier de vuistregels die degenen onderscheiden die Terraform gebruiken correct door degenen die vanaf dag één technische schulden creëren:
# 1. Formatta sempre prima di committare
terraform fmt -recursive
# 2. Valida la sintassi
terraform validate
# 3. Usa tflint per linting avanzato (trova deprecazioni, pattern errati)
tflint --init
tflint
# 4. Esegui checkov per security scanning
pip install checkov
checkov -d .
# 5. Pre-commit hooks per automatizzare tutto
# .pre-commit-config.yaml
# repos:
# - repo: https://github.com/antonbabenko/pre-commit-terraform
# hooks:
# - id: terraform_fmt
# - id: terraform_validate
# - id: terraform_tflint
# - id: terraform_checkov
De .gitignore voor Terraform
# .gitignore per progetti Terraform
.terraform/
*.tfstate
*.tfstate.backup
*.tfstate.*.backup
.terraform.tfstate.lock.info
*.tfvars # Se contengono segreti (crea terraform.tfvars.example)
override.tf
override.tf.json
*_override.tf
*_override.tf.json
crash.log
.terraformrc
terraform.rc
Compleet voorbeeld: webapp op AWS
Laten we het allemaal samenvatten in een echt voorbeeld: een EC2-instantie met beveiligingsgroep, load balancer en RDS-database, correct gestructureerd.
# main.tf — infrastruttura web app completa
# Security Group per le istanze web
resource "aws_security_group" "web" {
name = "${local.name_prefix}-sg-web"
description = "Security group per istanze web"
vpc_id = aws_vpc.main.id
ingress {
description = "HTTP dal load balancer"
from_port = 80
to_port = 80
protocol = "tcp"
security_groups = [aws_security_group.alb.id]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = { Name = "${local.name_prefix}-sg-web" }
}
# Security Group per ALB
resource "aws_security_group" "alb" {
name = "${local.name_prefix}-sg-alb"
description = "Security group per Application Load Balancer"
vpc_id = aws_vpc.main.id
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
# Launch Template per le istanze EC2
resource "aws_launch_template" "web" {
name_prefix = "${local.name_prefix}-lt-"
image_id = data.aws_ami.amazon_linux.id
instance_type = local.instance_type
network_interfaces {
associate_public_ip_address = false
security_groups = [aws_security_group.web.id]
}
user_data = base64encode(<<-EOF
#!/bin/bash
dnf update -y
dnf install -y nginx
systemctl enable nginx
systemctl start nginx
echo "Deploy Terraform - ${var.environment}
" > /usr/share/nginx/html/index.html
EOF
)
tag_specifications {
resource_type = "instance"
tags = merge(local.common_tags, {
Name = "${local.name_prefix}-web"
})
}
}
# Auto Scaling Group
resource "aws_autoscaling_group" "web" {
name = "${local.name_prefix}-asg"
vpc_zone_identifier = aws_subnet.private[*].id
target_group_arns = [aws_lb_target_group.web.arn]
health_check_type = "ELB"
min_size = var.environment == "prod" ? 2 : 1
max_size = var.environment == "prod" ? 6 : 2
desired_capacity = var.environment == "prod" ? 2 : 1
launch_template {
id = aws_launch_template.web.id
version = "$Latest"
}
tag {
key = "Name"
value = "${local.name_prefix}-web"
propagate_at_launch = true
}
}
# Application Load Balancer
resource "aws_lb" "main" {
name = "${local.name_prefix}-alb"
internal = false
load_balancer_type = "application"
security_groups = [aws_security_group.alb.id]
subnets = aws_subnet.public[*].id
enable_deletion_protection = var.environment == "prod"
tags = local.common_tags
}
resource "aws_lb_target_group" "web" {
name = "${local.name_prefix}-tg-web"
port = 80
protocol = "HTTP"
vpc_id = aws_vpc.main.id
health_check {
enabled = true
healthy_threshold = 2
unhealthy_threshold = 3
timeout = 5
interval = 30
path = "/health"
}
}
resource "aws_lb_listener" "http" {
load_balancer_arn = aws_lb.main.arn
port = "80"
protocol = "HTTP"
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.web.arn
}
}
Conclusies en volgende stappen
Je hebt nu een stevige basis om professioneel met Terraform aan de slag te gaan: je kent de syntaxis HCL, je weet hoe je AWS- en Azure-providers moet configureren, je begrijpt de Plan-Apply-Destroy-cyclus en de regels essentieel om het statusdossier veilig te beheren.
De volgende natuurlijke stap in uw groei met Terraform is het leren organiseren van uw code binnen herbruikbare modules: Zodra uw infrastructuur 200-300 lijnen overschrijdt van HCL wordt modularisering essentieel voor onderhoudbaarheid.
De complete serie: Terraform en IaC
- Artikel 01 (dit) - Terraform from Scratch: HCL, Provider en Plan-Apply-Destroy
- Artikel 02 — Herbruikbare Terraform-modules ontwerpen: structuur, I/O en register
- Artikel 03 — Terraform State: externe backend met S3/GCS, vergrendelen en importeren
- Artikel 04 — Terraform in CI/CD: GitHub-acties, Atlantis en Pull Request Workflow
- Artikel 05 — IaC-testen: Terratest, Terraform Native Test en Contracttesten
- Artikel 06 — IaC-beveiliging: Checkov, Trivy en OPA Policy-as-Code
- Artikel 07 — Terraform Multi-Cloud: AWS + Azure + GCP met gedeelde modules
- Artikel 08 — GitOps voor Terraform: Flux TF-controller, Spacelift en driftdetectie
- Artikel 09 — Terraform versus Pulumi versus OpenTofu: definitieve vergelijking 2026
- Artikel 10 — Terraform Enterprise-patronen: werkruimte, Sentinel en teamschaling
Officiële bronnen
- Officiële Terraform-documentatie
- Terraform-register — aanbieders, modules en beleid
- HashiCorp Learn — Interactieve tutorials







