Saltar a contenido

C4 Component — Traefik

Traefik v3 actúa como el único punto de entrada al sistema: termina TLS, aplica políticas de seguridad perimetrales y enruta el tráfico hacia Keycloak o los microservicios Spring WebFlux. Este documento descompone los componentes internos de Traefik y sus configuraciones relevantes para el MVP en VPS con Docker Compose.

Diagrama de componentes internos

flowchart TB
    Internet((Internet\n:80 / :443)) --> EP

    subgraph Traefik["Traefik v3 — Edge Proxy"]
        EP["EntryPoints\n────────────────\n• web → :80\n• websecure → :443"]

        CM["Certificate Manager\n────────────────\n• ACME / Let's Encrypt\n• TLS Challenge\n• Almacén local (acme.json)\n• Auto-renovación"]

        Router_KC["Router: keycloak\n────────────────\n• Host: auth.ejemplo.com\n• EntryPoint: websecure\n• TLS: certResolver=letsencrypt\n• Middleware: secure-headers"]

        Router_API["Router: api-service\n────────────────\n• Host: api.ejemplo.com\n• PathPrefix: /api\n• EntryPoint: websecure\n• TLS: certResolver=letsencrypt\n• Middleware: secure-headers, rate-limit"]

        Router_HTTP["Router: http-redirect\n────────────────\n• EntryPoint: web\n• Middleware: https-redirect"]

        MW_Headers["Middleware: secure-headers\n────────────────\n• Strict-Transport-Security\n• X-Frame-Options: DENY\n• X-Content-Type-Options\n• Referrer-Policy\n• Content-Security-Policy"]

        MW_Rate["Middleware: rate-limit\n────────────────\n• average: 100 req/s\n• burst: 50\n• sourceCriterion: ipStrategy"]

        MW_Redirect["Middleware: https-redirect\n────────────────\n• redirectScheme: https\n• permanent: true"]

        Svc_KC["Service: keycloak\n────────────────\n• URL: http://keycloak:8080\n• healthCheck: /health/ready\n• passHostHeader: true"]

        Svc_API["Service: api-service\n────────────────\n• URL: http://webflux-api:8080\n• healthCheck: /actuator/health\n• passHostHeader: true"]

        EP --> Router_KC
        EP --> Router_API
        EP --> Router_HTTP
        Router_HTTP --> MW_Redirect
        Router_KC --> MW_Headers --> Svc_KC
        Router_API --> MW_Headers
        MW_Headers --> MW_Rate --> Svc_API
        CM --> Router_KC
        CM --> Router_API
    end

    Svc_KC -->|HTTP| Keycloak[Keycloak\n:8080]
    Svc_API -->|HTTP| WebFlux[Spring WebFlux\n:8080]

EntryPoints

Los EntryPoints son los puntos de escucha de Traefik. Todo el tráfico externo entra por aquí antes de ser procesado.

# traefik.yml (configuración estática)
entryPoints:
  web:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: websecure
          scheme: https
          permanent: true

  websecure:
    address: ":443"
    http:
      tls:
        certResolver: letsencrypt

Routers

Los routers evalúan cada petición entrante y la dirigen al servicio correspondiente según reglas declarativas.

# docker-compose labels — Keycloak
labels:
  - "traefik.enable=true"
  - "traefik.http.routers.keycloak.rule=Host(`auth.ejemplo.com`)"
  - "traefik.http.routers.keycloak.entrypoints=websecure"
  - "traefik.http.routers.keycloak.tls.certresolver=letsencrypt"
  - "traefik.http.routers.keycloak.middlewares=secure-headers@file"
  - "traefik.http.services.keycloak.loadbalancer.server.port=8080"

# docker-compose labels — Spring WebFlux API
labels:
  - "traefik.enable=true"
  - "traefik.http.routers.api.rule=Host(`api.ejemplo.com`) && PathPrefix(`/api`)"
  - "traefik.http.routers.api.entrypoints=websecure"
  - "traefik.http.routers.api.tls.certresolver=letsencrypt"
  - "traefik.http.routers.api.middlewares=secure-headers@file,rate-limit@file"
  - "traefik.http.services.api.loadbalancer.server.port=8080"

