Capa de interoperabilidad · Prueba técnica de arquitectura

ADR-022: infraestructura del demo en AWS con OpenTofu

Aceptado el 15/11/2026 por Andrés (propuesto el 10/11/2026 por el carril `infra`; Andrés revisa además el plan antes de cada apply). Reemplazado en parte por ADR-027 (endpoint de la API de Kubernetes). Complementado por ADR-024 y por ADR-030 (fila 8: la entrada sigue con `Gateway` y `VirtualService` de Istio).

Nota del 14/11/2026: el endpoint de la API de Kubernetes ya no es público. ADR-027 lo reemplaza (solo privado, acceso por túnel de Session Manager); el público limitado por IP queda como respaldo. El resto de este ADR sigue igual.

Contexto

F7 pide red, EKS mínimo, complementos (Istio, Secrets Store CSI Driver, EKS Pod Identity), AWS Secrets Manager y los subdominios de docs/demo/02-subdominios-e-interfaz-de-sistemas.md en Cloudflare. El demo se enciende para validar y para la presentación, y se destruye después (docs/plataforma/04-stack.md). Se escribe el código ahora, sin credenciales, y se aplica después.

Restricciones: costo mínimo por hora, apagado fácil, ningún secreto en el repositorio ni en el estado si se puede evitar, y el mismo diseño de seguridad que el resto del proyecto (ADR-008, ADR-009, ADR-016).

Decisiones

# Tema Decisión Alternativa descartada y por qué
1 Raíces Cinco raíces con estado propio: base, cluster, plataforma, dns, auditoria. Se buscan entre sí por nombre y etiquetas, no leyendo el estado de otra Una sola raíz: los proveedores de Helm y Kubernetes dependen de un clúster que aún no existe en el primer plan, y apagar el clúster obligaría a tocar DNS y secretos
2 Estado Local, ignorado por git y cifrado por OpenTofu (AES-GCM, llave derivada de una frase con PBKDF2), obligatorio también para el plan S3 con bloqueo: un recurso más que crear antes de todo; con una sola persona aplicando no aporta. Queda como paso si el demo pasa a un pipeline
3 Valores de secretos Atributos de solo escritura (secret_string_wo) y claves aleatorias efímeras: los valores no quedan en el estado ni en el plan. Las claves externas (Confluent, Stripe) entran por una variable efímera Cargar los valores con la CLI de AWS: no está instalada y deja el paso fuera del código. Valores normales: quedarían en el estado
4 Secretos por carga Un secreto JSON por carga, un rol de IAM por carga que solo lee el suyo, asociado por EKS Pod Identity a su cuenta de servicio Un rol compartido: cualquier servicio leería las claves de otro
5 Complementos Todo lo posible como complemento administrado de EKS, en su versión por defecto para la versión de Kubernetes: vpc-cni, coredns, kube-proxy, eks-pod-identity-agent, aws-ebs-csi-driver y aws-secrets-store-csi-driver-provider (instala el driver y el proveedor de AWS, con rotación encendida) Charts de Helm: más versiones que fijar y requieren acceso al clúster para instalarse
6 Istio Charts base, istiod y gateway por Helm en la raíz plataforma, con pedidos de memoria recortados. Las políticas de la malla quedan en platform/k8s (F6) Istio en modo ambient: descartado en ADR-008
7 Entrada El gateway de entrada de Istio pide un NLB (Network Load Balancer, balanceador de red de AWS) al controlador de servicios que trae EKS. El NLB solo acepta los rangos de Cloudflare y solo el puerto 443 AWS Load Balancer Controller: un componente más con su rol y su chart, sin ganancia para un solo balanceador. Cloudflare Tunnel: quita el NLB, pero es una pieza que el diseño no prevé
8 TLS de origen Certificado de origen de Cloudflare (modo Full strict) en un Secret de istio-ingress. Su llave queda en el estado cifrado de plataforma cert-manager con Let's Encrypt: Cloudflare ya termina el TLS del público; el origen solo necesita confiar en Cloudflare
9 DNS y Access Solo los nueve subdominios del clúster (api, hooks, auth, erp, wms, oms, crm, grafana, lab), con proxy. La tienda, www, docs y marketplace son de Pages y del otro frente. Access protege erp, wms, oms, crm, grafana y lab; la ruta de la API de cada sistema queda fuera de Access para que el modo AS-IS funcione, y en TO-BE la cierra Istio Access sobre todo el host: el modo AS-IS dejaría de responder a k6
10 Tamaño Dos zonas, un NAT Gateway, dos nodos m7i-flex.xlarge bajo demanda (32 GiB en total). SPOT es una variable para las corridas de validación Tres zonas y un NAT por zona: lo de producción, el triple de costo fijo. Graviton: más barato, pero obliga a construir imágenes para ARM
11 Repositorios Amazon ECR con etiquetas inmutables, escaneo al subir y retención de 10 imágenes Docker Hub: límites de descarga y otra credencial
12 Apagado Interruptores por raíz (cluster_enabled, node_count, ingress_enabled, dns_enabled) y make infra-off, que destruye dns, plataforma y cluster en ese orden. make infra-audit falla si queda algo cobrando, incluido lo que crea el clúster y no OpenTofu (NLB y discos) Confiar en tofu destroy: no ve el NLB ni los discos de los PersistentVolumeClaim, que quedan huérfanos y cobrando
13 Presupuesto Dos presupuestos de AWS Budgets (mensual y diario) en base, que se aplica antes que nada Solo mensual: avisa tarde de un clúster olvidado un fin de semana
14 Análisis de seguridad Trivy sobre infra/tofu en make verify; falla con cualquier hallazgo. Tres excepciones escritas en el código con su razón: endpoint público de EKS limitado a rangos, logs del plano de control solo audit y authenticator, registro de flujos de la VPC apagado. Las dos últimas por costo, con interruptor Checkov: requiere Python y un entorno virtual; Trivy es un binario que se baja y valida como las demás herramientas

Qué se sacrifica

Lo que se verifica al tener credenciales

Lo que no se puede comprobar sin cuenta va como pendiente en infra/tofu/README.md: el esquema de configuración de los complementos de EKS, la etiqueta que el controlador pone al NLB y el primer tofu plan de cada raíz.