Protegiendo nuestras API's de manera inteligente.
Una manera eficiente de manejar un incidente, de punta a punta, con Wazuh y N8N. ¿El limite? La imaginación.

I have a bachelor's degree in Technology from the University of Palermo, a Master in Information Security from the University of Murcia and different certifications such as CISSP | CISM | CDPSE | CCSK | CSX | MCSA | SMAC™️ | DSOE | DEPC | CSFPC | CSFPC | 5x AWS Certified.
He is currently CISO at Klar, a Mexican Fintech. He was fortunate to be awarded as CISO of the Year in Argentina in 2021 and was among the Top 100 CISO's in the World in 2022.
A lover of new technologies, he has developed a career in DevSecOps and Cloud Security at Eko Party, the largest security conference in Latin America.
Introducción
Generé una API Dummy de cuentas bancarias y para protegerla vamos a tener API Manager Kong al frente, reportando los log’s de las consultas que recibe a Wazuh. Si tenemos coincidencia con algunas de las reglas que cargaremos en Wazuh, se responderá al evento. Esa respuesta será dada por N8N, ejecutando un flujo de trabajo donde realizaremos diferentes pasos, como agregar la dirección del atacante en una lista negra de Kong o enviar un mensaje o, por qué no, levantar el caso en The Hive. Como si fuera poco agregamos Konga para la gestión grafica de Kong.

