Una inmersión profunda en la construcción de una Plataforma de Publicación Omnicanal segura y escalable desde cero. Desde arquitectura hexagonal y despliegues de modo dual hasta seguridad Zero Trust, trazabilidad golden thread e integración con IA para publicación en redes sociales — esta es la anatomía de un proyecto DevSecOps moderno.
Todo ingeniero tiene ese proyecto — el que comienza como una idea simple y evoluciona hasta convertirse en un laboratorio de aprendizaje invaluable. Para mí, ese proyecto es esta Publisher Web App: un sistema diseñado para publicar anuncios en múltiples canales de redes sociales simultáneamente. ¿El caso de uso principal? El AWS Certification Announcer, una herramienta comunitaria donde los miembros envían sus logros de certificación AWS y la plataforma los publica automáticamente en Facebook, Instagram, WhatsApp, LinkedIn, Email, etc.
Lo que comenzó como una necesidad práctica para el AWS User Group rápidamente se convirtió en un ejercicio conveniente para aplicar cada principio DevSecOps que siempre quise poner en práctica, pero no había podido hasta ahora. Este artículo recorre los fundamentos del proyecto — la arquitectura, los lineamientos de seguridad, la estrategia de despliegue y las lecciones aprendidas en el camino.
El proyecto completo es open source y está disponible en github.com/Walsen/devsecops-poc .
El objetivo nunca fue construir “otro notificador de redes sociales más”. La visión era crear una plataforma que sirviera como implementación de referencia para el desarrollo cloud-native moderno — una que demuestre cómo construir software que sea seguro por diseño, portable entre modelos de despliegue y mantenible a lo largo del tiempo.
La plataforma necesitaba:
Si hay una decisión arquitectónica que hizo posible todo lo demás, es la adopción de la arquitectura hexagonal (también conocida como Patrón de Puertos y Adaptadores).
Este patrón separa el sistema en tres zonas concéntricas:
| Zona | Responsabilidad | Dependencias |
|---|---|---|
| Adaptadores de Entrada | Reciben input externo (HTTP, eventos Kinesis, cron) | Dependen de Puertos de Entrada |
| Núcleo de Aplicación | Lógica de negocio, casos de uso, modelo de dominio | Cero dependencias externas |
| Adaptadores de Salida | Implementan integraciones de salida (BD, colas, APIs) | Implementan Puertos de Salida |
El núcleo de la aplicación — entidades de dominio, casos de uso e interfaces de puertos — no tiene absolutamente ningún conocimiento del mundo exterior. No sabe si está corriendo en ECS o Lambda. No sabe si la base de datos es PostgreSQL o DynamoDB. Solo conoce abstracciones.
El dominio está construido con dataclasses puras de Python:
| Entidad / Value Object | Descripción |
|---|---|
Message (Aggregate Root) |
Rastrea contenido, canales, programación, estado y entregas por canal |
Certification (Entity) |
Logro de certificación AWS con información del miembro y tipo |
ChannelType (Value Object) |
Enum: facebook, instagram, linkedin, whatsapp, email, sms |
MessageStatus (Value Object) |
Ciclo de vida: DRAFT → SCHEDULED → PROCESSING → DELIVERED / FAILED |
DeliveryResult (Value Object) |
Resultado por canal con ID externo o error |
El puerto MessageRepository es la misma interfaz independientemente del modo de despliegue. Solo cambia el adaptador:
# Puerto (compartido entre ambos modos)
class MessageRepository(ABC):
@abstractmethod
async def get_by_id(self, id: UUID) -> Message | None: ...
@abstractmethod
async def save(self, message: Message) -> None: ...
# Adaptador para contenedores
class PostgresMessageRepository(MessageRepository):
def __init__(self, session: AsyncSession):
self._session = session
# Adaptador serverless
class DynamoMessageRepository(MessageRepository):
def __init__(self, table_name: str):
self._table = boto3.resource("dynamodb").Table(table_name)
Este es el habilitador clave para la estrategia de despliegue de modo dual. La lógica de negocio está completamente desacoplada de la infraestructura.
La plataforma está compuesta por tres microservicios conectados por Amazon Kinesis Data Streams:
Cada servicio tiene su propio main.py que sirve como composition root — el único lugar donde se importan e inyectan las implementaciones concretas. Ningún otro módulo importa directamente desde infrastructure/.
Aquí es donde la arquitectura hexagonal rinde frutos de manera muy tangible. La plataforma soporta dos modos de despliegue completamente independientes, intercambiables al momento del despliegue mediante un solo parámetro de CI/CD:
Contenedores (infra/) |
Serverless (infra-fs/) |
|
|---|---|---|
| Cómputo | ECS Fargate | Lambda |
| Base de Datos | PostgreSQL (RDS) | DynamoDB (Single-Table) |
| API Gateway | ALB + CloudFront | API Gateway + CloudFront |
| Scheduler | Servicio ECS (APScheduler) | EventBridge + Lambda |
| Costo (bajo tráfico) | ~$180-200/mes | ~$5-15/mes |
Ambos modos comparten las mismas capas de dominio y aplicación. Solo cambian los adaptadores de infraestructura. El workflow de despliegue selecciona el modo vía el input infra_type (containers o serverless), enrutando al proyecto CDK correspondiente. Los nombres de stack son completamente independientes, por lo que ambos pueden coexistir en la misma cuenta AWS durante una migración.
Diferentes etapas de un proyecto tienen diferentes necesidades:
| Etapa | Modo Recomendado | Razón |
|---|---|---|
| Desarrollo / Prototipado | Serverless | Costo casi nulo, despliegues instantáneos |
| Staging / QA | Cualquiera | Igualar producción o ahorrar costos |
| Producción (tráfico estable) | Contenedores | Latencia predecible, sin cold starts |
| Producción (tráfico variable) | Serverless | Pago por uso, auto-scaling |
Puedes comenzar barato con serverless y migrar a contenedores cuando el tráfico justifique el costo fijo — o viceversa — sin reescribir una sola línea de lógica de negocio.
Dado que los nombres de stack son independientes, puedes ejecutar ambos modos en paralelo durante una ventana de migración. Esto permite hacer smoke testing contra el nuevo modo antes de hacer el corte, migración gradual de tráfico usando enrutamiento DNS ponderado (Route 53) y rollback instantáneo cambiando el DNS de vuelta.
La seguridad no es una funcionalidad que se agrega al final. Es un principio de diseño que permea cada capa del sistema. La plataforma implementa una arquitectura Zero Trust basada en tres pilares:
Todo el tráfico fluye a través de múltiples capas de seguridad:
La VPC está segmentada en subredes públicas, privadas y aisladas. Los security groups aplican micro-segmentación — el ALB solo puede comunicarse con la API, la API solo puede comunicarse con el Worker y la base de datos, y la base de datos solo acepta conexiones de servicios autorizados.
Cada solicitud se valida contra JWTs de Cognito con restricción estricta de algoritmo (solo RS256), validación de audience e issuer, y caché de JWKS con refresco por TTL. Las credenciales OAuth para proveedores sociales se almacenan en AWS Secrets Manager.
El servicio API implementa un stack completo de middleware de seguridad:
| Aspecto | Implementación |
|---|---|
| Autenticación | Validación JWT de Cognito con restricción de algoritmo |
| Protección CSRF | Double Submit Cookie con tokens firmados por HMAC |
| Rate Limiting | Ventana deslizante por usuario (60 req/min) |
| Validación de Requests | Límite de 1MB, sanitización de input, escape de HTML |
| Headers de Seguridad | CSP, HSTS, X-Frame-Options, Permissions-Policy |
| Filtrado de Contenido | Detección de prompt injection + escaneo de PII |
| Idempotencia | Deduplicación basada en hash de message_id + channels |
El cifrado se aplica en cada capa:
El pipeline de build está endurecido contra ataques a la cadena de suministro con múltiples puertas de seguridad:
Ningún escáner individual lo detecta todo. El proyecto utiliza seis herramientas complementarias:
| Escáner | Tipo | Propósito |
|---|---|---|
| Semgrep | SAST | Patrones OWASP Top 10, reglas personalizadas |
| Bandit | SAST | Problemas de seguridad específicos de Python |
| pip-audit | SCA | Base de datos de CVEs de Python (PyPI Advisory) |
| Trivy | SCA | Escaneo de vulnerabilidades en SBOM |
| Gitleaks | Secrets | Detección de secretos hardcodeados en historial git |
| Checkov | IaC | Misconfiguraciones de seguridad AWS en CDK/CloudFormation |
Cada herramienta cubre puntos ciegos que las demás no detectan. Semgrep captura patrones de SQL injection y XSS. Bandit encuentra problemas específicos de Python como carga insegura de YAML. pip-audit y Trivy manejan CVEs conocidos. Gitleaks previene fugas de credenciales. Checkov asegura que la infraestructura misma sea segura — sin buckets S3 públicos, sin cifrado faltante, sin IAM excesivamente permisivo.
Los contenedores de producción se construyen con la seguridad como prioridad:
nonroot por defectoEl proyecto usa GitHub Actions OIDC para asumir roles IAM de AWS sin almacenar credenciales de larga duración. Un stack de bootstrap CDK (GitHubOIDCStack) crea el proveedor OIDC y dos roles IAM:
github-actions-deploy): Para despliegues CDK y pushes a ECRgithub-actions-security-scan): Para auditorías Prowler con acceso de solo lecturaNo se almacenan access keys de AWS en GitHub Secrets. Cada despliegue usa credenciales de corta duración (1 hora) obtenidas vía federación OIDC.
Uno de los aspectos más interesantes del proyecto es el Golden Thread — un ejercicio de trazabilidad distribuida que demuestra la correlación de solicitudes de extremo a extremo a través de todas las capas de infraestructura usando un único ID de correlación (X-Request-ID).
El ID de correlación fluye a través de:
/* correlation_id=golden-thread-test-1739... */ INSERT INTO messages (id, content_text, ...) VALUES (...)
Todo consultable desde CloudWatch Logs Insights con un solo filtro:
fields @timestamp, service, event, correlation_id, method, path, status_code
| filter correlation_id = "YOUR_TRACE_ID"
| sort @timestamp asc
El proyecto incluye ejercicios prácticos que simulan ataques reales y los rastrean a través de las capas:
' OR 1=1--, verificar que el WAF lo bloquea, confirmar que la solicitud nunca llega a la aplicación<script>alert(1)</script>, rastrear el bloqueo del WAF en CloudWatchLa documentación también incluye ejercicios usando herramientas profesionales de penetration testing — nmap, nikto, sqlmap, ffuf, nuclei e hydra — cada una con las consultas CloudWatch correspondientes para rastrear las firmas de ataque a través de la infraestructura.
El servicio Worker soporta dos estrategias de publicación, seleccionables vía configuración:
El AgentPublisher usa el Strands Agents SDK con Amazon Bedrock (Claude) para adaptar inteligentemente el contenido para cada plataforma:
| Plataforma | Adaptación |
|---|---|
| Posts más largos, emojis, hashtags al final | |
| Enfoque visual, muchos emojis, hashtags | |
| Tono profesional, lenguaje formal | |
| Corto, celebratorio, personal |
El agente razona sobre qué herramientas llamar, las ejecuta, observa los resultados y continúa hasta completar la tarea. El middleware de filtrado de contenido protege contra prompt injection y fuga de PII en la salida generada por IA.
Quizás la adición más novedosa al proyecto es el Agente de Testing de Seguridad — un asistente interactivo de penetration testing impulsado por IA, construido con el Strands Agents SDK y Amazon Bedrock. En lugar de ejecutar pruebas de seguridad manualmente e interpretar resultados, tienes una conversación con un agente que puede ejecutar tests, diagnosticar fallos, consultar recursos AWS e incluso auto-corregir código de pruebas.
La interacción se ve así:
🔒 Penetration Testing Agent Ready!
Tú: Ejecuta todos los tests rápidos
Agente: Voy a ejecutar la suite de tests rápidos en paralelo, omitiendo escaneos lentos...
✅ Todos los tests pasaron en 8 segundos!
Tú: El test de TLS está fallando, ¿puedes debuggearlo?
Agente: Déjame ejecutar el test de TLS y revisar los logs...
[ejecuta test, consulta CloudFormation para endpoints, revisa CloudWatch]
El certificado para api.ugcbba.click expiró. Esto es lo que encontré...
El agente aplica límites de seguridad estrictos:
testing/ — el path traversal está bloqueadoEl agente envuelve una suite completa de tests de seguridad basada en pytest que corre dentro de un contenedor Kali Linux:
| Categoría | Tests | Duración |
|---|---|---|
| Rápidos (< 10s c/u) | Health, headers de seguridad, TLS, CORS, cookies, divulgación de errores, métodos HTTP, acceso por origen, SQLi, XSS | ~10s total |
| Medios (15-30s) | Rate limiting, CSRF end-to-end, protección IDOR | ~1 min |
| Lentos (30s-10min) | Escaneo de puertos nmap, escaneo web Nikto, inyección automatizada sqlmap | ~15 min |
El agente es inteligente sobre qué tests ejecutar — prioriza tests que fallaron recientemente, omite escaneos lentos a menos que se soliciten explícitamente, y cachea resultados exitosos por 5 minutos para evitar ejecuciones redundantes. La ejecución paralela vía pytest-xdist hace que la suite rápida completa termine en unos 8 segundos.
Más allá del agente de IA, el proyecto incluye un framework independiente de penetration testing automatizado usando Kali Linux dockerizado. Esta es la base sobre la que el agente se construye, pero también puede usarse de forma independiente en pipelines de CI/CD.
# Construir el contenedor Kali
docker build -f testing/Dockerfile.kali -t pentest:latest testing/
# Smoke test rápido
docker run --rm -e TARGET_URL=http://your-alb.amazonaws.com pentest smoke
# Suite completa de tests
docker run --rm -e TARGET_URL=http://your-alb.amazonaws.com pentest all
# Generar reporte
docker run --rm -v $(pwd):/tests -e TARGET_URL=$TARGET_URL pentest report
El framework se integra con GitHub Actions para escaneos semanales programados y testing bajo demanda, con resultados subidos como artefactos del workflow.
La plataforma implementa detección y respuesta automatizada de amenazas:
GuardDuty monitorea amenazas. Cuando se detecta un hallazgo con severidad >= 4, una regla de EventBridge dispara una función Lambda que automáticamente bloquea la IP ofensora en el IP set del WAF y envía una alerta detallada a Slack. Security Hub agrega hallazgos de GuardDuty, CloudTrail y reglas de AWS Config para una vista unificada de cumplimiento.
Dashboards y alarmas de CloudWatch proporcionan visibilidad en tiempo real:
| Métrica | Umbral | Acción |
|---|---|---|
| Fallos de autenticación (5min) | >= 20 | Alarma + SNS |
| Fallos CSRF (5min) | >= 20 | Alarma + SNS |
| Acceso denegado (5min) | >= 30 | Alarma + SNS |
| Hits de rate limit (5min) | >= 100 | Alarma + SNS |
| Tasa de errores (5min) | >= 10 | Alarma + SNS |
| Errores críticos (1min) | >= 1 | Alarma + SNS |
| Latencia API p95 | > 1000ms | Alarma + SNS |
Un buen proyecto DevSecOps no se trata solo de seguridad y arquitectura — también se trata de hacer la vida del desarrollador más fácil. El proyecto usa Devbox para entornos de desarrollo aislados y Just como task runner.
El justfile proporciona un conjunto completo de comandos:
# Desarrollo
just dev # Iniciar servicios locales y seguir logs
just up # Iniciar PostgreSQL + LocalStack
just test # Ejecutar todos los tests
just lint-local # Lint de todos los servicios localmente
# Seguridad
just security-scan # SAST + SCA + Escaneo de secretos
just trivy-scan # Escaneo de vulnerabilidades de contenedores
just sbom-scan # Generar y escanear SBOMs
just iac-scan # Escaneo de infraestructura con Checkov
just pentest-full # Ejecutar la suite completa de penetration testing
# Gestión de Recursos AWS (Ahorro de Costos)
just aws-up # Escalar servicios ECS + iniciar RDS
just aws-down # Escalar a cero (ahorrar dinero)
just aws-status # Verificar estado de recursos
Los comandos aws-up y aws-down son particularmente útiles — permiten escalar toda la infraestructura a cero cuando no está en uso, ahorrando costos significativos durante el desarrollo.
El código está organizado para claridad y separación de responsabilidades:
.
├── api/ # Servicio API (FastAPI + hexagonal)
│ ├── src/
│ │ ├── domain/ # Entidades de negocio, value objects
│ │ ├── application/ # Casos de uso, puertos, DTOs
│ │ ├── infrastructure/ # Adaptadores (BD, Kinesis, Secrets)
│ │ └── presentation/ # Rutas HTTP, middleware
│ └── tests/
│
├── worker/ # Servicio Worker (consumidor Kinesis)
│ ├── src/
│ │ ├── domain/ # Puertos para canales, publishers
│ │ ├── application/ # Servicio de entrega
│ │ ├── infrastructure/ # Adaptadores de publisher (Directo, Agente IA)
│ │ └── channels/ # Gateways de canal (FB, IG, LI, Email, SMS)
│ └── tests/
│
├── scheduler/ # Servicio Scheduler (cron + ECS)
├── api-lambda/ # Handler Lambda de API (serverless)
├── worker-lambda/ # Handler Lambda de Worker (serverless)
├── scheduler-lambda/ # Handler Lambda de Scheduler (serverless)
├── web/ # Frontend (React + Vite + TypeScript)
│
├── testing/ # Framework de penetration testing
│ ├── pentest_agent.py # Agente de testing de seguridad con IA (Strands SDK)
│ ├── test_pentest.py # Casos de test de seguridad (pytest)
│ ├── Dockerfile.kali # Contenedor Kali Linux con herramientas
│ └── justfile # Task runner de pentest
│
├── infra/ # Infraestructura CDK (contenedores)
│ └── stacks/ # Network, Security, Auth, Data, Compute, Edge, Monitoring
│
├── infra-fs/ # Infraestructura CDK (serverless)
│ └── stacks/ # Data, Auth, API, Worker, Scheduler, Security, Frontend
│
├── docs/ # Documentación completa
├── .github/workflows/ # CI/CD (despliegue + escaneo de seguridad)
├── devbox.json # Entorno de desarrollo
├── docker-compose.yml # Servicios locales
└── justfile # Task runner
Construir este proyecto reforzó varias convicciones:
La arquitectura hexagonal no es overhead académico. Es la decisión única que habilitó el despliegue de modo dual, testing limpio y un código base que permanece navegable a medida que crece. La inversión inicial en definir puertos y adaptadores se paga muchas veces.
El escaneo de seguridad debe ser por capas. Ninguna herramienta individual lo detecta todo. La combinación de SAST, SCA, escaneo de secretos, escaneo de IaC y DAST proporciona una genuina defensa en profundidad. La clave es hacer estos escaneos rápidos y automáticos — si ralentizan al desarrollador, serán evitados.
Los IDs de correlación son innegociables. La capacidad de rastrear una sola solicitud desde CloudFront a través de la API, hacia Kinesis, a través del Worker y hasta la base de datos es invaluable para debugging, respuesta a incidentes y análisis forense de seguridad. Impleméntalos desde el día uno.
La gestión de costos es una funcionalidad. El patrón aws-up / aws-down para escalar recursos a cero cuando no están en uso es simple pero efectivo. Para un proyecto como este, es la diferencia entre una factura de $200/mes y una de $5/mes durante el desarrollo.
Los agentes de IA necesitan guardrails. La integración con Strands Agents es poderosa, pero sin filtrado de contenido, detección de prompt injection y validación de salida, es un riesgo. El agente solo puede ejecutar operaciones pre-aprobadas a través de interfaces de herramientas bien definidas — nunca llamadas directas a APIs. El mismo principio aplica al Agente de Testing de Seguridad: opera dentro de una lista blanca estricta de tests y acceso de solo lectura a AWS, demostrando que la automatización impulsada por IA y los límites de seguridad pueden coexistir.
Este proyecto es un laboratorio viviente. No está terminado, y probablemente nunca lo estará — porque el panorama de amenazas, herramientas y mejores prácticas está siempre evolucionando. Pero cumple su propósito: una referencia concreta y open source de cómo construir aplicaciones cloud-native modernas con seguridad tejida en cada capa.
Si estás comenzando un nuevo proyecto y te preguntas por dónde empezar con DevSecOps, mi consejo es simple: comienza por la arquitectura. Implementa bien la arquitectura hexagonal, define tus puertos y adaptadores, y el resto — seguridad, testing, flexibilidad de despliegue — se vuelve dramáticamente más fácil.
El código es open source. Haz fork, rómpelo, mejóralo. Para eso está.
Keyboard Shortcuts
| Command | Function |
|---|---|
| ? (Shift+/) | Bring up this help modal |
| g+h | Go to Home |
| g+p | Go to Posts |
| g+e | Open Editor page on GitHub in a new tab |
| g+s | Open Source page on GitHub in a new tab |
| r | Reload page |