Saltar a contenido

C4 — Contenedores

El nivel de contenedores muestra los procesos ejecutables y los almacenes de datos que componen el sistema. Cada contenedor es un proceso desplegable de forma independiente; en el MVP todos corren como contenedores Docker en un mismo VPS.

Diagrama de contenedores

flowchart TD
    Browser([Navegador\nHTML / JS])
    M2M([Servicio M2M\nJava / Python / etc.])

    subgraph VPS["VPS Ubuntu — Docker Compose"]
        subgraph frontend["Red Docker: frontend"]
            T["Traefik v3\nHTTPS :443 · HTTP :80\nReverse proxy + TLS"]
            K["Keycloak 26\nHTTP :8080 (interno)\nIAM / OAuth2 / OIDC"]
            W["Spring WebFlux\nHTTP :8081 (interno)\nResource Server"]
        end
        subgraph data["Red Docker: data"]
            K
            PG["PostgreSQL 16\nTCP :5432 (interno)\nPersistencia de Keycloak"]
        end
    end

    Browser -->|HTTPS 443| T
    M2M -->|HTTPS 443| T
    T -->|HTTP interno| K
    T -->|HTTP interno| W
    K -->|TCP 5432 SQL| PG
    W -. "GET /.well-known/jwks.json (caché 5 min)" .-> K

Tabla de contenedores

Contenedor Imagen Red(es) Puerto externo Responsabilidad
Traefik traefik:v3 frontend 80, 443 TLS termination, routing por Host, rate limiting, security headers
Keycloak quay.io/keycloak/keycloak:26 frontend + data — (solo interno) IAM: autenticación, autorización, emisión de JWT, gestión de realms
PostgreSQL postgres:16-alpine data — (solo interno) Persistencia de todos los datos de Keycloak: usuarios, sesiones, claves, realms
Spring WebFlux Imagen propia frontend — (solo interno) Resource Server: valida JWT, expone APIs de negocio protegidas

Comunicaciones entre contenedores

Origen Destino Protocolo Propósito
Traefik Keycloak HTTP (interno Docker) Proxy de requests de autenticación y API admin
Traefik Spring WebFlux HTTP (interno Docker) Proxy de requests a las APIs de negocio
Keycloak PostgreSQL TCP / SQL Lectura y escritura de datos de identidad
Spring WebFlux Keycloak HTTP (JWKS endpoint) Descarga y refresco de claves públicas para validar JWT

Sin comunicación directa entre aplicaciones

Spring WebFlux nunca llama directamente a Keycloak para validar tokens. La validación es local usando la clave pública descargada del JWKS endpoint. Esto elimina latencia y dependencia en tiempo real con Keycloak para cada request.

Variables de entorno clave

# compose.yml (fragmento)
keycloak:
  environment:
    KC_DB: postgres
    KC_DB_URL: jdbc:postgresql://postgres:5432/keycloak
    KC_DB_USERNAME: ${KC_DB_USER}
    KC_DB_PASSWORD: ${KC_DB_PASSWORD}
    KC_HOSTNAME: ${KC_HOSTNAME}
    KC_PROXY: edge
    KC_HTTP_ENABLED: "true"
    KEYCLOAK_ADMIN: ${KC_ADMIN}
    KEYCLOAK_ADMIN_PASSWORD: ${KC_ADMIN_PASSWORD}

spring-webflux-app:
  environment:
    SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_ISSUER_URI: >
      https://${KC_HOSTNAME}/realms/realm-internal

Flujo completo de autenticación

sequenceDiagram
    actor B as Navegador
    participant T as Traefik
    participant K as Keycloak
    participant W as Spring WebFlux
    participant PG as PostgreSQL

    B->>T: GET /app (sin sesión)
    T->>B: 302 Redirect → Keycloak /auth
    B->>T: GET /realms/realm-internal/protocol/openid-connect/auth?...
    T->>K: Proxy
    K->>B: Mostrar formulario de login
    B->>K: POST credenciales + code_verifier
    K->>PG: Verificar usuario y credenciales
    PG-->>K: Usuario válido
    K->>B: 302 Redirect con authorization_code
    B->>K: POST /token (code + code_verifier)
    K-->>B: access_token + id_token + refresh_token
    B->>T: GET /api/resource Bearer: access_token
    T->>W: Proxy (token en header)
    W->>K: GET /jwks (cacheado)
    K-->>W: Claves públicas RSA
    W->>W: Verificar firma + claims
    W-->>B: 200 OK + datos