DataSkills Hub

Kong Gateway

Kong Gateway es un API Gateway open-source nativo en la nube. Gestiona enrutamiento, autenticación, rate limiting y observabilidad de servicios internos (FastAPI, Trino REST, PostgreSQL, Airflow). Conecta directamente con los clientes y protege los microservicios backend.

#Getting Started

#Arquitectura Kong

Kong corre en contenedor Docker:

Clientes externos / Internos
         ↓
    Kong Gateway (proxy)
         ↓
    ┌───────┬───────┬────────┐
    ↓       ↓       ↓        ↓
  FastAPI  Trino  PostgreSQL Airflow
  (Data)   (SQL)  (Ops)      (Orch)

#URLs de Kong

Componente URL Puerto
Kong Proxy
Admin API
Metrics/Status /status

#Verificar que Kong funciona

# Health check desde cliente
curl -i <tu-url>/status

# Debería retornar JSON con DB connection status
# {
#   "database": {"reachable": true},
#   "server": {...}
# }

#Servicios y Rutas

#Registrar un nuevo Servicio

Un Servicio en Kong apunta al backend real (ej: FastAPI app en <tu-url>)

# Crear servicio
curl -X POST <tu-url>/services \
  -H "Content-Type: application/json" \
  -d '{
    "name": "data-api",
    "url": "<tu-url>",
    "port": "<puerto>",
    "protocol": "http",
    "host": "<tu-url>"
  }'

# Respuesta: devuelve ID del servicio
# {
#   "id": "abc-123-def",
#   "name": "data-api",
#   ...
# }

#Registrar una Ruta (Route)

Una Ruta define cómo llega la solicitud externa a Kong y a qué Servicio redirige.

# Crear ruta: /api/data/* → servicio data-api
curl -X POST <tu-url>/services/data-api/routes \
  -H "Content-Type: application/json" \
  -d '{
    "name": "data-api-route",
    "paths": ["/api/data"],
    "methods": ["GET", "POST", "PUT", "DELETE"],
    "strip_path": true,
    "preserve_host": false
  }'

# Resultado:
# Cliente →  <tu-url>/api/data/tables
#            ↓ (Kong redirige eliminando /api/data)
#            <tu-url>/tables

Opciones importantes:

Opción Descripción
paths Rutas que Kong escucha (ej: /api/data, /tables)
methods HTTP methods permitidos (GET, POST, etc.)
strip_path Si true, elimina el path de Kong en redireccion
preserve_host Si true, mantiene header Host original

#Plugins de Seguridad

#Plugin: Key Authentication

Requerir API Key para acceder a una ruta:

# 1. Crear Consumer (usuario/app que accede)
curl -X POST <tu-url>/consumers \
  -d "username=analytics-app"

# 2. Agregar credencial (API Key)
curl -X POST <tu-url>/consumers/analytics-app/key-auth \
  -d "key=super-secret-key-12345"

# 3. Activar plugin en la ruta
curl -X POST <tu-url>/routes/data-api-route/plugins \
  -H "Content-Type: application/json" \
  -d '{"name": "key-auth"}'

# Cliente ahora debe enviar:
curl -H "apikey: super-secret-key-12345" <tu-url>/api/data/tables

#Plugin: CORS (Cross-Origin Resource Sharing)

Permitir requests desde dominios externos (Superset, dashboards):

curl -X POST <tu-url>/routes/data-api-route/plugins \
  -H "Content-Type: application/json" \
  -d '{
    "name": "cors",
    "config": {
      "origins": ["<tu-url>", "<tu-url>"],
      "methods": ["GET", "POST", "OPTIONS"],
      "allow_headers": ["Content-Type", "Authorization"],
      "credentials": true
    }
  }'

#Plugin: Rate Limiting

Limitar requests por segundo/minuto:

curl -X POST <tu-url>/routes/data-api-route/plugins \
  -H "Content-Type: application/json" \
  -d '{
    "name": "rate-limiting",
    "config": {
      "second": 100,
      "minute": 10000,
      "policy": "local"
    }
  }'

# Resultado:
# analytics-app está limitado a 100 req/seg y 10000 req/min
# Si excede → retorna HTTP 429 Too Many Requests

#Plugins Operativos

#Plugin: Request/Response Transformer

Modificar headers o body de requests/responses:

# Agregar header personalizado a todas las respuestas
curl -X POST <tu-url>/routes/data-api-route/plugins \
  -H "Content-Type: application/json" \
  -d '{
    "name": "response-transformer",
    "config": {
      "add": {
        "headers": ["X-API-Version:1.0", "X-Powered-By:Kong"]
      }
    }
  }'

