Curso: BluePrints / ARSW
Duración estimada: 2–3 horas (base) + 1–2 horas (retos)
Última actualización: 2025-11-09
Modernizar el laboratorio de balanceo de carga en Azure usando Terraform para definir, aprovisionar y versionar la infraestructura. El objetivo es que los estudiantes diseñen y desplieguen una arquitectura reproducible, segura y con buenas prácticas de IaC.
- Modelar infraestructura de Azure con Terraform (providers, state, módulos y variables).
- Desplegar una arquitectura de alta disponibilidad con Load Balancer (L4) y 2+ VMs Linux.
- Endurecer mínimamente la seguridad: NSG, SSH por clave, tags, naming conventions.
- Integrar backend remoto para el state en Azure Storage con state locking.
- Automatizar plan/apply desde GitHub Actions con autenticación OIDC (sin secretos largos).
- Validar operación (health probe, página de prueba), observar costos y destruir con seguridad.
Nota: Este lab reemplaza la versión clásica basada en acciones manuales. Enfócate en IaC y pipelines.
- Resource Group (p. ej.
rg-lab8-<alias>) - Virtual Network con 2 subredes:
subnet-web: VMs detrás de Azure Load Balancer (público)subnet-mgmt: Bastion o salto (opcional)
- Network Security Group: solo permite 80/TCP (HTTP) desde Internet al LB y 22/TCP (SSH) solo desde tu IP pública.
- Load Balancer público:
- Frontend IP pública
- Backend pool con 2+ VMs
- Health probe (TCP/80 o HTTP)
- Load balancing rule (80 → 80)
- 2+ VMs Linux (Ubuntu LTS) con cloud-init/Custom Script Extension para instalar nginx y servir una página con el hostname.
- Azure Storage Account + Container para Terraform remote state (con bloqueo).
- Etiquetas (tags):
owner,course,env,expires.
Opcional (retos): usar VM Scale Set, o reemplazar LB por Application Gateway (L7).
- Cuenta/Subscription en Azure (Azure for Students o equivalente).
- Azure CLI (
az) y Terraform >= 1.6 instalados en tu equipo. - SSH key generada (ej.
ssh-keygen -t ed25519). - Cuenta en GitHub para ejecutar el pipeline de Actions.
.
├─ infra/
│ ├─ main.tf
│ ├─ providers.tf
│ ├─ variables.tf
│ ├─ outputs.tf
│ ├─ backend.hcl.example
│ ├─ cloud-init.yaml
│ └─ env/
│ ├─ dev.tfvars
│ └─ prod.tfvars (opcional)
├─ modules/
│ ├─ vnet/
│ │ ├─ main.tf
│ │ ├─ variables.tf
│ │ └─ outputs.tf
│ ├─ compute/
│ │ ├─ main.tf
│ │ ├─ variables.tf
│ │ └─ outputs.tf
│ └─ lb/
│ ├─ main.tf
│ ├─ variables.tf
│ └─ outputs.tf
└─ .github/workflows/terraform.yml
Primero crea el Resource Group, Storage Account y Container para el state:
# Nombres únicos
SUFFIX=$RANDOM
LOCATION=eastus
RG=rg-tfstate-lab8
STO=sttfstate${SUFFIX}
CONTAINER=tfstate
az group create -n $RG -l $LOCATION
az storage account create -g $RG -n $STO -l $LOCATION --sku Standard_LRS --encryption-services blob
az storage container create --name $CONTAINER --account-name $STOCompleta infra/backend.hcl.example con los valores creados y renómbralo a backend.hcl.
En infra/variables.tf define:
prefix,location,vm_count,admin_username,ssh_public_keyallow_ssh_from_cidr(tu IPv4 en /32)tags(map)
En infra/env/dev.tfvars:
prefix = "lab8"
location = "eastus"
vm_count = 2
admin_username= "student"
ssh_public_key= "~/.ssh/id_ed25519.pub"
allow_ssh_from_cidr = "X.X.X.X/32" # TU IP
tags = { owner = "tu-alias", course = "ARSW/BluePrints", env = "dev", expires = "2025-12-31" }Archivo infra/cloud-init.yaml (instala nginx y muestra el hostname):
#cloud-config
package_update: true
packages:
- nginx
runcmd:
- echo "Hola desde $(hostname)" > /var/www/html/index.nginx-debian.html
- systemctl enable nginx
- systemctl restart nginxcd infra
# Autenticación en Azure
az login
az account show # verifica la suscripción activa
# Inicializa Terraform con backend remoto
terraform init -backend-config=backend.hcl
# Revisión rápida
terraform fmt -recursive
terraform validate
# Plan con variables de dev
terraform plan -var-file=env/dev.tfvars -out plan.tfplan
# Apply
terraform apply "plan.tfplan"
# Verifica el LB público (cambia por tu IP)
curl http://$(terraform output -raw lb_public_ip)Outputs esperados (ejemplo):
lb_public_ipresource_group_namevm_names
El workflow .github/workflows/terraform.yml:
- Ejecuta
fmt,validateyplanen cada PR. - Publica el plan como artefacto/comentario.
- Job manual
applycon workflow_dispatch y aprobación.
Configura OIDC en Azure (federación con tu repositorio) y asigna el rol Contributor al principal del workflow sobre el RG del lab.
- Repositorio GitHub del equipo con:
- Código Terraform (módulos) y
cloud-init.yaml. backend.hcl(sin secretos) yenv/dev.tfvars(sin llaves privadas).- Workflow de GitHub Actions y evidencias del
plan.
- Código Terraform (módulos) y
- Diagrama (componente y secuencia) del caso de estudio propuesto.
- URL/IP pública del Load Balancer + captura mostrando respuesta de 2 VMs (p. ej. refrescar y ver hostnames cambiar).
- Reflexión técnica (1 página máx.): decisiones, trade‑offs, costos aproximados y cómo destruir seguro.
- Limpieza: confirmar
terraform destroyal finalizar.
- Infra desplegada y funcional (40 pts): LB, 2+ VMs, health probe, NSG correcto.
- Buenas prácticas Terraform (20 pts): módulos, variables,
fmt/validate, remote state. - Seguridad y costos (15 pts): SSH por clave, NSG mínimo, tags y naming; estimación de costos.
- CI/CD (15 pts): pipeline con
planautomático yapplymanual (OIDC). - Documentación y diagramas (10 pts): README del equipo, diagramas claros y reflexión.
- Migrar a VM Scale Set con Custom Script Extension o cloud-init.
- Reemplazar LB por Application Gateway con probe HTTP y path-based routing (si exponen múltiples apps).
- Azure Bastion para acceso SSH sin IP pública en VMs.
- Alertas de Azure Monitor (p. ej. estado del probe) y Budget alert.
- Módulos privados versionados con semantic versioning.
terraform destroy -var-file=env/dev.tfvarsTip: Mantén los recursos etiquetados con
expiresy elimina todo al terminar.
- ¿Por qué L4 LB vs Application Gateway (L7) en tu caso? ¿Qué cambiaría?
- ¿Qué implicaciones de seguridad tiene exponer 22/TCP? ¿Cómo mitigarlas?
- ¿Qué mejoras harías si esto fuera producción? (resiliencia, autoscaling, observabilidad).
- Azure, Terraform, IaC, LB y VMSS (docs oficiales) — revisa enlaces en clase.