🚀 Entorno Práctico: Terraform + Azure Emulator + Topaz en Docker¶
Contenido¶
- Preparación del Host
- Cómo Iniciar el Entorno
- Descripción del Entorno
- Ejemplos Prácticos
- Operaciones sobre el Contenedor
- Desplegar con Terraform
- Notas Importantes
🖥️ Preparación del Host (Ubuntu 24.04 LTS)¶
El entorno se ejecuta sobre Ubuntu 24.04.5 LTS (Noble Numbat). Antes de arrancar el contenedor es necesario instalar Docker desde el repositorio oficial, disponer de los repositorios de Azure CLI y HashiCorp, y configurar la resolución local del nombre topaz.local.dev.
1. Instalar Docker Engine¶
Primero, instala los prerrequisitos y añade la clave GPG oficial de Docker:
sudo apt-get update
sudo apt-get install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
A continuación, registra el repositorio de Docker en APT:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
Instala Docker Engine, la CLI, containerd y los plugins de Buildx y Compose:
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Comprueba que el servicio está activo y funciona correctamente:
Nota: Para ejecutar Docker sin
sudo, añade tu usuario al grupodockerconsudo usermod -aG docker $USERy vuelve a iniciar sesión. Si tenías instalados paquetes no oficiales (docker.io,docker-compose,podman-docker,containerd,runc), elimínalos antes consudo apt-get removepara evitar conflictos.
2. Repositorios APT Configurados¶
Tras la instalación, el host terraform00 dispone de los siguientes orígenes de paquetes en /etc/apt/sources.list.d/azure-cli.sources:
Azure CLI — /etc/apt/sources.list.d/azure-cli.sources (formato DEB822):
Types: deb
URIs: https://packages.microsoft.com/repos/azure-cli/
Suites: noble
Components: main
Architectures: amd64
Signed-by: /etc/apt/keyrings/microsoft.gpg
Docker — /etc/apt/sources.list.d/docker.list:
deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu noble stable
HashiCorp (Terraform) — /etc/apt/sources.list.d/hashicorp.list:
deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com noble main
Ubuntu — /etc/apt/sources.list.d/ubuntu.sources (formato DEB822, réplica española + seguridad):
Types: deb
URIs: http://es.archive.ubuntu.com/ubuntu/
Suites: noble noble-updates noble-backports
Components: main restricted universe multiverse
Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg
Types: deb
URIs: http://security.ubuntu.com/ubuntu/
Suites: noble-security
Components: main restricted universe multiverse
Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg
Nota: Con estos repositorios registrados, Azure CLI y Terraform se instalan directamente con
sudo apt-get install azure-cli terraform. Ubuntu 24.04 combina dos formatos: el clásico de una línea (.list) y el nuevo DEB822 (.sources); ambos son válidos y APT los procesa indistintamente.
3. Solución de Problemas: Error NO_PUBKEY¶
Si al ejecutar apt-get update aparecen errores como estos, APT está encontrando los repositorios pero no dispone de las claves públicas necesarias para verificar sus firmas:
Err:6 https://apt.releases.hashicorp.com noble InRelease
Las firmas siguientes no se pudieron verificar porque su clave pública no está disponible: NO_PUBKEY AA16FCBCA621E701
Err:7 https://packages.microsoft.com/repos/azure-cli noble InRelease
Las firmas siguientes no se pudieron verificar porque su clave pública no está disponible: NO_PUBKEY EB3E94ADBE1229CF
E: El repositorio «https://apt.releases.hashicorp.com noble InRelease» no está firmado.
E: El repositorio «https://packages.microsoft.com/repos/azure-cli noble InRelease» no está firmado.
Causa: los archivos hashicorp.list y azure-cli.sources referencian mediante signed-by dos keyrings (/usr/share/keyrings/hashicorp-archive-keyring.gpg y /etc/apt/keyrings/microsoft.gpg) que no existen en el host o están corruptos. Es habitual cuando se copian los archivos de sources.list.d/ de una máquina a otra sin copiar también las claves. Puedes confirmarlo así:
Solución: descarga cada clave y guárdala en la ruta exacta que espera su archivo de repositorio.
Clave de HashiCorp (ID AA16FCBCA621E701):
sudo apt-get install -y gnupg curl
curl -fsSL https://apt.releases.hashicorp.com/gpg | \
sudo gpg --dearmor --yes -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
sudo chmod a+r /usr/share/keyrings/hashicorp-archive-keyring.gpg
Clave de Microsoft (ID EB3E94ADBE1229CF):
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://packages.microsoft.com/keys/microsoft.asc | \
sudo gpg --dearmor --yes -o /etc/apt/keyrings/microsoft.gpg
sudo chmod a+r /etc/apt/keyrings/microsoft.gpg
Verifica que las claves descargadas contienen los IDs que APT reclamaba y vuelve a actualizar los índices:
gpg --show-keys /usr/share/keyrings/hashicorp-archive-keyring.gpg | grep -i AA16FCBCA621E701
gpg --show-keys /etc/apt/keyrings/microsoft.gpg | grep -i EB3E94ADBE1229CF
sudo apt-get update
Si todo es correcto, las líneas 6 y 7 pasarán de Err a Des/Obj y desaparecerán los avisos W: Error de GPG. Ya puedes instalar las herramientas:
Nota:
gpg --dearmorconvierte la clave de formato ASCII (.asc) a binario, que es el que esperasigned-bycuando el archivo termina en.gpg. La opción--yessobrescribe un keyring previo si estaba dañado. Evita el antiguoapt-key add: está obsoleto en Ubuntu 24.04 y añade las claves de forma global, lo que permitiría a cualquier repositorio firmar paquetes con ellas.
4. Resolución de Nombres: /etc/hosts¶
El emulador se publica bajo el nombre topaz.local.dev, que es el nombre para el que está emitido su certificado TLS. Ese nombre debe resolver a la propia máquina. En terraform00 el archivo /etc/hosts queda así (la última línea es la que importa):
127.0.0.1 localhost
127.0.1.1 curso
# The following lines are desirable for IPv6 capable hosts
::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
127.0.0.1 topaz.local.dev
Para añadir la entrada en cualquier host que aún no la tenga (el grep evita duplicarla) y comprobar la resolución:
grep -q 'topaz.local.dev' /etc/hosts || echo '127.0.0.1 topaz.local.dev' | sudo tee -a /etc/hosts
getent hosts topaz.local.dev
# Salida esperada: 127.0.0.1 topaz.local.dev
Nota: No sustituyas
topaz.local.devporlocalhosten las URLs: el certificado no incluye ese nombre y la validación TLS fallaría. Sigetentno devuelve nada o devuelve una IP distinta de127.0.0.1, la entrada falta o está mal escrita.
📌 Cómo Iniciar el Entorno¶
Para arrancar el entorno en Docker, ejecuta el siguiente comando en tu terminal:
Nota: Este comando descargará la imagen (si no la tienes) y ejecutará el contenedor en segundo plano (
-d). Todos los servicios estarán disponibles en el puerto8899.
Credenciales del Emulador¶
El emulador incluye una identidad de administrador predefinida. Se utiliza al iniciar sesión desde la página de autenticación por código de dispositivo (https://topaz.local.dev:8899/devicelogin):
| Campo | Valor |
|---|---|
| Usuario | topazadmin@topaz.local.dev |
| Contraseña | admin |
Nota: Estas credenciales son exclusivas del emulador local y no tienen ninguna relación con cuentas reales de Azure o Microsoft Entra ID.
🔧 Descripción del Entorno¶
1. Azure Emulator (v1.10.222-preview)¶
Simula servicios clave de Azure en local:
| Servicio | Endpoint | Descripción |
|---|---|---|
| Azure Storage | Https: 8899 | Blobs, tablas y colas. |
| Resource Manager | Https: 8899 | Grupos de recursos y suscripciones. |
| Key Vault | Https: 443, 8898, 8899 | Secretos y claves seguras. |
| Virtual Machines | Https: 8899 | Máquinas virtuales simuladas. |
| App Service | Https: 8899 (Web), 8896 (Kudu) | Entorno para aplicaciones web. |
2. Topaz Services¶
Herramientas adicionales para observabilidad y gestión:
- FinOps: Monitoreo de costos y optimización (puerto 8899).
- Chaos Engineering: Simulación de fallos (puerto 8899).
- Forward Proxy: Proxy inverso para servicios internos (puerto 8900).
3. Servicios de Background¶
Tareas automáticas para mantener el entorno:
- Purga de Key Vault: cada 1 hora.
- Sincronización de Storage: cada 30 segundos.
- Expiración de mensajes en Service Bus: cada 30 segundos.
4. Acceder a los Servicios¶
Todos los endpoints están disponibles en https://topaz.local.dev:8899 (usa el ID de suscripción genérico).
Para el Forward Proxy de Topaz, usa el puerto 8900.
🔄 Operaciones sobre el Contenedor¶
Comandos para inspeccionar, respaldar, reiniciar y verificar el contenedor azure-environment, exportar su certificado y conectar la CLI de Azure con el emulador. El orden de los pasos importa: cada uno depende del anterior.
1. Inspeccionar el Contenedor¶
Muestra la imagen base, el directorio de trabajo y los volúmenes montados:
docker inspect azure-environment \
--format 'Imagen={{.Config.Image}} Directorio={{.Config.WorkingDir}} Mounts={{json .Mounts}}'
2. Respaldar y Recrear el Contenedor¶
Este bloque detiene el contenedor, guarda su estado actual como una nueva imagen etiquetada con la fecha, renombra el contenedor original como respaldo y arranca uno nuevo a partir de la imagen guardada:
(
set -e
MARCA="$(date +%Y%m%d-%H%M%S)"
RESPALDO="azure-environment-backup-$MARCA"
IMAGEN="topaz-local-backup:$MARCA"
docker stop azure-environment
docker commit azure-environment "$IMAGEN"
docker rename azure-environment "$RESPALDO"
printf '\nContenedor original: %s\nImagen de respaldo: %s\n\n' "$RESPALDO" "$IMAGEN"
docker run -d \
--name azure-environment \
-p 8899:8899 \
"$IMAGEN" \
--log-level Information \
--default-subscription 00000000-0000-0000-0000-000000000001
)
Nota: El bloque se ejecuta dentro de un subshell
( ... )conset -e, de modo que si cualquier paso falla, el proceso se detiene y no se pierde el contenedor original. Los contenedores de respaldo quedan detenidos y pueden eliminarse condocker rm <nombre>cuando ya no se necesiten.
3. Revisar los Logs¶
Comprueba que el nuevo contenedor arrancó correctamente. El emulador tarda unos segundos en estar listo; espera a ver las líneas Now listening on:
4. Exportar el Certificado del Emulador¶
El emulador sirve todo por HTTPS con un certificado autofirmado que se genera al crear el contenedor. Para que curl, az y Terraform confíen en él, hay que exportarlo al host. La forma más fiable es capturarlo directamente de la conexión TLS, lo que garantiza que corresponde al contenedor actual:
mkdir -p "$PWD/topaz-certs"
openssl s_client -connect 127.0.0.1:8899 -servername topaz.local.dev -showcerts </dev/null 2>/dev/null \
| openssl x509 -outform PEM > "$PWD/topaz-certs/topaz.crt"
openssl x509 -in "$PWD/topaz-certs/topaz.crt" -noout -subject -dates
La última línea debe mostrar el subject con topaz.local.dev y unas fechas de validez que incluyan hoy. A continuación, instala el certificado en el almacén del sistema para que lo reconozcan también las herramientas que no leen --cacert:
sudo cp "$PWD/topaz-certs/topaz.crt" /usr/local/share/ca-certificates/topaz.crt
sudo update-ca-certificates
# Debe indicar "1 added"
Nota: Cada vez que se recree el contenedor (paso 2 o un
docker runnuevo) el certificado cambia. Repite este paso después de cualquier recreación; de lo contrario aparecerán erroresSSL certificate problemencurlyaz.
5. Verificar el Endpoint de Metadatos¶
Consulta el endpoint de descubrimiento de Azure Resource Manager usando el certificado exportado:
curl --noproxy '*' \
--cacert "$PWD/topaz-certs/topaz.crt" \
--connect-timeout 5 --max-time 15 \
-i \
'https://topaz.local.dev:8899/metadata/endpoints?api-version=2022-09-01'
Una respuesta HTTP/1.1 200 OK seguida de un JSON con los endpoints confirma que el emulador está operativo y el certificado es válido.
6. Despliegue total de los certificados¶
El bloque es idempotente: puedes ejecutarlo entero aunque parte ya esté hecha.
# --- A. Exportar e instalar el certificado del contenedor ACTUAL ---
mkdir -p ~/topaz-certs
openssl s_client -connect 127.0.0.1:8899 -servername topaz.local.dev -showcerts </dev/null 2>/dev/null \
| openssl x509 -outform PEM > ~/topaz-certs/topaz.crt
openssl x509 -in ~/topaz-certs/topaz.crt -noout -subject -dates # debe mostrar topaz.local.dev
cp ~/topaz-certs/topaz.crt /usr/local/share/ca-certificates/topaz.crt
update-ca-certificates # "1 added" (o "0 added" si ya estaba: también vale)
# --- B. Variables para Python (az) y Go (terraform): shell actual + .bashrc de root ---
export REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt
export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
grep -q REQUESTS_CA_BUNDLE /root/.bashrc || cat >> /root/.bashrc <<'EOF'
export REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt
export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
EOF
# --- C. Comprobar que la cadena valida ANTES de volver a la CLI ---
openssl verify -CAfile /etc/ssl/certs/ca-certificates.crt ~/topaz-certs/topaz.crt
# Esperado: /root/topaz-certs/topaz.crt: OK
Repite ahora el registro de la nube. Recarga META primero: la variable se pierde si has abierto otra terminal.
META="$(curl -s --noproxy '*' 'https://topaz.local.dev:8899/metadata/endpoints?api-version=2022-09-01')"
echo "$META" | jq -r '.authentication.loginEndpoint' # URL bajo topaz.local.dev, nunca vacío
az cloud register --name Topaz \
--endpoint-resource-manager "https://topaz.local.dev:8899" \
--endpoint-active-directory "$(echo "$META" | jq -r '.authentication.loginEndpoint')" \
--endpoint-active-directory-resource-id "$(echo "$META" | jq -r '.authentication.audiences[0]')" \
--endpoint-active-directory-graph-resource-id "$(echo "$META" | jq -r '.authentication.audiences[0]')" \
--suffix-storage-endpoint "$(echo "$META" | jq -r '.suffixes.storage')" \
--suffix-keyvault-dns "$(echo "$META" | jq -r '.suffixes.keyVaultDns')"
az cloud set --name Topaz
az config set core.instance_discovery=false
Si aún existe algun error en este punto¶
| Síntoma | Significado | Acción |
|---|---|---|
curl da 200 pero az sigue fallando |
La variable no llega al proceso de az |
env \| grep CA_BUNDLE. No uses sudo az ... (limpia el entorno): trabaja como root o usa sudo -E |
openssl verify: unable to get local issuer certificate |
El certificado instalado es de un contenedor anterior | Repetir el bloque A entero |
update-ca-certificates no añade nada |
El archivo no termina en .crt o no está en /usr/local/share/ca-certificates/ |
Revisar ruta y nombre exactos |
| Necesitas avanzar sin más demora (solo laboratorio) | Desactivar la verificación TLS en la CLI | export AZURE_CLI_DISABLE_CONNECTION_VERIFICATION=1. Solo contra el emulador; Terraform no lo respeta, así que el bloque A sigue siendo necesario |
💡 La lección de fondo. Cada herramienta trae su propia idea de "certificados de confianza":
curlmira/etc/ssl/certs, Python miraREQUESTS_CA_BUNDLE, Go miraSSL_CERT_FILE. Instalar el certificado en el sistema es necesario pero no suficiente: hay que decirle a cada cliente dónde está. Este mismo principio explica el errorx509: certificate signed by unknown authorityque verás en Terraform si olvidasSSL_CERT_FILE.
7. Iniciar Sesión y Seleccionar la Suscripción¶
Con la nube Topaz activa, limpia sesiones previas, inicia sesión con código de dispositivo, selecciona la suscripción del emulador y verifica el contexto:
az account clear
az login --use-device-code
az account set --subscription 00000000-0000-0000-0000-000000000001
az account show \
--query '{nombre:name,id:id,tenant:tenantId,cloud:environmentName}' \
--output json
El mensaje de az login debe indicar la página del emulador, no la de Microsoft:
To sign in, use a web browser to open the page https://topaz.local.dev:8899/device and enter the code XXXXXXXXX to authenticate.
Abre esa URL, introduce el código y autentícate con topazadmin@topaz.local.dev / admin. La salida correcta de az account show es similar a esta (anota el tenant: lo necesitarás en Terraform):
{
"cloud": "Topaz",
"id": "00000000-0000-0000-0000-000000000001",
"nombre": "Topaz - Default",
"tenant": "50717675-3E5E-4A1E-8CB5-C62D8BE8CA48"
}
🛠️ Solución de problemas: az login redirige a login.microsoft.com¶
To sign in, use a web browser to open the page https://login.microsoft.com/device and enter the code LV6E3G5BB to authenticate.
La CLI sigue apuntando a la nube pública. Cancela con Ctrl+C y comprueba:
az cloud list --query '[].{nube:name, activa:isActive}' -o table
# Debe aparecer Topaz con isActive = True
- Topaz no aparece: el registro falló (normalmente por
Unable to get endpoints). Ejecuta 6a y repite 6b. - Topaz aparece pero
isActiveesFalse: ejecutaaz cloud set --name Topaz. - Topaz activa pero con endpoints incorrectos: revisa
az cloud show --name Topaz -o json; para corregirlos,az cloud set --name AzureCloud && az cloud unregister --name Topazy repite 6b. - Traceback
invalid_instance ... is not known: ejecuta 6c y repiteaz login.
Nota: Si
az loginya muestra la URL del emulador pero falla conCERTIFICATE_VERIFY_FAILED, la nube está bien registrada y el problema es la confianza TLS: compruebaecho $REQUESTS_CA_BUNDLEy que el certificado del paso 4 corresponde al contenedor en marcha. Si el login completa sin suscripciones, usa--allow-no-subscriptionsy fija la suscripción conaz account set.
🛠️ Caso resuelto: la nube Topaz no está registrada o activa en este host¶
export ARM_METADATA_HOSTNAME=topaz.local.dev:8899
export ARM_TENANT_ID=50717675-3E5E-4A1E-8CB5-C62D8BE8CA48
export ARM_SUBSCRIPTION_ID=00000000-0000-0000-0000-000000000001
az login --use-device-code
To sign in, use a web browser to open the page https://login.microsoft.com/device and enter the code L65MYKUFP to authenticate.
Qué está pasando. Las variables ARM_* las lee solo Terraform; Azure CLI las ignora y decide a qué nube hablar únicamente por az cloud set. Si az login sigue enviando a login.microsoft.com, es que en este host la nube Topaz no está registrada (lo habitual: el az cloud register anterior falló con CERTIFICATE_VERIFY_FAILED y nunca llegó a crearse) o está registrada pero no activa.
Primero, averigua en cuál de los dos casos estás:
az cloud list --query '[].{nube:name, activa:isActive}' -o table
# Topaz no aparece → registro pendiente: ejecuta el bloque completo
# Topaz aparece con False → solo falta activarla: salta al paso 3
El bloque siguiente es idempotente: puedes ejecutarlo entero sin miedo aunque parte ya esté hecha.
# --- 1. Confianza TLS para Python (sin esto, el registro vuelve a fallar) ---
export REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt
export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
openssl verify -CAfile /etc/ssl/certs/ca-certificates.crt ~/topaz-certs/topaz.crt
# Esperado: .../topaz-certs/topaz.crt: OK (si no, repite el paso 4: exportar e instalar el certificado)
# --- 2. Registrar Topaz (solo si no aparecía en az cloud list) ---
META="$(curl -s --noproxy '*' 'https://topaz.local.dev:8899/metadata/endpoints?api-version=2022-09-01')"
echo "$META" | jq -r '.authentication.loginEndpoint' # debe ser una URL bajo topaz.local.dev, nunca vacío
az cloud register --name Topaz \
--endpoint-resource-manager "https://topaz.local.dev:8899" \
--endpoint-active-directory "$(echo "$META" | jq -r '.authentication.loginEndpoint')" \
--endpoint-active-directory-resource-id "$(echo "$META" | jq -r '.authentication.audiences[0]')" \
--endpoint-active-directory-graph-resource-id "$(echo "$META" | jq -r '.authentication.audiences[0]')" \
--suffix-storage-endpoint "$(echo "$META" | jq -r '.suffixes.storage')" \
--suffix-keyvault-dns "$(echo "$META" | jq -r '.suffixes.keyVaultDns')"
# --- 3. Activar la nube, desactivar instance discovery y entrar ---
az cloud set --name Topaz
az config set core.instance_discovery=false
az account clear
az login --use-device-code
La salida correcta apunta al emulador, con la ruta /devicelogin y un código con formato XXXX-XXXX:
To sign in, use a web browser to open the page https://topaz.local.dev:8899/devicelogin and enter the code EGWR-6P33 to authenticate
Abre esa URL, introduce el código y autentícate con topazadmin@topaz.local.dev / admin. Después, fija la suscripción y confirma el contexto:
az account set --subscription 00000000-0000-0000-0000-000000000001
az account show --query '{nombre:name,id:id,tenant:tenantId,cloud:environmentName}' -o json
# Esperado: "cloud": "Topaz"
Si
az cloud registerdice queTopazya existe (un intento fallido dejó la entrada a medias), elimínala y repite el paso 2:💡 Las variables
ARM_*no estorban. Déjalas exportadas: Terraform las leerá más adelante para el provider y el backend. Simplemente no sirven para redirigir a Azure CLI. Cada herramienta tiene su propio "mando":az cloud setpara la CLI,metadata_host/ARM_METADATA_HOSTNAMEpara Terraform.
Resolución de problemas: Acceso a Topaz Azure Emulator en Firefox¶
Descripción del problema¶
Al intentar acceder a la interfaz de autenticación del emulador Topaz mediante la URL por defecto:
https://topaz.local.dev:8899/devicelogin
Firefox bloquea la conexión o no permite cargar la página debido a restricciones de seguridad en los certificados SSL autofirmados y las políticas HSTS aplicadas a los dominios .dev.
Causa raíz¶
- Certificados autofirmados: Firefox utiliza su propio almacén de certificados aislado y no confía automáticamente en la entidad emisora (CA) local generada por Topaz.
- Restricciones de dominio .dev: Los dominios con la extensión .dev fuerzan conexiones HTTPS mediante HSTS (HTTP Strict Transport Security), lo que impide a Firefox añadir excepciones manuales de seguridad para esos nombres de dominio.
Solución¶
Sustituir el nombre de host topaz.local.dev por la dirección IP de bucle invertido (loopback) 127.0.0.1.
Cambio de URL:¶
❌ URL original (bloqueada):
https://topaz.local.dev:8899/devicelogin
✅ URL corregida:
https://127.0.0.1:8899/devicelogin
Pasos para acceder¶
- Abre Firefox e introduce en la barra de direcciones:
https://127.0.0.1:8899/devicelogin - Si Firefox muestra la pantalla "Advertencia: Riesgo potencial de seguridad a continuación":
- Haz clic en Avanzado...
- Haz clic en Aceptar el riesgo y continuar.
- La página de inicio de sesión del emulador se cargará correctamente.
- Debes poner el device code que te genera el az login y de usuario
topazadmin@topaz.local.dev
▶️ Desplegar la Infraestructura de prueba con Terraform para probar el entorno¶
Con el contenedor en ejecución, el endpoint de metadatos respondiendo 200 OK y la CLI autenticada en la nube Topaz, ya puedes trabajar con Terraform. Pero hay un matiz importante: Terraform no hereda la configuración de az cloud set. El provider azurerm y el backend azurerm apuntan por defecto a la nube pública (management.azure.com), así que hay que indicarles explícitamente dónde está el emulador.
🛠️ Ejemplos Prácticos¶
1. Provisionar un Grupo de Recursos¶
Definición de infraestructura en main.tf:
terraform {
required_providers {
azurerm = { source = "hashicorp/azurerm", version = "~> 4.0" }
}
}
provider "azurerm" {
features {}
metadata_host = "topaz.local.dev:8899"
resource_provider_registrations = "none"
subscription_id = "00000000-0000-0000-0000-000000000001"
}
resource "azurerm_resource_group" "rg" {
name = "rg-humo"
location = "eastus"
}
output "rg_id" {
value = azurerm_resource_group.rg.id
}
Nota: Esto solo define la infraestructura. Los comandos de despliegue (
terraform init,planyapply) se ejecutan más adelante, en la sección Desplegar la Infraestructura con Terraform, una vez que el entorno esté montado, verificado y la CLI de Azure autenticada.
2. Desplegar¶
🛠️ Solución de problemas: SubscriptionNotFound en terraform init¶
Error: retrieving Storage Account (Subscription: "00000000-0000-0000-0000-000000000001"
Resource Group Name: "defaultRG"
Storage Account Name: "localstorage"): unexpected status 404 (404 Not Found) with error:
SubscriptionNotFound: The subscription '00000000-0000-0000-0000-000000000001' could not be found.
Aunque az account show muestre "cloud": "Topaz", este error indica que Terraform está hablando con la nube pública de Azure, donde esa suscripción no existe. La causa casi siempre es que falta metadata_host en el backend y/o en el provider (paso 1). Confírmalo viendo a qué host se conecta Terraform:
TF_LOG=DEBUG terraform init 2>&1 | grep -oE 'https://[a-zA-Z0-9.:-]+' | sort -u
# Incorrecto: https://management.azure.com → falta metadata_host
# Correcto: https://topaz.local.dev:8899 (y los endpoints que devuelve)
Si Terraform sí apunta a topaz.local.dev:8899 y el error persiste, el emulador realmente no conoce esa suscripción (por ejemplo, si el contenedor se arrancó sin --default-subscription). Comprueba qué suscripciones expone y usa ese ID en main.tf y en az account set:
az account list --query '[].{nombre:name, id:id}' -o table
az rest --method get \
--url "https://topaz.local.dev:8899/subscriptions/00000000-0000-0000-0000-000000000001?api-version=2022-12-01"
Orden de comprobación recomendado cuando algo falla en Terraform:
| Error de Terraform | Causa probable | Corrección |
|---|---|---|
SubscriptionNotFound |
Terraform apunta a Azure real | metadata_host en backend y provider (paso 1) |
x509: certificate signed by unknown authority |
Go no encuentra topaz.crt |
Paso 4 del contenedor; SSL_CERT_FILE |
StorageAccountNotFound / ResourceGroupNotFound |
Backend remoto sin storage previo | Crear con az (paso 2) o backend local (paso 3) |
dial tcp ... :8891: connection refused |
Puerto de Storage no publicado / sin entrada en hosts | -p 8891:8891 y /etc/hosts, o backend local |
| Error al registrar resource providers | El emulador no implementa ese registro | resource_provider_registrations = "none" |
plan se queda colgado en Refreshing state... |
Estado con recursos de otra práctica cuyo plano de datos no es alcanzable (típico: un storage account) | terraform state rm de los sobrantes, o borrar terraform.tfstate* y empezar de cero |
🛠️ Solución de problemas: terraform plan se queda colgado en Refreshing state...¶
Si el plan imprime varias líneas Refreshing state... y no avanza, el provider está reintentando una conexión que nunca responde. El caso habitual es un azurerm_storage_account heredado de un apply anterior: al refrescarlo, el provider consulta el plano de datos (https://<cuenta>.storage.topaz.local.dev:8891), un nombre que no está en /etc/hosts y un puerto que el contenedor no publica. Pulsa Ctrl+C e identifica el recurso refrescando de uno en uno:
terraform state list # ¿hay recursos que ya no están en main.tf?
terraform plan -parallelism=1 # el último "Refreshing" impreso es el culpable
Si el recurso ya no forma parte de main.tf, sácalo del estado y bórralo con la CLI, que sí habla correctamente con el emulador:
terraform state rm azurerm_storage_account.ejemplo
az storage account delete -g rg-declarativo-topaz -n stdeclarativo01 --yes
terraform plan
Para empezar de cero (el estado de una práctica no tiene valor) o para desatascar un plan puntual sin consultar el emulador:
# Borrón y cuenta nueva
az group delete -n rg-declarativo-topaz --yes --no-wait
rm -f terraform.tfstate terraform.tfstate.backup
terraform init -reconfigure
# Solo comparar código y estado, sin refrescar contra el emulador
terraform plan -refresh=false
Nota: Si el
curldel paso 5 oaz account showno funcionan, Terraform tampoco lo hará: resuelve primero los pasos 4 a 7 de Operaciones sobre el Contenedor antes de tocar la configuración de Terraform.
🛠️ Caso resuelto: terraform apply falla con x509: certificate signed by unknown authority¶
Error: retrieving metadata from endpoint "https://topaz.local.dev:8899": performing request:
Get "https://topaz.local.dev:8899/metadata/endpoints?api-version=2022-09-01":
tls: failed to verify certificate: x509: certificate signed by unknown authority
with provider["registry.terraform.io/hashicorp/azurerm"],
on main.tf line 12, in provider "azurerm":
Qué está pasando. El main.tf es correcto: Terraform ya apunta al emulador gracias a metadata_host. Lo que falla es la confianza TLS en Go: recibe el certificado autofirmado del contenedor y no lo encuentra en el almacén. Tres causas, por orden de probabilidad:
- El certificado instalado es de otro contenedor. Si
azure-environmentse recreó después deupdate-ca-certificates, eltopaz.crtdel sistema ya no coincide con el que sirve el puerto 8899. azfunciona solo porque tieneAZURE_CLI_DISABLE_CONNECTION_VERIFICATION=1. Esa variable desactiva la comprobación en la CLI, pero Terraform la ignora. Es el caso típico de "la CLI va y Terraform no".SSL_CERT_FILEno está en esta shell (trabajas comorooty la variable se añadió al.bashrcdecurso).
Compara la huella del certificado que sirve el contenedor ahora con la del instalado:
openssl s_client -connect 127.0.0.1:8899 -servername topaz.local.dev </dev/null 2>/dev/null \
| openssl x509 -noout -fingerprint -sha256
openssl x509 -in /usr/local/share/ca-certificates/topaz.crt -noout -fingerprint -sha256
# Huellas distintas → certificado obsoleto
echo "SSL_CERT_FILE=$SSL_CERT_FILE DISABLE_VERIFICATION=$AZURE_CLI_DISABLE_CONNECTION_VERIFICATION"
El arreglo es idempotente y cubre las tres causas a la vez:
# --- A. Reinstalar el certificado del contenedor ACTUAL ---
mkdir -p ~/topaz-certs
openssl s_client -connect 127.0.0.1:8899 -servername topaz.local.dev -showcerts </dev/null 2>/dev/null \
| openssl x509 -outform PEM > ~/topaz-certs/topaz.crt
cp ~/topaz-certs/topaz.crt /usr/local/share/ca-certificates/topaz.crt
update-ca-certificates --fresh # --fresh purga el certificado antiguo del bundle
# --- B. Bundle para Go (Terraform) y Python (az): shell actual + .bashrc de root ---
export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
export REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt
unset AZURE_CLI_DISABLE_CONNECTION_VERIFICATION # enmascara problemas; ya no hace falta
grep -q SSL_CERT_FILE /root/.bashrc || cat >> /root/.bashrc <<'EOF'
export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
export REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt
EOF
# --- C. Verificar y reintentar ---
openssl verify -CAfile /etc/ssl/certs/ca-certificates.crt ~/topaz-certs/topaz.crt # Esperado: OK
curl -s --noproxy '*' -o /dev/null -w 'HTTP %{http_code}\n' \
'https://topaz.local.dev:8899/metadata/endpoints?api-version=2022-09-01' # Esperado: HTTP 200
terraform apply
Nota: si el contenedor se recreó, la sesión de
aztambién ha caducado. Como el provider usause_cli = true, ejecutaaz account clear && az login --use-device-codeantes delapply, o el siguiente error será de autenticación en lugar de TLS.💡 Regla práctica. Cada vez que hagas
docker runo recreesazure-environment, repite en este orden: certificado (paso 4) →az login(paso 7) →terraform apply. Saltarse el primero produce exactamente este error; saltarse el segundo, un401del emulador.
⚠️ Notas Importantes¶
Este es un entorno de práctica local. No está diseñado para producción.
Los comandos y configuraciones son ejemplos simplificados para aprendizaje.
Las credenciales
topazadmin@topaz.local.dev/admin, la contraseña de la VM en claro, la desactivación de la validación TLS y la de instance discovery solo deben usarse contra el emulador local, nunca contra Azure real.