Arquitectura
Antes de eso deberían descargar la configuración de Wazuh Docker, para esta ocasión uso single-node-stack.
git clone https://github.com/wazuh/wazuh-docker.git -b v4.13.1
Generamos los certificados.
cd wazuh-docker/single-node/
docker compose -f generate-indexer-certs.yml run --rm generator
Una vez que lo corramos, podemos modificar le docker-compose original, con todo el stack necesario para esta prueba de concepto.
# Wazuh App Copyright (C) 2017, Wazuh Inc. (License GPLv2)
services:
wazuh.manager:
image: wazuh/wazuh-manager:4.13.1
hostname: wazuh.manager
restart: always
ulimits:
memlock:
soft: -1
hard: -1
nofile:
soft: 655360
hard: 655360
ports:
- "1514:1514"
- "1515:1515"
- "514:514/udp"
- "55000:55000"
environment:
- INDEXER_URL=https://wazuh.indexer:9200
- INDEXER_USERNAME=admin
- INDEXER_PASSWORD=SecretPassword
- FILEBEAT_SSL_VERIFICATION_MODE=none
- SSL_CERTIFICATE_AUTHORITIES=/etc/ssl/root-ca.pem
- SSL_CERTIFICATE=/etc/ssl/filebeat.pem
- SSL_KEY=/etc/ssl/filebeat.key
- API_USERNAME=wazuh-wui
- API_PASSWORD=MyS3cr37P450r.*-
volumes:
- wazuh_api_configuration:/var/ossec/api/configuration
- wazuh_etc:/var/ossec/etc
- wazuh_logs:/var/ossec/logs
- wazuh_queue:/var/ossec/queue
- wazuh_var_multigroups:/var/ossec/var/multigroups
- wazuh_integrations:/var/ossec/integrations
- wazuh_active_response:/var/ossec/active-response/bin
- wazuh_agentless:/var/ossec/agentless
- wazuh_wodles:/var/ossec/wodles
- filebeat_etc:/etc/filebeat
- filebeat_var:/var/lib/filebeat
- ./config/wazuh_indexer_ssl_certs/root-ca-manager.pem:/etc/ssl/root-ca.pem
- ./config/wazuh_indexer_ssl_certs/wazuh.manager.pem:/etc/ssl/filebeat.pem
- ./config/wazuh_indexer_ssl_certs/wazuh.manager-key.pem:/etc/ssl/filebeat.key
- ./config/wazuh_cluster/wazuh_manager.conf:/wazuh-config-mount/etc/ossec.conf
- ./config/wazuh_cluster/kong-rules.xml:/var/ossec/etc/rules/kong-rules.xml:ro
- ./config/wazuh_cluster/0374-kong-decoder.xml:/var/ossec/etc/decoders/0374-kong-decoder.xml:ro # Agrego el decoder para Kong.
- ./config/wazuh_cluster/custom-n8n:/var/ossec/integrations/custom-n8n:ro
networks:
- poc-network
wazuh.indexer:
image: wazuh/wazuh-indexer:4.13.1
hostname: wazuh.indexer
restart: always
ports:
- "9200:9200"
environment:
- "OPENSEARCH_JAVA_OPTS=-Xms1g -Xmx1g"
ulimits:
memlock:
soft: -1
hard: -1
nofile:
soft: 65536
hard: 65536
volumes:
- wazuh-indexer-data:/var/lib/wazuh-indexer
- ./config/wazuh_indexer_ssl_certs/root-ca.pem:/usr/share/wazuh-indexer/certs/root-ca.pem
- ./config/wazuh_indexer_ssl_certs/wazuh.indexer-key.pem:/usr/share/wazuh-indexer/certs/wazuh.indexer.key
- ./config/wazuh_indexer_ssl_certs/wazuh.indexer.pem:/usr/share/wazuh-indexer/certs/wazuh.indexer.pem
- ./config/wazuh_indexer_ssl_certs/admin.pem:/usr/share/wazuh-indexer/certs/admin.pem
- ./config/wazuh_indexer_ssl_certs/admin-key.pem:/usr/share/wazuh-indexer/certs/admin-key.pem
- ./config/wazuh_indexer/wazuh.indexer.yml:/usr/share/wazuh-indexer/opensearch.yml
- ./config/wazuh_indexer/internal_users.yml:/usr/share/wazuh-indexer/opensearch-security/internal_users.yml
networks:
- poc-network
wazuh.dashboard:
image: wazuh/wazuh-dashboard:4.13.1
hostname: wazuh.dashboard
restart: always
ports:
- 443:5601
environment:
- INDEXER_USERNAME=admin
- INDEXER_PASSWORD=SecretPassword
- WAZUH_API_URL=https://wazuh.manager
- DASHBOARD_USERNAME=kibanaserver
- DASHBOARD_PASSWORD=kibanaserver
- API_USERNAME=wazuh-wui
- API_PASSWORD=MyS3cr37P450r.*-
volumes:
- ./config/wazuh_indexer_ssl_certs/wazuh.dashboard.pem:/usr/share/wazuh-dashboard/certs/wazuh-dashboard.pem
- ./config/wazuh_indexer_ssl_certs/wazuh.dashboard-key.pem:/usr/share/wazuh-dashboard/certs/wazuh-dashboard-key.pem
- ./config/wazuh_indexer_ssl_certs/root-ca.pem:/usr/share/wazuh-dashboard/certs/root-ca.pem
- ./config/wazuh_dashboard/opensearch_dashboards.yml:/usr/share/wazuh-dashboard/config/opensearch_dashboards.yml
- ./config/wazuh_dashboard/wazuh.yml:/usr/share/wazuh-dashboard/data/wazuh/config/wazuh.yml
- wazuh-dashboard-config:/usr/share/wazuh-dashboard/data/wazuh/config
- wazuh-dashboard-custom:/usr/share/wazuh-dashboard/plugins/wazuh/public/assets/custom
depends_on:
- wazuh.indexer
links:
- wazuh.indexer:wazuh.indexer
- wazuh.manager:wazuh.manager
networks:
- poc-network
# ============================================
# KONG DATABASE
# ============================================
kong-database:
image: postgres:15-alpine
container_name: kong-database
restart: always
networks:
- poc-network
environment:
POSTGRES_USER: kong
POSTGRES_DB: kong
POSTGRES_PASSWORD: kongpass
ports:
- "5432:5432"
volumes:
- kong-database-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD", "pg_isready", "-U", "kong"]
interval: 10s
timeout: 5s
retries: 5
# ============================================
# KONG MIGRATIONS
# ============================================
kong-migrations:
image: kong:3.5
container_name: kong-migrations
command: kong migrations bootstrap
networks:
- poc-network
environment:
KONG_DATABASE: postgres
KONG_PG_HOST: kong-database
KONG_PG_USER: kong
KONG_PG_PASSWORD: kongpass
KONG_PG_DATABASE: kong
depends_on:
kong-database:
condition: service_healthy
restart: on-failure
# ============================================
# KONG API GATEWAY
# ============================================
kong:
image: kong:3.5
container_name: kong
restart: unless-stopped
networks:
- poc-network
environment:
KONG_DATABASE: postgres
KONG_PG_HOST: kong-database
KONG_PG_USER: kong
KONG_PG_PASSWORD: kongpass
KONG_PG_DATABASE: kong
KONG_PROXY_ACCESS_LOG: /dev/stdout
KONG_ADMIN_ACCESS_LOG: /dev/stdout
KONG_PROXY_ERROR_LOG: /dev/stderr
KONG_ADMIN_ERROR_LOG: /dev/stderr
KONG_ADMIN_LISTEN: 0.0.0.0:8001
KONG_ADMIN_GUI_LISTEN: 0.0.0.0:8002
KONG_PROXY_LISTEN: 0.0.0.0:8000, 0.0.0.0:8443 ssl
ports:
- "8000:8000"
- "8443:8443"
- "8001:8001"
- "8002:8002"
depends_on:
kong-database:
condition: service_healthy
kong-migrations:
condition: service_completed_successfully
healthcheck:
test: ["CMD", "kong", "health"]
interval: 10s
timeout: 10s
retries: 10
# ============================================
# KONGA DATABASE
# ============================================
konga-database:
image: postgres:9.6-alpine
container_name: konga-database
restart: always
networks:
- poc-network
environment:
POSTGRES_USER: konga
POSTGRES_DB: konga
POSTGRES_PASSWORD: kongapass
ports:
- "5433:5432"
volumes:
- konga-database-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD", "pg_isready", "-U", "konga"]
interval: 10s
timeout: 5s
retries: 5
# ============================================
# KONGA PREPARE
# ============================================
konga-prepare:
image: pantsel/konga:latest
container_name: konga-prepare
command: "-c prepare -a postgres -u postgresql://konga:kongapass@konga-database:5432/konga"
networks:
- poc-network
environment:
DB_ADAPTER: postgres
DB_HOST: konga-database
DB_USER: konga
DB_PASSWORD: kongapass
DB_DATABASE: konga
depends_on:
konga-database:
condition: service_healthy
restart: on-failure
# ============================================
# KONGA GUI
# ============================================
konga:
image: pantsel/konga:latest
container_name: konga
restart: always
networks:
- poc-network
environment:
DB_ADAPTER: postgres
DB_HOST: konga-database
DB_PORT: 5432
DB_USER: konga
DB_PASSWORD: kongapass
DB_DATABASE: konga
NODE_ENV: production
KONGA_HOOK_TIMEOUT: 120000
DB_PG_SCHEMA: public
TOKEN_SECRET: change-this-secret-token
ports:
- "1337:1337"
depends_on:
konga-database:
condition: service_healthy
konga-prepare:
condition: service_completed_successfully
kong:
condition: service_healthy
# ============================================
# BANKING API
# ============================================
banking-api:
image: safernandez666/banking-api
container_name: banking-api
restart: always
networks:
- poc-network
ports:
- "3000:3000"
volumes:
- banking-data:/app
# ============================================
# LOGSPOUT - LOG FORWARDER
# ============================================
logspout:
image: gliderlabs/logspout:latest
container_name: logspout
restart: always
networks:
- poc-network
volumes:
- /var/run/docker.sock:/var/run/docker.sock
command: syslog://wazuh.manager:514
environment:
- SYSLOG_FORMAT=rfc3164
- LOGSPOUT=ignore
- FILTER_NAME=kong|banking-api # ← AGREGAR: Solo Kong y Banking API
depends_on:
- wazuh.manager
# ============================================
# N8N
# ============================================
n8n:
image: n8nio/n8n:latest
container_name: n8n
restart: unless-stopped
ports:
- "5678:5678"
environment:
- N8N_BASIC_AUTH_ACTIVE=true
- N8N_BASIC_AUTH_USER=admin
- N8N_BASIC_AUTH_PASSWORD=n8n_password
- N8N_HOST=0.0.0.0
- N8N_PORT=5678
- N8N_PROTOCOL=http
- WEBHOOK_URL=http://n8n:5678/
- GENERIC_TIMEZONE=America/Argentina/Buenos_Aires
volumes:
- n8n_data:/home/node/.n8n
networks:
- poc-network
# ============================================
# OLLAMA
# ============================================
ollama:
image: ollama/ollama:latest
container_name: ollama
ports:
- "11435:11434" # Expose Ollama's API port
volumes:
- ollama_data:/root/.ollama # Persistent storage for models and data
restart: unless-stopped
networks:
- poc-network
# ============================================
# NETWORKS
# ============================================
networks:
poc-network:
driver: bridge
# ============================================
# VOLUMES
# ============================================
volumes:
wazuh_api_configuration:
wazuh_etc:
wazuh_logs:
wazuh_queue:
wazuh_var_multigroups:
wazuh_integrations:
wazuh_active_response:
wazuh_agentless:
wazuh_wodles:
filebeat_etc:
filebeat_var:
wazuh-indexer-data:
wazuh-dashboard-config:
wazuh-dashboard-custom:
kong-database-data:
konga-database-data:
banking-data:
n8n_data:
ollama_data:
Importante edistar ./config/wazuh_cluster/wazuh_manager.conf, para que lo tome Wazuh Manager como su ossec.conf. Le agregamos esto:
<!-- ============================================ -->
<!-- Configuración de receptor remoto (Syslog) -->
<!-- ============================================ -->
<remote>
<connection>syslog</connection>
<port>514</port>
<protocol>udp</protocol>
<allowed-ips>any</allowed-ips>
</remote>
<!-- ============================================ -->
<!-- INTEGRACIÓN CON N8N - WEBHOOKS PARA KONG -->
<!-- ============================================ -->
<!-- Webhook específico para ATAQUES (nivel 8+) -->
<integration>
<name>custom-n8n</name>
<level>8</level>
<group>kong,attack</group>
<alert_format>json</alert_format>
</integration>
También vamos agregar la integración custom-n8n en ./config/wazuh_cluster/.
#!/bin/bash
# Wazuh to n8n Integration
N8N_WEBHOOK_URL="http://n8n:5678/webhook/wazuh-kong-alerts"
LOG_FILE="/var/ossec/logs/integrations.log"
# Wazuh pasa el archivo de alerta como primer argumento
ALERT_FILE="$1"
# Timestamp
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
# Log
echo "[${TIMESTAMP}] Processing alert from file: ${ALERT_FILE}" >> ${LOG_FILE}
# Leer el contenido del archivo
if [ -f "${ALERT_FILE}" ]; then
ALERT_JSON=$(cat "${ALERT_FILE}")
# Enviar a n8n
HTTP_CODE=$(curl -X POST "${N8N_WEBHOOK_URL}" \
-H "Content-Type: application/json" \
-d "${ALERT_JSON}" \
-w "%{http_code}" \
-s \
-o /dev/null \
--connect-timeout 10 \
--max-time 30)
if [ "${HTTP_CODE}" == "200" ] || [ "${HTTP_CODE}" == "201" ]; then
echo "[${TIMESTAMP}] SUCCESS - HTTP ${HTTP_CODE}" >> ${LOG_FILE}
exit 0
else
echo "[${TIMESTAMP}] FAILED - HTTP ${HTTP_CODE}" >> ${LOG_FILE}
exit 1
fi
else
echo "[${TIMESTAMP}] ERROR - Alert file not found: ${ALERT_FILE}" >> ${LOG_FILE}
exit 1
fi
Es muy importante que a custom-n8n le hagan un chmod 555, para que pueda ser ejecutado por cualquiera. Esto en local, antes de levantar el contenedor.
Agregamos el docoder y las regla, también en /config/wazuh_cluster. El decoder se llamara 0374-kong-decoder.xml y las regla kong-rules.xml.
<!--
- Kong API Manager custom decoder
- Created for extracting srcip from Kong logs
- Author: Santiago Fernandez
- Date: October 2025
-
- This decoder extracts:
- - srcip: Source IP address
- - protocol: HTTP method (GET, POST, etc.)
- - url: Requested URL
- - id: HTTP status code
-->
<decoder name="kong-decoder">
<prematch>^\S+ \S+ kong[\d+]:</prematch>
<regex>^\S+ \S+ kong[\d+]: (\S+) \S+ \S+ [\S+ \S+] "(\w+) (\S+) HTTP\S+" (\d+) \d+ \S+ \S+</regex>
<order>srcip, protocol, url, id</order>
</decoder>
<!--
- Kong API Gateway Rules
- Author: Santiago Fernandez
- Date: October 2025
-
- Rule ID Range: 100100 - 100199
-->
<group name="kong,">
<!-- ============================================ -->
<!-- REGLA BASE - Cualquier tráfico de Kong -->
<!-- ============================================ -->
<rule id="100100" level="3">
<decoded_as>kong-decoder</decoded_as>
<description>Kong: API Gateway traffic detected</description>
<group>kong,access</group>
</rule>
<!-- ============================================ -->
<!-- REGLAS PARA BANKING API -->
<!-- ============================================ -->
<!-- Accesos exitosos (2xx) a banking -->
<rule id="100101" level="5">
<if_sid>100100</if_sid>
<url>/banking/</url>
<id>^2\d\d$</id>
<description>Kong: Successful access to banking API - $(protocol) $(url) - Status: $(id) from $(srcip)</description>
<group>kong,banking,success</group>
</rule>
<!-- Errores del cliente (4xx) en banking -->
<rule id="100102" level="7">
<if_sid>100100</if_sid>
<url>/banking/</url>
<id>^4\d\d$</id>
<description>Kong: Client error on banking API - $(protocol) $(url) - Status: $(id) from $(srcip)</description>
<group>kong,banking,error,client_error</group>
</rule>
<!-- Errores del servidor (5xx) en banking -->
<rule id="100103" level="10">
<if_sid>100100</if_sid>
<url>/banking/</url>
<id>^5\d\d$</id>
<description>Kong: Server error on banking API - $(protocol) $(url) - Status: $(id)</description>
<group>kong,banking,critical,server_error</group>
</rule>
<!-- ============================================ -->
<!-- REGLAS DE CORRELACIÓN - Detección de ataques -->
<!-- ============================================ -->
<!-- Múltiples errores 4xx desde la misma IP (posible escaneo) -->
<rule id="100104" level="8" frequency="5" timeframe="60">
<if_matched_sid>100102</if_matched_sid>
<same_source_ip />
<description>Kong: Multiple failed requests ($(id)) from $(srcip) to banking API - Possible scanning or brute force attempt</description>
<group>kong,banking,attack,multiple_errors,scanning</group>
</rule>
<!-- Múltiples errores 5xx (problema en el servidor) -->
<rule id="100105" level="9" frequency="3" timeframe="120">
<if_matched_sid>100103</if_matched_sid>
<description>Kong: Multiple server errors on banking API - Service may be down or experiencing issues</description>
<group>kong,banking,critical,service_degradation</group>
</rule>
<!-- ============================================ -->
<!-- ENDPOINTS SENSIBLES -->
<!-- ============================================ -->
<!-- Acceso a endpoints de cuentas -->
<rule id="100106" level="6">
<if_sid>100101</if_sid>
<url>/banking/cuentas</url>
<description>Kong: Access to accounts endpoint - $(protocol) $(url) from $(srcip)</description>
<group>kong,banking,sensitive,accounts</group>
</rule>
<!-- Acceso a endpoints de transacciones -->
<rule id="100107" level="6">
<if_sid>100101</if_sid>
<url>/banking/transacciones</url>
<description>Kong: Access to transactions endpoint - $(protocol) $(url) from $(srcip)</description>
<group>kong,banking,sensitive,transactions</group>
</rule>
<!-- Acceso a endpoints de transferencias -->
<rule id="100108" level="7">
<if_sid>100101</if_sid>
<url>/banking/transferencias</url>
<description>Kong: Access to money transfer endpoint - $(protocol) $(url) from $(srcip)</description>
<group>kong,banking,sensitive,transfers,high_risk</group>
</rule>
<!-- ============================================ -->
<!-- MÉTODOS HTTP ESPECÍFICOS -->
<!-- ============================================ -->
<!-- Peticiones DELETE en banking (alta sensibilidad) -->
<rule id="100110" level="8">
<if_sid>100100</if_sid>
<url>/banking/</url>
<protocol>DELETE</protocol>
<description>Kong: DELETE request on banking API - $(url) from $(srcip)</description>
<group>kong,banking,modification,delete,high_risk</group>
</rule>
<!-- Peticiones PUT/PATCH en banking -->
<rule id="100111" level="6">
<if_sid>100100</if_sid>
<url>/banking/</url>
<protocol>PUT|PATCH</protocol>
<description>Kong: Modification request on banking API - $(protocol) $(url) from $(srcip)</description>
<group>kong,banking,modification</group>
</rule>
<!-- Peticiones POST en banking -->
<rule id="100112" level="5">
<if_sid>100100</if_sid>
<url>/banking/</url>
<protocol>POST</protocol>
<id>^2\d\d$</id>
<description>Kong: POST request on banking API - $(url) from $(srcip)</description>
<group>kong,banking,creation</group>
</rule>
<!-- ============================================ -->
<!-- CÓDIGOS DE ESTADO ESPECÍFICOS -->
<!-- ============================================ -->
<!-- 401 - No autorizado -->
<rule id="100120" level="7">
<if_sid>100100</if_sid>
<url>/banking/</url>
<id>^401$</id>
<description>Kong: Unauthorized access attempt to banking API - $(protocol) $(url) from $(srcip)</description>
<group>kong,banking,authentication,unauthorized</group>
</rule>
<!-- Múltiples 401 desde la misma IP -->
<rule id="100121" level="9" frequency="3" timeframe="60">
<if_matched_sid>100120</if_matched_sid>
<same_source_ip />
<description>Kong: Multiple unauthorized access attempts from $(srcip) - Possible credential stuffing attack</description>
<group>kong,banking,attack,authentication,credential_stuffing</group>
</rule>
<!-- 403 - Prohibido -->
<rule id="100122" level="7">
<if_sid>100100</if_sid>
<url>/banking/</url>
<id>^403$</id>
<description>Kong: Forbidden access attempt to banking API - $(protocol) $(url) from $(srcip)</description>
<group>kong,banking,authorization,forbidden</group>
</rule>
<!-- 404 - No encontrado -->
<rule id="100123" level="5">
<if_sid>100100</if_sid>
<url>/banking/</url>
<id>^404$</id>
<description>Kong: Resource not found on banking API - $(protocol) $(url) from $(srcip)</description>
<group>kong,banking,not_found</group>
</rule>
<!-- Múltiples 404 desde la misma IP (posible escaneo de endpoints) -->
<rule id="100124" level="8" frequency="10" timeframe="120">
<if_matched_sid>100123</if_matched_sid>
<same_source_ip />
<description>Kong: Multiple 404 errors from $(srcip) - Possible endpoint enumeration attack</description>
<group>kong,banking,attack,enumeration</group>
</rule>
<!-- 429 - Too Many Requests (Rate Limiting) -->
<rule id="100125" level="6">
<if_sid>100100</if_sid>
<url>/banking/</url>
<id>^429$</id>
<description>Kong: Rate limit exceeded on banking API from $(srcip)</description>
<group>kong,banking,rate_limit,abuse</group>
</rule>
<!-- ============================================ -->
<!-- TRÁFICO NO BANKING (Otros endpoints) -->
<!-- ============================================ -->
<!-- Accesos exitosos a otros endpoints -->
<rule id="100130" level="3">
<if_sid>100100</if_sid>
<id>^2\d\d$</id>
<description>Kong: Successful request - $(protocol) $(url) from $(srcip)</description>
<group>kong,success</group>
</rule>
<!-- Errores en otros endpoints -->
<rule id="100131" level="5">
<if_sid>100100</if_sid>
<id>^4\d\d$</id>
<description>Kong: Client error - $(protocol) $(url) - Status: $(id) from $(srcip)</description>
<group>kong,error</group>
</rule>
</group>
Listo! Ya estamos para ejecutar.
docker-compose up -d
Vamos a pegarle una mirada a los contenedores.

