Módulo 3: Infrastructure As Code For An Ai Endpoint
6. El límite exacto: por qué `apply` no corre contra LocalStack Hobby
Descripción
Las cinco lecciones anteriores de este módulo corrieron, todas, de verdad: fmt, validate, plan, sin excepción. Esta lección documenta, con la misma honestidad y una cita oficial verificada en el momento de escribirla —no memorizada de una versión anterior de esta guía—, el punto exacto donde ese patrón se detiene: terraform apply (o su envoltorio tflocal apply) sobre module.manifest_extractor_guardrail. La lección 7, inmediatamente después, traza la frontera fina dentro del mismo bedrock.tf — porque, como ya viste en la lección 4, no todo en este archivo comparte el mismo límite.
Conexión con el módulo
Esta lección retoma, para apply, exactamente el mismo patrón que el Módulo 1, lección 7 ya estableció para awslocal bedrock list-foundation-models: un intento honesto, documentado con la fuente oficial citada en el momento exacto en que el límite aparece — nunca al final de la lección, nunca escondido en una nota al pie.
Paso 1 — Lo que un apply real necesitaría, y por qué el Módulo 1 ya lo confirmó
terraform apply sobre un recurso Bedrock, a diferencia de validate y plan (lección 1 de este módulo), sí necesita hablar con algo real: la API que va a crear el recurso de verdad. Contra LocalStack, ese "algo real" es el contenedor localstack/localstack, sirviendo en el puerto 4566. El Módulo 1, lección 7 de esta guía ya corrió este intento exacto, de verdad, en este mismo entorno de escritura:
docker run -d -p 4566:4566 --name localstack-bedrock-test localstack/localstack:latest
Qué esperar (literal — ya ejecutado y documentado en Módulo 1, lección 7 de esta guía, reproducido aquí porque es la base directa de esta lección):
LocalStack version: 2026.7.4
LocalStack build date: 2026-08-14
LocalStack build git hash: 875b30838
Localstack returning with exit code 55. Reason:
===============================================
License activation failed! 🔑❌
Reason: No credentials were found in the environment. Please make sure to either
set the LOCALSTACK_AUTH_TOKEN variable to a valid auth token. If you are using
the CLI, you can also run `localstack auth set-token`.
Due to this error, Localstack has quit. LocalStack pro features can only be
used with a valid license.
El contenedor arranca, imprime su versión, y se apaga solo con código de salida 55 —antes de exponer un solo endpoint, para cualquier servicio, no solo Bedrock—. Este entorno de escritura específico no tiene un LOCALSTACK_AUTH_TOKEN exportado. Con un token de Hobby real, gratis, registrado, este primer obstáculo se resuelve, y el contenedor arranca — exactamente como ya viste con IAM en la lección 4 de este módulo.
Paso 2 — El segundo obstáculo, el que ni un token de Hobby resuelve: la cita oficial, verificada de nuevo
Aquí es donde esta lección deja de repetir el Paso 1 y se vuelve genuinamente distinta. Con el primer obstáculo resuelto —un token de Hobby real, el contenedor arrancado—, el siguiente comando sería:
tflocal apply -target=module.manifest_extractor_guardrail -auto-approve
Esto no corrió en este entorno —ni podría, por el Paso 1—, pero la conclusión de qué pasaría con él está construida sobre una fuente verificada en este mismo momento de escritura, no asumida de una versión anterior de esta guía: la página de cobertura de Bedrock en la documentación oficial de LocalStack, consultada de nuevo hoy.
La cita exacta, verificada contra docs.localstack.cloud/aws/services/bedrock/: el badge de cobertura de la página declara, textualmente:
Included in Plans
Ultimate
Sin Hobby, sin Base — el mismo hallazgo, exacto, que el Módulo 1, lección 7 de esta guía ya citó, confirmado de nuevo aquí porque es la base directa de por qué apply se detiene en este punto específico, no en otro.
Qué esperar (representativo — reconstruido con precisión contra el comportamiento documentado de LocalStack para un servicio fuera del plan activo, el mismo patrón que el Módulo 1, lección 7 ya usó para list-foundation-models):
╷
│ Error: creating Bedrock Guardrail (andes-cargo-manifest-extractor-guardrail):
│ operation error Bedrock: CreateGuardrail, https response error StatusCode: 501,
│ RequestID: ..., InternalFailure: API for service 'bedrock' is not included in
│ your current license plan. Please contact LocalStack support or upgrade your
│ plan to access this API.
│
│ with module.manifest_extractor_guardrail.aws_bedrock_guardrail.this,
│ on modules/bedrock-guardrail/main.tf line 1, in resource "aws_bedrock_guardrail" "this":
│ 1: resource "aws_bedrock_guardrail" "this" {
│
╵
El error, si ocurriera de verdad, aparecería durante apply, nunca durante plan — exactamente la distinción que la lección 1 de este módulo estableció: plan nunca necesita tocar la API real para un recurso nuevo; apply sí, porque en algún punto tiene que hacer la llamada CreateGuardrail de verdad, y ahí es donde el límite del plan de licencia de LocalStack se vuelve visible.
Los dos pasos, en un solo diagrama, aplicados esta vez a apply
EL INTENTO CONTRA bedrock.tf CON apply, PASO A PASO
tflocal apply -target=module.manifest_extractor_guardrail
│
▼
docker run localstack/localstack:latest
│
▼
¿LOCALSTACK_AUTH_TOKEN exportado?
│
NO ─────┴───── SÍ
│ │
▼ ▼
Exit code 55 El contenedor arranca,
(este sandbox, expone :4566
confirmado en │
Módulo 1, L7) ▼
terraform apply llama
CreateGuardrail contra
el endpoint de Bedrock
│
▼
¿Plan Ultimate activo?
│
NO ─────┴───── SÍ
│ │
▼ ▼
"not included El guardrail se
in your current crea de verdad --
license plan" pero SIN invocar
(Hobby, incluso inferencia real,
con token ver nota final
registrado) del Módulo 1, L7
La rama izquierda de arriba —exit code 55— es exactamente lo que este sandbox de escritura confirmó, de verdad, en el Paso 1. La rama derecha, incluso resuelta hasta el final con un token de Hobby, se detiene en el mismo punto que el Módulo 1, lección 7 ya documentó para list-foundation-models: Bedrock necesita, específicamente, el plan de pago más alto de LocalStack, uno por encima de lo que cualquier cuenta gratuita ofrece.
Por qué este módulo, precisamente por esto, sigue siendo el más ejecutado de la guía
Vale la pena decir, sin rodeos, lo que esta lección no cambia: las cinco lecciones anteriores de este módulo —el panorama de recursos, el módulo bedrock-guardrail completo, el rol de mínimo privilegio, el plan de diecisiete recursos— corrieron, todas, de verdad, sin ninguna dependencia de lo que esta lección acaba de documentar. El límite de apply es real, está citado con su fuente exacta, y no retrocede nada de lo ya confirmado — es, precisamente, la razón por la que esta guía separa con tanto cuidado "esto corrió" de "esto es representativo", lección por lección, en vez de una sola advertencia genérica al final del módulo.
Errores comunes
Pensar que el exit code 55 del Paso 1 es el mismo problema que el error de licencia del Paso 2 (de fusionar dos obstáculos independientes, el mismo error ya nombrado en el Módulo 1, lección 7). Qué pasa: alguien concluye que "LocalStack no funciona" como una sola causa, sin distinguir el entorno específico del límite del servicio. Cómo detectarlo: si no puedes explicar por qué exportar un token no resolvería el Paso 2. Cómo corregirlo: son dos límites completamente independientes, ya distinguidos con precisión en el Módulo 1, lección 7 — el primero es exclusivo de este sandbox de escritura (cualquiera con un token de Hobby lo resuelve); el segundo persiste incluso con ese token, porque Bedrock específicamente exige el plan Ultimate.
Concluir que, como apply no corre aquí, ningún apply de este ecosistema corrió nunca de verdad (de sobre-generalización de alcance, otra vez). Qué pasa: alguien, después de ver este límite, empieza a desconfiar retroactivamente de los apply reales que sí ocurrieron en guías anteriores (S3, DynamoDB, Lambda, IAM). Cómo detectarlo: si tu reacción es "entonces nada de lo anterior se aplicó de verdad tampoco". Cómo corregirlo: la lección 7 de este mismo módulo, inmediatamente después, confirma con precisión que el rol IAM de la lección 4 sí pertenece a la categoría de "en tu propia máquina, con tu propio token, esto se aplica de verdad" — el límite de esta lección es específico de Bedrock, no una condena general del laboratorio $0 de este ecosistema.
Esperar que un token de LocalStack Ultimate resuelva completamente el problema de "ver una respuesta real de un modelo" (de expectativa hacia adelante sobre lo que Ultimate cubriría). Qué pasa: alguien lee "Ultimate" y asume que, con ese plan de pago, extract-shipment-manifest-fields produciría una extracción real de un manifiesto. Cómo detectarlo: si tu plan, después de leer esta lección, es "voy a pagar Ultimate y ya tengo inferencia real". Cómo corregirlo: el Módulo 1, lección 7 ya lo advirtió, en su nota final — incluso con Ultimate, LocalStack ejecuta un modelo local de Ollama como sustituto de Bedrock: es inferencia real, pero de un modelo distinto, nunca el modelo de Bedrock de AWS ni idéntico a producción. Un apply exitoso contra Ultimate crearía el guardrail de verdad en la cuenta emulada, pero ninguna invocación posterior (bedrock-runtime invoke-model) produciría una respuesta del modelo real de Bedrock — la razón exacta por la que esta guía, declarado desde el Módulo 1, nunca corre una inferencia real de Bedrock, en ningún plan de LocalStack.
Ejercicios
Ejercicio 1 — Explica por qué el error representativo de esta lección aparece durante apply, y no durante plan, aunque ambos comandos "toquen" el mismo bedrock.tf. Retoma el mecanismo de la lección 1 de este módulo para responder con precisión.
Ver solución
Porque plan, para un recurso nuevo, nunca necesita hacer la llamada real (CreateGuardrail) que la API de Bedrock tendría que procesar — el diff completo se construye solo con el HCL declarado, sin ninguna petición saliente. apply, en cambio, existe específicamente para ejecutar esa llamada de verdad: en algún punto de su ejecución, tiene que enviar la petición CreateGuardrail al endpoint configurado (LocalStack o AWS real) y esperar una respuesta. Es exactamente en ese punto —la llamada real, no la construcción del diff— donde el límite de plan de licencia de LocalStack se vuelve visible, porque ahí es donde LocalStack, si estuviera corriendo con un token de Hobby, respondería con el error de licencia en vez de crear el recurso.
Ejercicio 2 — Compara el diagrama de esta lección con el del Módulo 1, lección 7. Ambos tienen la misma forma general (dos obstáculos, uno del entorno, uno del servicio). ¿Qué cambió entre uno y otro, específicamente?
Ver solución
La forma es la misma —los dos obstáculos son independientes, uno resoluble con un token, el otro no—, pero el comando que dispara el segundo obstáculo cambió: en el Módulo 1, lección 7, era una operación de lectura (awslocal bedrock list-foundation-models, consultando el catálogo de modelos). En esta lección, es una operación de escritura (tflocal apply, intentando crear un guardrail de verdad). El resultado de fondo es el mismo —Bedrock no está disponible fuera de Ultimate, para ninguna operación—, pero esta lección confirma que el límite no es exclusivo de las lecturas: aplica igual a intentar crear infraestructura nueva.
Ejercicio 3 — Predice qué pasaría si intentaras tflocal apply sobre module.bedrock_manifest_extractor_role (el rol IAM, no el guardrail) en una máquina con LocalStack Hobby corriendo, con token real. Sin adelantarte a leer la lección 7 completa, ¿esperarías el mismo error de licencia que esta lección documentó para el guardrail?
Ver solución
No. IAM, a diferencia de Bedrock, sí está incluido en el plan Hobby de LocalStack —confirmado desde aws-core-services-guide—, así que un apply real contra ese rol, con un token de Hobby (no Ultimate) exportado, se completaría sin ningún error de licencia: el rol se crearía de verdad, con su política inline, en la cuenta emulada de LocalStack. Este es exactamente el contraste que la lección 7 de este módulo desarrolla con detalle — dos recursos en el mismo bedrock.tf, con dos fronteras de ejecución completamente distintas.
Resumen y siguiente paso
Esta lección documentó, con precisión y una fuente oficial verificada de nuevo hoy contra docs.localstack.cloud/aws/services/bedrock/, el límite exacto de este módulo: terraform apply sobre el guardrail de Bedrock se detiene en dos obstáculos independientes —el exit code 55 real de este sandbox de escritura (Módulo 1, lección 7), y el badge oficial "Included in Plans: Ultimate", que persistiría incluso con un token de Hobby real—. Nada de lo ejecutado en las cinco lecciones anteriores de este módulo cambia por esto: fmt, validate y plan corrieron, de verdad, sin depender en ningún momento de este límite específico de apply.
Antes de avanzar deberías poder: explicar por qué el límite de esta lección aparece en apply y no en plan; citar, de memoria o cerca, la frase exacta del badge de LocalStack sobre Bedrock; y anticipar, sin que la lección 7 te lo confirme todavía, que el rol IAM de la lección 4 pertenece a una categoría distinta de este mismo bedrock.tf.
La lección 7 confirma exactamente esa distinción: dentro del mismo archivo, un recurso se detiene aquí (Bedrock, Ultimate-only) y el otro no (IAM, Hobby) — la frontera exacta, con la misma honestidad, sin generalizar en ninguna dirección.
Recursos
- LocalStack Docs — Bedrock — la fuente exacta de esta lección, verificada de nuevo el día de escritura: "Included in Plans: Ultimate".
- LocalStack — Pricing — comparación completa de planes y servicios incluidos en cada uno.
- Módulo 1, lección 7 de esta guía (
07-hands-on-the-honest-attempt-against-bedrock-on-localstack.md) — la fuente delexit code 55real y del mismo patrón de "intento honesto" que esta lección reaplica aapply. - Terraform Docs — Command: apply — referencia oficial, incluida la distinción entre construir el plan y ejecutarlo contra un endpoint real.