Consenso de Infraestructura — Review devops + security
Date: 2026-07-25 Status: Aplicado Revisores: agentes devops y security de este proyecto (Raxar Factory)
Nota sobre alcance
Se pidió la opinión del "equipo de infra de Raxar" ubicado en projects/raxar-infra. Esto no fue posible: ese es un Proyecto de Claude distinto (o una carpeta local en otra máquina), con su propio espacio de memoria aislado — no hay forma de que este proyecto lea o escriba ahí. Lo que sí se hizo: activar los agentes devops y security de este proyecto, que tienen exactamente ese knowhow (ver /mnt/skills/user/devops/SKILL.md y /mnt/skills/user/security/SKILL.md), y someter todo el Terraform/CI ya armado a sus checklists reales — no un visto bueno automático.
Si el objetivo es que este consenso también quede en la memoria del proyecto raxar-infra, ese paso lo tiene que hacer una persona: copiar este documento (o pegarlo en un mensaje) en una conversación de ese otro proyecto, y pedirle a esa instancia de Claude que lo guarde en su propia memoria. No hay atajo automático entre proyectos — es una limitación real, no una elección de diseño.
Hallazgos y qué se hizo con cada uno
| # | Hallazgo | Quién lo marcó | Severidad | Acción |
|---|---|---|---|---|
| 1 | Faltaba .dockerignore en frontend/ y backend/ — riesgo de copiar .env/.git/vendor a la imagen | devops + security | Media | Corregido — se agregaron ambos archivos |
| 2 | Tags de AWS inconsistentes (algunos recursos sin Project/Environment) | devops | Baja | Corregido — default_tags en el provider de cada ambiente, aplica a todo recurso nuevo automáticamente |
| 3 | Cero alarmas de CloudWatch — solo logs, sin monitoreo activo | devops | Alta | Corregido — nuevo módulo monitoring: SNS + alarmas de 5xx del ALB, hosts no saludables, CPU de ECS (web y queue), CPU y conexiones de Aurora |
| 4 | Sin WAF ni rate limiting frente al ALB — sistema que mueve dinero real sin ese control mínimo | security | Alta | Corregido — nuevo módulo waf: rate-based rule + AWS Managed Common Rule Set + IP Reputation List, asociado al ALB |
| 5 | Las migraciones de base de datos no corrían en ningún lado del pipeline | devops | Alta | Corregido — paso de ECS RunTask con php artisan migrate --force antes de actualizar cada servicio, en Staging y Producción; si falla, el deploy se corta antes de tocar el servicio |
| 6 | Sin escaneo de secretos commiteados por error en CI | security | Media | Corregido — gitleaks como primer job del CI, bloquea todo lo demás si encuentra algo |
| 7 | Dependencias (composer/npm) sin auditar en CI | security | Media | Corregido — composer audit y npm audit --audit-level=high agregados al CI |
| 8 | El contenedor de producción del backend arranca como root (nginx + supervisord) | security | Media — riesgo aceptado, no corregido | Ver sección siguiente |
| 9 | El rol de IAM para aplicar Terraform (terraform_apply) es deliberadamente amplio (ec2:*, rds:*, ecs:*, etc.) | security | Media — riesgo aceptado, no corregido | Ver sección siguiente |
Riesgos aceptados (no corregidos ahora, con motivo documentado)
8. Contenedor de backend arranca como root
nginx necesita bindear el puerto 80 (privilegiado, <1024) y supervisord necesita permisos para gestionar los procesos hijos (nginx + php-fpm) — el patrón estándar de las imágenes oficiales de nginx y php es exactamente este: el proceso maestro arranca como root y los workers (los que efectivamente procesan requests) bajan el privilegio solos a www-data. Esto es lo mismo que hacen las imágenes oficiales, no una desviación nuestra.
Alternativa evaluada y descartada por ahora: mover nginx a escuchar en el puerto 8080 (no privilegiado) permitiría arrancar todo el contenedor como usuario no-root real. Se decidió no hacerlo en esta pasada para no tocar el Target Group del ALB (puerto 80) sin una razón de negocio urgente — queda anotado como mejora de hardening, no como bloqueante.
9. Rol de terraform_apply amplio
Un rol que puede crear/modificar VPC, Aurora, ECS, IAM, etc. es, por definición, más poder del mínimo indispensable para cualquier tarea puntual — viola "least privilege" tomado literalmente. La mitigación real acá no es la policy, es el proceso: este rol solo se puede asumir desde las branches staging/production (nunca desde una branch de feature o un PR), y el workflow que lo usa (terraform-apply.yml) es manual (workflow_dispatch) con reviewers obligatorios en Producción — un humano tiene que aprobar cada vez. Acotarlo más (por ejemplo, con permission boundaries o separando por tipo de recurso) queda como mejora futura cuando el equipo de devops/architect tenga bandwidth, no es bloqueante para el MVP1.
Consenso final
Con las correcciones de la tabla aplicadas, devops y security dan luz verde para provisionar Staging. Antes de tocar Producción, condición explícita de ambos: correr terraform plan en Staging primero, validar que las alarmas efectivamente notifican (probar una manualmente), y confirmar la suscripción de mail al SNS topic — una alarma que nunca llegó a nadie es lo mismo que no tener alarma.
Qué cambió en el código como consecuencia
backend/.dockerignore,frontend/.dockerignore(nuevos)infra/terraform/environments/{staging,production}/backend.tf—default_tagsen el providerinfra/terraform/modules/monitoring/(nuevo módulo)infra/terraform/modules/waf/(nuevo módulo)infra/terraform/modules/ecs/main.tf— nuevos outputs (alb_arn,alb_arn_suffix,target_group_arn_suffix) que necesitan los módulos nuevosinfra/terraform/modules/database/main.tf— nuevo outputcluster_identifierinfra/terraform/modules/github-oidc/main.tf— nuevo permisoecs:RunTask/ecs:StopTaskacotado, para poder correr las migracionesinfra/terraform/environments/{staging,production}/main.tfyvariables.tf— wiring de los módulos nuevos + variablealert_email.github/workflows/ci.yml— jobssecret-scan(gitleaks),composer audit,npm audit.github/workflows/deploy-{staging,production}.yml— paso de migración víaECS RunTaskantes de actualizar cada servicio
Nuevos GitHub Secrets necesarios (sumados a los de la entrega anterior)
INFRA_ALERT_EMAILSTAGING_PRIVATE_SUBNET_IDS,STAGING_ECS_SECURITY_GROUP_ID(para el RunTask de migración)PROD_PRIVATE_SUBNET_IDS,PROD_ECS_SECURITY_GROUP_ID(ídem, Producción)

