Módulo 2: The Bedrock Cost Model
5. Manos a la obra: el intento honesto de `infracost scan` sobre `bedrock.tf`
Descripción
ADR-001-llm-as-escalation-path.md cerró el Módulo 1 con una frase exacta: "ni bedrock.tf existe, ni extract-shipment-manifest-fields tiene una sola línea de código". Esta lección escribe la primera línea de bedrock.tf que existe en toda esta guía — deliberadamente mínima, un solo recurso, escrita únicamente para poder hacerle a Infracost la pregunta que este módulo entero existe para contestar: ¿puede Infracost ponerle precio a un recurso de Bedrock? El intento corrió de verdad, en este mismo entorno, mientras se escribía esta lección — y se detiene en un punto que vale la pena documentar con precisión, no menos honesto que el de cloud-security-and-guardrails-guide M2.6 ni el del Módulo 1, lección 7 de esta misma guía.
Conexión con el módulo
La lección 4 confirmó que Infracost sigue disponible, sin reinstalación. Esta lección lo apunta, por primera vez, a un recurso aws_bedrock_guardrail real. La lección 6, inmediatamente después, explica por qué el resultado de esta lección es el que es — no una falla de esta guía, sino una consecuencia estructural de cómo funciona Infracost, aplicada a un tipo de recurso que nunca tuvo que enfrentar antes.
Paso 1 — El primer bedrock.tf de esta guía, deliberadamente mínimo
Esto no es la infraestructura completa de la carga de IA de Andes Cargo — esa es el trabajo íntegro del Módulo 3, con el módulo modules/bedrock-guardrail/, las seis políticas de guardrail del Módulo 4, y el rol IAM de mínimo privilegio. Es, a propósito, la versión más pequeña posible de un recurso Bedrock real: un solo aws_bedrock_guardrail, suficiente para que Infracost tenga algo concreto que intentar leer, y nada más.
En la raíz de andes-cargo-infra/, agrega bedrock.tf:
# bedrock.tf -- Module 2 draft. A single aws_bedrock_guardrail resource, written
# only to run `infracost scan` against a real Bedrock resource (Module 2, lesson 5).
# This is NOT the complete infrastructure -- Module 3 builds modules/bedrock-guardrail/
# and BedrockManifestExtractorRole in full. ADR-001 (Module 1) confirmed that, at the
# close of Module 1, no bedrock.tf existed yet; this is its first draft line.
resource "aws_bedrock_guardrail" "manifest_extractor" {
name = "andes-cargo-manifest-extractor-guardrail"
blocked_input_messaging = "This input is not allowed due to content policy violations."
blocked_outputs_messaging = "This output is not allowed due to content policy violations."
content_policy_config {
filters_config {
type = "PROMPT_ATTACK"
input_strength = "HIGH"
output_strength = "NONE"
}
}
tags = local.common_tags
}
Nota el comentario del encabezado: es la misma disciplina de trazabilidad que iam.tf, s3.tf y dynamodb.tf de andes-cargo-infra/ ya establecieron — cada archivo .tf declara, en su primera línea, de dónde viene y qué todavía no es.
Paso 2 — terraform init / validate / plan: la parte que sí corre completa
Exactamente como confirmó el Módulo 1 de esta guía (y, antes, el diseño completo de esta guía, verificado por ejecución directa): declarar y planear un recurso Bedrock nuevo no necesita LocalStack corriendo, ni cuenta AWS, ni ningún token — porque Terraform nunca necesita leer del state un recurso que todavía no existe ahí.
terraform init -input=false
terraform validate
terraform plan -out=tfplan -input=false
Qué esperar (literal — corrido de verdad en este entorno, Terraform v1.15.8, provider hashicorp/aws v6.60.0):
Initializing the backend...
Initializing modules...
Initializing provider plugins...
- Reusing previous version of hashicorp/archive from the dependency lock file
- Reusing previous version of hashicorp/aws from the dependency lock file
- Using previously-installed hashicorp/aws v6.60.0
- Using previously-installed hashicorp/archive v2.8.0
Terraform has been successfully initialized!
Success! The configuration is valid.
# aws_bedrock_guardrail.manifest_extractor will be created
+ resource "aws_bedrock_guardrail" "manifest_extractor" {
+ blocked_input_messaging = "This input is not allowed due to content policy violations."
+ blocked_outputs_messaging = "This output is not allowed due to content policy violations."
+ created_at = (known after apply)
+ description = (known after apply)
+ guardrail_arn = (known after apply)
+ guardrail_id = (known after apply)
+ name = "andes-cargo-manifest-extractor-guardrail"
+ region = "us-east-1"
+ status = (known after apply)
+ tags = {
+ "Environment" = "dev"
+ "ManagedBy" = "terraform"
+ "Project" = "andes-cargo"
}
...
}
Plan: 15 to add, 0 to change, 0 to destroy.
Saved the plan to: tfplan
Nota el número de la versión del provider: v6.60.0, no v5.100.0. La versión exacta instalada en un entorno depende de cuándo se corrió terraform init contra la restricción ~> 6.0 ya fijada en versions.tf de andes-cargo-infra/ desde terraform-and-iac-guide — el número exacto cambia con el tiempo, lo que importa, y se confirma aquí de nuevo, es que aws_bedrock_guardrail existe en el esquema del provider y se planea sin errores, sin importar el patch exacto instalado.
Paso 3 — infracost scan, el intento real
Con tfplan generado, el siguiente paso —el que este módulo entero existe para poner a prueba— es apuntar Infracost al proyecto completo:
infracost scan andes-cargo-infra/
Recuerda, de la lección 4: [path] es un argumento posicional, no una bandera. Este comando corrió de verdad, en este entorno, mientras se escribía esta lección.
Qué esperar (literal — corrido contra el binario real v2.16.1, sin sesión iniciada, en este entorno):
Port 26372 is already in use, falling back to device authentication.
Please go to the following URL to log in:
https://login.infracost.io/activate
And enter the code:
QSRS-QGBJ
El comando nunca llegó a leer bedrock.tf. Antes de analizar un solo recurso, scan intenta confirmar una sesión iniciada — el mismo hallazgo, exacto, que finops-and-cost-guardrails-guide M2.2 ya documentó ("Please go to the following URL to log in", seguido de una URL de PKCE) —, pero con una variación real de este entorno específico que vale la pena señalar con precisión: el puerto 26372, el mismo que el flujo PKCE de esa guía hermana usaba para el servidor local que recibe el callback del navegador, ya estaba en uso en este entorno al momento de correr el comando. Infracost detectó esa colisión y, en vez de fallar, cayó automáticamente al segundo mecanismo que la lección 4 ya había anticipado como posible: device flow — un código de un solo uso (QSRS-QGBJ en esta corrida específica; el tuyo será distinto) que se ingresa manualmente en login.infracost.io/activate desde cualquier navegador, en cualquier dispositivo, sin necesitar que ese navegador esté en la misma máquina que corrió el comando.
La respuesta honesta a la pregunta de esta lección
El diseño de esta guía planteó tres resultados posibles, igualmente honestos, para este intento: que el recurso de Bedrock apareciera con precio, que apareciera listado como omitido (una salida del estilo "no soportado" o "sin precio"), o ninguno de los dos. La respuesta real, confirmada por esta corrida, es la tercera — pero con una precisión que vale la pena decir completa: no es que Infracost haya evaluado aws_bedrock_guardrail y decidido no poder ponerle precio. Es que nunca llegó a evaluar ningún recurso del plan en absoluto. El gate de autenticación se ejecuta antes que cualquier análisis del HCL o del tfplan.json — exactamente como ya advirtió finops-and-cost-guardrails-guide M2.2: "el primer paso de scan es confirmar la sesión, y si no la encuentra, [...] espera ahí, indefinidamente".
EL INTENTO CONTRA BEDROCK.TF, PASO A PASO
terraform init / validate / plan
│
▼
Success! -- sin necesitar LocalStack, cuenta AWS ni token
(confirmado en el Paso 2 de esta lección)
│
▼
infracost scan andes-cargo-infra/
│
▼
¿Sesión de Infracost iniciada?
│
NO ─────┴───── (nunca se llegó a probar el SÍ en este entorno)
│
▼
Puerto 26372 ocupado -> cae a device flow
"Please go to the following URL to log in..."
-- espera ahí, indefinidamente --
│
▼
bedrock.tf NUNCA se leyó. Ni con precio, ni --include-warnings,
ni "not supported" -- el gate de autenticación bloquea ANTES
de que exista una respuesta a esa pregunta.
Una corrección honesta sobre una bandera que no existe. Antes de escribir esta lección se consideró correr infracost scan andes-cargo-infra/ --show-skipped, para ver si esa bandera revelaría recursos no soportados sin necesitar sesión. Esa bandera no existe en el --help real de scan de esta versión —confirmado en la lección 4: las únicas banderas de scan son --currency, --include-warnings, -o/--option y --ssh-key-file—. --show-skipped pertenece a documentación o tutoriales de una versión anterior del CLI, probablemente del comando ya deprecado breakdown. La bandera vigente más cercana a esa función es --include-warnings ("Also show warning-severity diagnostics in the summary") — pero, como el gate de autenticación bloquea antes de cualquier análisis, ni siquiera esa bandera pudo probarse en este entorno.
Errores comunes
Concluir, de esta lección, que Infracost "no soporta Bedrock" (de sobre-generalización sin evidencia). Qué pasa: alguien lee que bedrock.tf nunca se analizó y concluye que Infracost carece de soporte para recursos de Bedrock. Cómo detectarlo: si tu resumen de esta lección es "Infracost no tiene precios de Bedrock". Cómo corregirlo: esta lección no puede probar esa afirmación — el gate de autenticación impidió que el análisis siquiera comenzara. La lección 6 investiga esa pregunta específica por una vía distinta (la documentación pública de recursos soportados de Infracost), separada de este intento de ejecución.
Pensar que el segundo intento, con sesión iniciada, necesariamente resolvería la pregunta de precio de Bedrock (de expectativa hacia adelante). Qué pasa: alguien asume que, si tuviera una cuenta de Infracost autenticada, scan mostraría automáticamente un precio completo para aws_bedrock_guardrail. Cómo detectarlo: si tu plan es "solo necesito loguearme y el número va a aparecer". Cómo corregirlo: incluso con sesión iniciada, un recurso puede aparecer sin precio por dos razones completamente distintas — que Infracost no tenga ese tipo de recurso en su catálogo (la pregunta de la lección 6), o que sí lo tenga pero sea usage-based sin un supuesto de volumen declarado (el mismo hueco que finops-and-cost-guardrails-guide M2.5 ya encontró con DynamoDB y Lambda). Autenticarse resuelve el primer obstáculo de esta lección, no garantiza una respuesta con precio.
Copiar el código de un solo uso (QSRS-QGBJ) de esta lección esperando que funcione (de lectura literal de un valor efímero). Qué pasa: alguien, siguiendo esta lección al pie de la letra, intenta ingresar el código exacto mostrado arriba en login.infracost.io/activate. Cómo detectarlo: si copiaste el código de este documento en vez de generar el tuyo. Cómo corregirlo: ese código es de un solo uso, generado para esta corrida específica, y ya expiró. Cada corrida de infracost scan sin sesión genera su propia URL y su propio código — la parte que se repite, siempre, es el mecanismo (device flow, con el puerto de PKCE en uso), no el valor exacto.
Ejercicios
Ejercicio 1 — Explica por qué terraform plan de esta lección terminó completo, pero infracost scan no. Un colega, viendo ambos comandos correr contra el mismo bedrock.tf, pregunta por qué uno completó su trabajo y el otro se quedó esperando un login. Explícale la diferencia.
Ver solución
terraform plan sobre un recurso que no existe todavía en el state nunca necesita leer ninguna API externa — construye el diff completo a partir del HCL declarado localmente, exactamente como confirmó el Módulo 1 de esta guía. infracost scan, en cambio, necesita dos cosas antes de poder mostrar un número: confirmar una sesión contra la plataforma de Infracost (un servicio externo, con su propio sistema de cuentas) y, solo después, consultar su catálogo de precios. El primer paso —la sesión— es una barrera completamente independiente del HCL que se está analizando; bloquea antes de que el segundo paso, el que sí involucra el contenido de bedrock.tf, pueda siquiera comenzar.
Ejercicio 2 — Predice qué pasaría si corrieras este mismo comando en tu propia máquina, con un puerto 26372 disponible (no ocupado). Basándote en lo que finops-and-cost-guardrails-guide M2.2 ya documentó sobre el flujo PKCE, ¿qué verías en vez del mensaje de device flow de esta lección?
Ver solución
Verías una URL larga de autorización PKCE —del estilo https://login.infracost.io/authorize?audience=...&client_id=...&code_challenge=...&redirect_uri=http%3A%2F%2Flocalhost%3A26372%2Fcallback...—, en vez del mensaje corto de device flow con un código de activación. El comando abriría (o esperaría que abrieras manualmente) esa URL en un navegador, y el propio proceso de infracost scan levantaría un servidor local temporal en el puerto 26372 para recibir la respuesta del navegador cuando completes el login — el mismo mecanismo que la lección 4 de esta guía anticipó como el "camino normal", reservando device flow para cuando ese puerto específico no está disponible.
Ejercicio 3 — Explica por qué esta lección corrige explícitamente la bandera --show-skipped en vez de simplemente omitirla. ¿Por qué vale la pena, para esta guía, señalar una bandera que no existe, en vez de solo hablar de las que sí existen?
Ver solución
Porque el diseño original de esta guía consideró esa bandera como una posible vía para revelar recursos no soportados, y verificar contra el --help real (lección 4) reveló que no existe en la versión vigente del CLI — es exactamente el mismo tipo de corrección que finops-and-cost-guardrails-guide M2.2 ya hizo con breakdown --path y infracost diff. Callar ese hallazgo habría dejado pasar, sin corregir, una suposición que un tutorial desactualizado —o esta misma guía, si no se hubiera verificado— podría haber propagado como si fuera cierta. Nombrar la corrección, con la fuente exacta (el --help real, corrido en la lección 4), es la misma disciplina de honestidad que sostiene toda esta guía: verificar antes de citar, y corregir en voz alta cuando una suposición razonable resulta ser incorrecta.
Resumen y siguiente paso
Esta lección escribió el primer bedrock.tf real de esta guía —mínimo, un solo recurso, deliberadamente incompleto— y confirmó, con terraform init/validate/plan corridos de verdad, que se declara y planea sin ningún error, sin LocalStack, sin cuenta AWS, sin token. Después apuntó infracost scan a ese mismo proyecto, y documentó el resultado real: el comando nunca llegó a leer bedrock.tf — el gate de autenticación de Infracost lo detuvo antes, cayendo a device flow por una colisión de puerto específica de este entorno. La pregunta de si Infracost puede ponerle precio a un recurso de Bedrock queda, por esta vía, sin respuesta observable en este laboratorio — no como una falla, sino como el resultado honesto de un intento real.
Antes de avanzar deberías poder: explicar por qué terraform plan completó y infracost scan no, sobre el mismo archivo; describir, de memoria, el mecanismo de device flow frente a PKCE; y explicar por qué el gate de autenticación hace que esta lección no pueda, por sí sola, confirmar si Infracost soporta o no recursos de Bedrock.
La lección 6 contesta esa pregunta pendiente por una vía distinta —no ejecutando scan de nuevo, sino leyendo directamente la documentación pública de qué recursos soporta Infracost— y explica, con esa evidencia, por qué incluso una respuesta afirmativa a esa pregunta no resolvería el problema completo de costear extract-shipment-manifest-fields.
Recursos
- Infracost — CLI commands — la referencia oficial de
scan, confirmada de nuevo contra el comportamiento real de esta lección. finops-and-cost-guardrails-guide, Módulo 2, lección 2 — la fuente original del hallazgo de autenticación PKCE, aquí confirmado con una variante real (device flow) no documentada en esa guía hermana.- Infracost — Authentication — documentación oficial de ambos mecanismos de autenticación, PKCE y device flow.
- Módulo 1, lección 8 de esta guía (
ADR-001-llm-as-escalation-path.md) — la fuente de la afirmación "nibedrock.tfexiste" que esta lección resuelve por primera vez.