🧰 Instalación de herramientas y arranque de Topaz¶
1. Qué se instala y para qué¶
| Herramienta | Versión del curso | Para qué |
|---|---|---|
| Terraform | 1.11.x, fijada con tenv |
Todo el curso. La versión fijada garantiza que tu plan y el del pipeline coinciden |
| Azure CLI | 2.7x o superior |
Autenticación (el provider la reutiliza), comprobaciones fuera de Terraform, provocar derivas en los laboratorios |
| Docker | Engine o Desktop | Ejecutar Topaz |
| Git | 2.4x | Versionado desde la página 1; pipelines desde la 13 |
| jq | 1.7 | Leer terraform show -json y salidas de az: aparece en casi todos los laboratorios |
| Editor | VS Code + extensión HashiCorp Terraform | Formato, validación y autocompletado del provider. Opcional pero muy recomendable |
| tflint, trivy, gitleaks | Se instalan en la página 13 | Comprobaciones del pipeline; no hacen falta todavía |
| Azure PowerShell | No se usa | El original lo lista como opcional. El curso es bash + az; dos CLIs para lo mismo es una fuente de confusión |
2. Instalación por sistema¶
La ruta canónica del curso es Ubuntu (nativo o en WSL2). macOS va con Homebrew. En Windows sin WSL2 se puede seguir con winget, pero los scripts de los laboratorios son bash y habría que traducirlos.
# ─── Ubuntu 22.04 / 24.04 (también WSL2) ─────────────────────────────────────────
sudo apt-get update && sudo apt-get install -y ca-certificates curl gnupg lsb-release git jq unzip
# Azure CLI desde el repositorio de Microsoft (no "curl | sudo bash": un fichero remoto ejecutado como root sin leerlo)
sudo mkdir -p /etc/apt/keyrings
curl -sLS https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor | sudo tee /etc/apt/keyrings/microsoft.gpg >/dev/null
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/microsoft.gpg] https://packages.microsoft.com/repos/azure-cli/ $(lsb_release -cs) main" \
| sudo tee /etc/apt/sources.list.d/azure-cli.list
sudo apt-get update && sudo apt-get install -y azure-cli
# Terraform con tenv: gestor de versiones (lee .terraform-version y required_version)
curl -sLO https://github.com/tofuutils/tenv/releases/latest/download/tenv_$(curl -s https://api.github.com/repos/tofuutils/tenv/releases/latest | jq -r .tag_name)_amd64.deb
sudo dpkg -i tenv_*_amd64.deb && rm tenv_*_amd64.deb
tenv tf install 1.11.4 && tenv tf use 1.11.4 # ajusta al último parche 1.11.x
# Alternativa sin gestor: repositorio apt de HashiCorp (ver referencias); o binario + comprobación de SHA256SUMS. Nunca "el que haya en PATH".
# Docker Engine (en WSL2 también vale Docker Desktop con integración WSL activada)
curl -fsSL https://get.docker.com -o get-docker.sh && less get-docker.sh # léelo antes: es lo que no hacíamos con la CLI
sudo sh get-docker.sh && sudo usermod -aG docker "$USER" && newgrp docker
# ─── macOS ───────────────────────────────────────────────────────────────────────
brew install azure-cli git jq tenv && brew install --cask docker
tenv tf install 1.11.4 && tenv tf use 1.11.4
# ─── Windows sin WSL2 (no recomendado para el curso) ─────────────────────────────
winget install Microsoft.AzureCLI Git.Git jqlang.jq Docker.DockerDesktop Hashicorp.Terraform
# ─── Comprobar versiones (esto NO es la verificación; la verificación es 3.6) ────
terraform version -json | jq -r .terraform_version # 1.11.x
az version --query '"azure-cli"' -o tsv # 2.7x
docker --version && git --version && jq --version
3. Por qué la versión va fijada, en dos sitios¶
Terraform cambia el formato del estado y el comportamiento del plan entre versiones menores. Si tú planificas con 1.11 y el pipeline aplica con 1.9, el plan no coincide, o el estado escrito por uno no lo lee el otro. La versión se fija en dos sitios que se refuerzan:
.terraform-versionen la raíz del repositorio:tenv(y su antecesortfenv) lo leen y cambian de binario al entrar en el directorio. Es para las personas.required_versionen el bloqueterraform {}: si el binario no cumple,initfalla. Es para el pipeline y para quien no usa gestor.
Lo mismo aplica al provider: version = "~> 4.20" acepta parches y menores de la 4, no la 5. Y .terraform.lock.hcl, que init genera, fija el parche exacto y sus sumas; va al repositorio (página 4).
4. Topaz: arrancar, registrar, autenticarse¶
Topaz es un contenedor que implementa la API de Azure Resource Manager. Para que az y Terraform hablen con él en lugar de con Azure hacen falta tres cosas: que az lo conozca como una nube más (az cloud register), que confíe en su certificado, y que la sesión contra él no se mezcle con la de Azure real. Esto último se consigue con un directorio de configuración separado (AZURE_CONFIG_DIR): dos "perfiles" de az que no se ven entre sí.
⚠️ Valores que dependen de la versión de Topaz. Imagen, puerto, ruta de metadatos y certificado cambian entre versiones del emulador. Están en las variables del principio del laboratorio; contrástalas con el README del repositorio antes de ejecutar. El resto (cómo se registra una nube, cómo confía cada herramienta en un certificado, cómo se configura el provider) es estable.
5. El providers.tf del curso¶
Este fichero se copia desde ~/tf-st en todos los laboratorios. Cada línea tiene un motivo.
terraform {
required_version = "~> 1.11" # 3.3: falla el init si el binario no cumple
required_providers {
azurerm = { source = "hashicorp/azurerm", version = "~> 4.20" }
}
}
provider "azurerm" {
features {}
# Nube: si metadata_host está vacío, el provider habla con Azure público. Si apunta al emulador,
# descarga de ahí los endpoints (ARM, autenticación, storage…) y no toca Azure. Es el interruptor.
metadata_host = var.metadata_host
# azurerm 4.x exige subscription_id explícito: ya no lo toma del contexto de az. Es una protección:
# obliga a decir a qué suscripción se aplica. En Topaz, la que el emulador expone; en real, la tuya.
subscription_id = var.subscription_id
tenant_id = var.tenant_id
# Autenticación: la sesión de az. Ni client_secret ni contraseñas aquí, nunca (página 12: OIDC en el pipeline).
use_cli = true
# El emulador no registra proveedores de recursos; en Azure real, el registro lo hace la plataforma (página 12)
resource_provider_registrations = "none"
# Hablar con storage con Entra ID, no con claves: coherente con shared_access_key_enabled = false en todo el curso
storage_use_azuread = true
}
variable "metadata_host" { type = string, default = "" } # vacío = Azure público. El valor de Topaz llega por TF_VAR_metadata_host
variable "subscription_id" { type = string }
variable "tenant_id" { type = string }
Las tres variables no tienen valor en el código: llegan por entorno (TF_VAR_*) desde el script topaz.env del laboratorio. Así el mismo providers.tf sirve para el emulador y para Azure real, y el cambio entre ambos es cambiar de entorno, no editar código.
6. Laboratorio: arrancar Topaz y verificar con un apply¶
# ─── 0. Valores de tu versión de Topaz: contrástalos con el README ──────────────
TOPAZ_IMAGE=ghcr.io/azure/azure-local-emulator:latest # o el nombre que indique el README
TOPAZ_PORT=8899
TOPAZ_HOST=localhost
TOPAZ_META=https://$TOPAZ_HOST:$TOPAZ_PORT # host de metadatos: debe responder en /metadata/endpoints?api-version=2022-09-01
# ─── 1. Arrancar el emulador ─────────────────────────────────────────────────────
docker volume create topaz-datos # los recursos sobreviven a reinicios del contenedor
docker run -d --name topaz --restart unless-stopped -p $TOPAZ_PORT:$TOPAZ_PORT -v topaz-datos:/data "$TOPAZ_IMAGE"
sleep 5 && docker logs topaz --tail 5
curl -sk "$TOPAZ_META/metadata/endpoints?api-version=2022-09-01" | jq '{arm: .resourceManager, login: .authentication.loginEndpoint}'
# Si esto responde con JSON, el emulador está vivo y expone lo que az y Terraform necesitan.
# ─── 2. Certificado: que az (Python) y Terraform (Go) confíen en él ──────────────
mkdir -p ~/.topaz && docker cp topaz:/certs/topaz.crt ~/.topaz/topaz.crt 2>/dev/null \
|| openssl s_client -connect $TOPAZ_HOST:$TOPAZ_PORT -showcerts </dev/null 2>/dev/null | openssl x509 > ~/.topaz/topaz.crt
# Opción limpia: añadirlo al almacén del sistema (Ubuntu): sudo cp ~/.topaz/topaz.crt /usr/local/share/ca-certificates/ && sudo update-ca-certificates
# Opción por proceso (la que usa topaz.env): REQUESTS_CA_BUNDLE para az, SSL_CERT_FILE para Terraform.
# ─── 3. Perfil de az separado para Topaz, y la nube registrada ──────────────────
cat > ~/.topaz/topaz.env <<EOF
# source ~/.topaz/topaz.env → esta terminal habla con el emulador
export AZURE_CONFIG_DIR=~/.azure-topaz # sesión y nube propias: no toca ~/.azure (Azure real)
export REQUESTS_CA_BUNDLE=~/.topaz/topaz.crt
export SSL_CERT_FILE=~/.topaz/topaz.crt
export ARM_METADATA_HOSTNAME=$TOPAZ_HOST:$TOPAZ_PORT # el provider también lo lee de aquí
export TF_VAR_metadata_host=$TOPAZ_HOST:$TOPAZ_PORT
export TF_VAR_subscription_id=\$(az account show --query id -o tsv 2>/dev/null)
export TF_VAR_tenant_id=\$(az account show --query tenantId -o tsv 2>/dev/null)
export PS1="(topaz) \$PS1" # que se vea en el prompt
EOF
source ~/.topaz/topaz.env
az cloud register -n Topaz --endpoint-resource-manager "$TOPAZ_META" \
--endpoint-active-directory "$(curl -sk "$TOPAZ_META/metadata/endpoints?api-version=2022-09-01" | jq -r .authentication.loginEndpoint)" \
--endpoint-active-directory-resource-id "$TOPAZ_META" --suffix-storage-endpoint "$TOPAZ_HOST:$TOPAZ_PORT"
# Si tu versión trae un script de registro (topaz-cli o similar), úsalo: hace exactamente esto con los sufijos correctos.
az cloud set -n Topaz
az login # el emulador acepta cualquier identidad; en Azure real abriría el navegador
az account show --query "{nube:environmentName, sub:id, tenant:tenantId}" -o table # environmentName = Topaz
source ~/.topaz/topaz.env # ahora TF_VAR_subscription_id y tenant_id tienen valor
# ─── 4. El providers.tf del curso ────────────────────────────────────────────────
mkdir -p ~/tf-st && cd ~/tf-st && git init -q
# guarda aquí el providers.tf de 3.5
echo "1.11.4" > .terraform-version
terraform init # descarga azurerm ~> 4.20 y escribe .terraform.lock.hcl
git add . && git commit -qm "providers.tf del curso"
# ─── 5. La verificación de verdad: un recurso creado y borrado ───────────────────
cat > verificacion.tf <<'EOF'
resource "azurerm_resource_group" "verificacion" { name = "rg-verificacion", location = "eastus" }
EOF
az account show --query environmentName -o tsv # Topaz ← siempre, antes de aplicar
terraform plan # Plan: 1 to add
terraform apply -auto-approve
az group show -n rg-verificacion --query name -o tsv # az y Terraform ven el mismo recurso en el mismo emulador
terraform destroy -auto-approve && rm verificacion.tf
# Si esto funciona, funciona todo lo que el curso necesita: autenticación, provider, ARM emulado, estado local.
# ─── 6. El interruptor: volver a Azure real (solo si tienes suscripción) ─────────
# Abre OTRA terminal sin hacer source de topaz.env: AZURE_CONFIG_DIR apunta a ~/.azure, la nube es AzureCloud, TF_VAR_metadata_host está vacío.
az cloud set -n AzureCloud && az login && az account set --subscription "<tu suscripción>"
az account show --query environmentName -o tsv # AzureCloud
export TF_VAR_subscription_id=$(az account show --query id -o tsv) TF_VAR_tenant_id=$(az account show --query tenantId -o tsv)
# Regla del curso: una terminal por nube. El prompt "(topaz)" dice en cuál estás. Y antes de cada apply, az account show.
7. Errores comunes¶
| Mensaje o síntoma | Causa y solución |
|---|---|
curl … \| sudo bash para instalar la CLI (el original) |
Ejecuta como root un fichero que no has leído y que puede cambiar mañana. Repositorio apt con clave, o al menos descargar, leer y ejecutar. En un curso de IaC, la instalación también es código revisable |
Error: Unsupported Terraform Core version |
required_version hace su trabajo: el binario no es 1.11.x. tenv tf use 1.11.4, o entra en el directorio con .terraform-version |
Error: "subscription_id" is required al hacer plan |
azurerm 4.x lo exige. TF_VAR_subscription_id está vacío: haz az login primero y vuelve a hacer source topaz.env |
x509: certificate signed by unknown authority (Terraform) o SSLError … CERTIFICATE_VERIFY_FAILED (az) |
Cada herramienta tiene su cadena de confianza: SSL_CERT_FILE para Go, REQUESTS_CA_BUNDLE para Python. Las dos van en topaz.env; o añade el certificado al sistema |
| El apply de verificación crea el grupo en Azure real | Terminal sin source topaz.env, o TF_VAR_metadata_host vacío. Por eso el paso 5 empieza con az account show. Borra el grupo (az group delete) y revisa el prompt |
connection refused en localhost:8899 |
El contenedor no está o el puerto es otro: docker ps, docker logs topaz. En Docker Desktop con WSL2, comprueba que la integración con tu distro está activada |
az cloud register falla por sufijos o endpoints |
Cada versión de Topaz expone endpoints distintos. Lee /metadata/endpoints con curl y usa esos valores; si el README trae un script de registro, es la fuente de verdad |
| Los recursos desaparecen al reiniciar el contenedor | Sin volumen, el emulador arranca vacío y el estado de Terraform apunta a recursos que ya no existen. -v topaz-datos:/data (ruta según README); si ya pasó, terraform state rm o borrar el estado local del laboratorio |
| Un tipo de recurso devuelve not supported en Topaz | Esperado: el emulador cubre una lista de proveedores. Cada página marca qué va a Azure real. Consulta la lista de tu versión |
az login en Topaz abre el navegador o pide credenciales reales |
La nube activa es AzureCloud: AZURE_CONFIG_DIR no está exportado. source topaz.env y az cloud set -n Topaz |
| "Instalo Azure PowerShell también, por si acaso" (el original) | Dos CLIs con sesiones y nubes propias duplican los sitios donde equivocarse de destino. El curso usa solo az |
8. Autoevaluación¶
-
¿Por qué la verificación es un apply y no
--version?
Porque una versión impresa no prueba autenticación, provider, certificado ni emulador. Crear y borrar un recurso prueba los cuatro. -
¿En qué dos sitios se fija la versión de Terraform y para quién es cada uno?
.terraform-versionpara las personas (el gestor cambia de binario);required_versionpara el pipeline (el init falla si no cumple). -
¿Qué hace
metadata_host?
Indica al provider de dónde descargar los endpoints de la nube. Vacío: Azure público. Apuntando a Topaz: el emulador. Es el interruptor. -
¿Por qué azurerm 4.x exige
subscription_id?
Para que el destino sea explícito y no dependa del contexto deaz: una protección contra aplicar en la suscripción equivocada. -
¿Para qué sirve
AZURE_CONFIG_DIRen el curso?
Separa la sesión y la nube de Topaz de las de Azure real; dos perfiles que no se ven entre sí. Una terminal por nube. -
¿Por qué hay dos variables de certificado en
topaz.env?
Terraform (Go) leeSSL_CERT_FILE;az(Python) leeREQUESTS_CA_BUNDLE. Cadenas de confianza distintas. -
¿Qué credenciales hay en
providers.tf?
Ninguna.use_cli = truereutiliza la sesión deaz; en el pipeline será OIDC. Un secreto enprovideracaba en Git. -
¿Qué pasa si el contenedor arranca sin volumen?
El emulador olvida los recursos y el estado de Terraform queda apuntando a nada. Volumen siempre; si pasa, limpiar el estado. -
¿Qué comprobación va antes de cada apply, y qué debe devolver?
az account show --query environmentName:Topazen los laboratorios,AzureCloudsolo en los bloques marcados. -
¿Por qué el curso no instala Azure PowerShell?
Es una segunda CLI con su propia sesión y nube: duplica los sitios donde equivocarse de destino sin aportar nada queazno haga.
9. Referencias¶
- Azure Local Emulator (Topaz): README con imagen, puerto, certificado y proveedores emulados por versión
- Instalar Azure CLI en Linux (apt) y nubes en Azure CLI (
az cloud register) - Configuración de Azure CLI (
AZURE_CONFIG_DIR,REQUESTS_CA_BUNDLE) - Instalar Terraform (repositorio apt, Homebrew, binarios con sumas) y tenv
required_versiony fichero de bloqueo de dependencias- Argumentos del provider azurerm (
metadata_host,use_cli,resource_provider_registrations,storage_use_azuread) y guía de migración a 4.0 (subscription_idobligatorio) - Instalar Docker Engine en Ubuntu y Docker Desktop con WSL2
- Instalar WSL2 (Microsoft Learn)
- Extensión HashiCorp Terraform para VS Code
- Manual de jq