Para que tengamos una idea de los puertos y contenedores, te los paso en limpio aquí.

Banking API
Es una API generada para este Prueba de Concepto con información ficticia. Pueden encontrar el código en el repositorio, pero a grandes rasgos nos data esta información:
Gestiona clientes (nombre, email, teléfono, fecha de registro).
Gestiona cuentas vinculadas a clientes (número, tipo, saldo, moneda).
Gestiona tarjetas de crédito asociadas a cuentas (número, límite, saldo usado, vencimiento). En las respuestas públicas el CVV se oculta.
Registra transacciones (depósitos, retiros, transferencias, compras).
Provee un resumen por cliente que agrega cuentas y tarjetas (totales de saldos y crédito disponible).
Incluye endpoints de salud y la documentación.
Kong
Voy a proporcionarles los comandos para que nuestro API Manager consuma la Banking API. Vamos paso a paso: primero, debemos crear un "Service" en Kong que represente tu API backend.
curl -i -X POST http://localhost:8001/services/ \
--data "name=banking-api" \
--data "url=http://banking-api:3000"
Creamos un "Route" que define cómo los clientes accederán a tu servicio. Vincula la ruta al servicio creado anteriormente.
curl -i -X POST http://localhost:8001/services/banking-api/routes \
--data "name=banking-route" \
--data "paths[]=/banking" \
--data "strip_path=true"
Habilitamos CORS (Cross-Origin Resource Sharing) para permitir peticiones desde navegadores. Aca lo voy a crear de una forma permisiva.
curl -i -X POST http://localhost:8001/services/banking-api/plugins \
--data "name=cors" \
--data "config.origins=*" \
--data "config.methods[]=GET" \
--data "config.methods[]=HEAD" \
--data "config.methods[]=PUT" \
--data "config.methods[]=PATCH" \
--data "config.methods[]=POST" \
--data "config.methods[]=DELETE" \
--data "config.methods[]=OPTIONS" \
--data "config.headers[]=*" \
--data "config.exposed_headers[]=*" \
--data "config.credentials=true" \
--data "config.max_age=3600"
Como saben, Kong es un API Manager. Podríamos habilitar varios plugins, pero para la PoC no son necesarios. Podrías habilitar Rate Limiting, Request Size Limiting, Correlation ID o Request Transformer. Vamos a probarlo.
# Vamos a ver los clientes
curl http://localhost:8000/banking/clientes | jq
# Cliente con ID 1
curl http://localhost:8000/banking/clientes/1 | jq