# O modificar body antes de enviar al backend
curl -X POST <tu-url>/routes/data-api-route/plugins \
  -H "Content-Type: application/json" \
  -d '{
    "name": "request-transformer",
    "config": {
      "add": {
        "headers": ["X-Request-ID:<valor-generado>"]
      }
    }
  }'

#Plugin: Logging

Registrar todas las requests/responses:

curl -X POST <tu-url>/routes/data-api-route/plugins \
  -H "Content-Type: application/json" \
  -d '{
    "name": "file-log",
    "config": {
      "path": "/var/log/kong/api-data.log"
    }
  }'

# Ver logs
docker logs dataskills-hub 2>&1 | grep "api-data.log"

Alternativa: usar HTTP Log para enviar logs a servidor externo:

curl -X POST <tu-url>/routes/data-api-route/plugins \
  -H "Content-Type: application/json" \
  -d '{
    "name": "http-log",
    "config": {
      "http_endpoint": "<tu-url>/logs"
    }
  }'

#Gestión de Consumers

#Crear y administrar Consumers

# Listar todos los consumers
curl <tu-url>/consumers

# Crear consumer (aplicación o usuario)
curl -X POST <tu-url>/consumers \
  -d "username=fastapi-processor" \
  -d "custom_id=app-001"

# Ver credentials de un consumer
curl <tu-url>/consumers/fastapi-processor

# Eliminar consumer
curl -X DELETE <tu-url>/consumers/fastapi-processor

#Asignar múltiples credenciales

Un Consumer puede tener varias formas de autenticarse:

# Key Auth (API Key)
curl -X POST <tu-url>/consumers/fastapi-processor/key-auth \
  -d "key=key-12345"

# Basic Auth (usuario:contraseña en base64)
curl -X POST <tu-url>/consumers/fastapi-processor/basic-auth \
  -d "username=fastapi" \
  -d "password=secure-password"

# OAuth2
curl -X POST <tu-url>/consumers/fastapi-processor/oauth2 \
  -d "client_id=oauth-app-1" \
  -d "client_secret=secret-123" \
  -d "redirect_uris=<tu-url>/callback"

#Monitoreo y Troubleshooting

#Ver estado de Kong

# Health status detallado
curl <tu-url>/status | jq .

# Resultado típico:
# {
#   "database": {"reachable": true},
#   "server": {"connections_accepted": 1250, ...}
# }

#Listar todas las rutas y plugins activos

# Servicios
curl <tu-url>/services | jq '.data[] | {name, url}'

# Rutas
curl <tu-url>/routes | jq '.data[] | {name, paths, methods}'

# Plugins
curl <tu-url>/plugins | jq '.data[] | {name, service_id}'

#Debugging de requests

Habilitar logging detallado para diagnosticar:

# Agregar verbose logging a toda ruta
curl -X POST <tu-url>/services/data-api/plugins \
  -H "Content-Type: application/json" \
  -d '{
    "name": "request-size-limiting",
    "config": {
      "allowed_payload_size": 128  # 128 MB max
    }
  }'

# Test de ruta con verbose
curl -v -H "apikey: super-secret-key-12345" <tu-url>/api/data/tables

#Errores comunes

Código Significado Solución
404 Ruta no encontrada Verificar paths en route config
401 No autorizado Revisar credenciales/plugin auth
429 Rate limit excedido Esperar o aumentar límite
502 Backend no responde Verificar servicio backend online
503 Kong sin conexión a DB Revisar Docker / conectividad

#Mejores Prácticas

#Convenciones de rutas y servicios

Componente Patrón Ejemplo
Nombre Servicio <app>-<función>-api data-processor-api
Ruta externa /api/<v>/< recurso> /api/v1/tables
Consumer name <nombre-app> analytics-consumer
Plugin scope Aplicar a nivel ruta/svc Específico, no global

#Política de rate limiting

Recomendaciones por tipo de consumer:

Tipo req/seg req/min Caso de uso
Internal API 1000 500000 Apps de plataforma
Data Extract 100 10000 Superset, dashboards
Public API 10 1000 Clientes externos
Development 50 5000 Apps en desarrollo

#Seguridad: API Keys

Buenas prácticas:

✓ Usar Key Auth para servicios internos (FastAPI, Trino)
✓ Rotar keys cada 90 días
✓ Almacenar keys en .env del cliente, NO en código
✓ Usar diferentes keys por entorno (dev, staging, prod)
✓ Revocar keys cuando app o persona se desactiva

Ejemplo en FastAPI cliente:

# .env
KONG_API_KEY=sk-data-12345-abc

# main.py
import os
from httpx import Client

client = Client(
    base_url="<tu-url>",
    headers={"apikey": os.getenv("KONG_API_KEY")}
)
response = client.get("/api/v1/tables")

#Also see