Middlewares

Los middlewares transforman o filtran las peticiones y respuestas antes de llegar al servicio backend.

# middlewares.yml (configuración dinámica en archivo)
http:
  middlewares:
    secure-headers:
      headers:
        stsSeconds: 31536000
        stsIncludeSubdomains: true
        stsPreload: true
        forceSTSHeader: true
        frameDeny: true
        contentTypeNosniff: true
        referrerPolicy: "strict-origin-when-cross-origin"
        customResponseHeaders:
          X-Powered-By: ""
          Server: ""

    rate-limit:
      rateLimit:
        average: 100
        burst: 50
        sourceCriterion:
          ipStrategy:
            depth: 1

    https-redirect:
      redirectScheme:
        scheme: https
        permanent: true

Certificate Manager (ACME)

Traefik gestiona certificados TLS de Let's Encrypt automáticamente mediante el protocolo ACME.

# traefik.yml — certificatesResolvers
certificatesResolvers:
  letsencrypt:
    acme:
      email: "admin@ejemplo.com"
      storage: "/letsencrypt/acme.json"
      tlsChallenge: {}

Permisos de acme.json

El archivo acme.json debe tener permisos 600. Traefik lo verifica al iniciar y falla si los permisos son incorrectos.

chmod 600 /opt/traefik/letsencrypt/acme.json

Rate limits de Let's Encrypt

El límite es 5 certificados por dominio por semana en producción. Para pruebas, usa el staging endpoint de ACME para evitar bloqueos.

Tabla de configuraciones clave

Componente Parámetro Valor en MVP Impacto
EntryPoint web address :80 Recibe HTTP, redirige a HTTPS
EntryPoint websecure address :443 Recibe todo el tráfico HTTPS
ACME storage storage /letsencrypt/acme.json Persiste certificados entre reinicios
ACME challenge tlsChallenge habilitado No requiere puerto 80 para validación
HSTS stsSeconds 31536000 (1 año) Fuerza HTTPS en navegadores
Rate limit average 100 req/s Protege backend de ataques volumétricos
Rate limit burst 50 Permite picos cortos legítimos
Keycloak passHostHeader true true Keycloak necesita el Host original para construir las URLs de respuesta

Tabla de rutas configuradas

Router Host Path Servicio Middlewares
keycloak auth.ejemplo.com / (todo) keycloak:8080 secure-headers
api api.ejemplo.com /api/* webflux-api:8080 secure-headers, rate-limit
http-redirect * / (todo) https-redirect

Configuración de red Docker

# compose.yml — red interna compartida
networks:
  proxy:
    external: false

services:
  traefik:
    image: traefik:v3.0
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./traefik/traefik.yml:/etc/traefik/traefik.yml:ro
      - ./traefik/middlewares.yml:/etc/traefik/dynamic/middlewares.yml:ro
      - ./letsencrypt:/letsencrypt
    networks:
      - proxy

  keycloak:
    networks:
      - proxy
    # No expone puertos al host — sólo accesible vía Traefik

  webflux-api:
    networks:
      - proxy
    # No expone puertos al host — sólo accesible vía Traefik

Exposición directa de puertos

Los contenedores Keycloak y Spring WebFlux no deben exponer puertos al host (127.0.0.1 o 0.0.0.0). Todo el tráfico debe pasar por Traefik para que los middlewares de seguridad sean efectivos.

Health checks y observabilidad

Traefik expone un API de administración en el puerto 8080 (sólo en red interna) para monitorear el estado de routers y servicios:

# traefik.yml
api:
  dashboard: true
  insecure: false   # Exponer sólo vía router con autenticación en producción

ping:
  entryPoint: "traefik"

log:
  level: INFO
  format: json

accessLog:
  filePath: "/var/log/traefik/access.log"
  format: json
  fields:
    defaultMode: keep
    headers:
      defaultMode: drop
      names:
        Authorization: redact