Konga
Todo lo que hicimos con curl, podemos hacerlo a través de la interfaz gráfica. Primero, vamos a crear nuestra cuenta en Konga y luego agregar la conexión para gestionar Kong.

Ahí se ve todo lo creado, anteriormente. Por ejemplo el servicio.

o la ruta.

Wazuh
Si todo salió bien, ingresamos a Wazuh para ver nuestras consultas. Para ver las reglas de Kong, aplique un filtro decoder.name: kong-decoder

N8N
Ya levantado el contenedor ingresamos a http://localhost:5678. Ahí armaremos dos workflows, uno para el análisis y otro para que los administradores puedan liberar la ip bloqueada.

Una vez que suframos el ataque, habrá lógica para decidir si debemos bloquear o no. Esto es una prueba, pero imagino consultas de diferentes API, Slack o servicios internos. Una vez que se ejecute el Workflow Block IP, deberíamos recibir un correo como este:

Al final del correo, podemos invocar el Workflow Release IP para liberar la dirección del atacante.
Simulacion de Ataque
Les dejo un script para simular un ataque rápidamente.
#!/bin/bash
# quick-test.sh - Prueba rpida
echo " Generando alertas de prueba..."
# Trfico normal
curl -s http://localhost:8000/banking/cuentas
# Mltiples 404 (activar regla de correlacin)
for i in {1..12}; do
curl -s http://localhost:8000/banking/fake-endpoint-$i
sleep 0.5
done
# Mltiples 401 (credential stuffing)
for i in {1..5}; do
curl -s http://localhost:8000/banking/cuentas -H "Authorization: Bearer fake_$i"
sleep 1
done
# DELETE peligroso
curl -s -X DELETE http://localhost:8000/banking/cuentas/123
echo " Alertas generadas. Revisa n8n y Wazuh!"
Espero que les sirva y puedan usarlo en sus empresas, si necesitan una mano me avisan.
Saludos, Santi.
Bonus Track
Dejo los Worflows de N8N para analizar con Ollama. Código.




Comandos Útiles
# 1. Reiniciar Wazuh Manager
docker-compose restart single-node-wazuh.manager-1
# 2. Verificar que está escuchando en el puerto 514
docker exec single-node-wazuh.manager-1 netstat -tlnp | grep 514
# 3. Revisar ossec.conf
docker exec single-node-wazuh.manager-1 cat /var/ossec/etc/ossec.conf
# 4. Ver logs de Integraciones
docker exec single-node-wazuh.manager-1 tail -f /var/ossec/logs/integrations.log
# 5. Ver logs de Alarmas de Kong
docker exec -it single-node-wazuh.manager-1 tail -f /var/ossec/logs/alerts/alerts.log | grep -A 10 "kong"
# 6. Ver logs de Wazuh Manager
docker logs -f single-node-wazuh.indexer-1
Referencias
https://ipv6.rs/tutorial/Ubuntu_Server_Latest/Kong/
https://documentation.wazuh.com/current/deployment-options/docker/wazuh-container.html




