La gestión de identidad y sesión en sistemas distribuidos, especialmente en entornos de juegos de baja latencia, presenta un desafío fundamental: cómo integrar un proveedor de identidad externo y un sistema de sesión interno sin comprometer la experiencia del usuario o la seguridad. Este problema se agrava cuando los sistemas tienen ciclos de vida de tokens y modelos de autenticación distintos. La solución propuesta aborda esto mediante un patrón de autenticación dual-token, donde un proveedor de identidad gestionado (Amazon Cognito) se encarga de la identidad del jugador, y el servidor de juego (Nakama) gestiona las sesiones de juego. La clave es un mecanismo de intercambio de tokens que valida criptográficamente la identidad y la traduce a una sesión de juego, desacoplando así las responsabilidades y permitiendo que cada sistema opere de forma independiente en tiempo de ejecución.
Históricamente, la autenticación en aplicaciones distribuidas ha evolucionado desde sistemas monolíticos con bases de datos de usuarios internas hasta el uso de protocolos federados como OAuth 2.0 y OpenID Connect (OIDC). La necesidad de separar la identidad de la sesión surge de la complejidad de escalar ambos componentes de manera independiente y de la conveniencia de delegar la seguridad de la identidad a servicios especializados. Este patrón es particularmente relevante en arquitecturas de microservicios o sistemas de juego donde la latencia y la resiliencia son críticas, y donde los servidores de juego a menudo requieren un control granular sobre las sesiones persistentes.
Arquitectura del Sistema
La arquitectura propuesta se compone de cuatro capas principales: autenticación, enrutamiento de borde, balanceo de carga y servidor de juego. Amazon Cognito actúa como el proveedor de identidad, gestionando los User Pools y emitiendo JSON Web Tokens (JWTs) tras la autenticación del cliente mediante el flujo USER_SRP_AUTH, que evita la transmisión de contraseñas. Amazon CloudFront es el punto de entrada HTTPS único, integrando AWS WAF para la inspección de tráfico en el borde. CloudFront dirige el tráfico HTTP API a un Application Load Balancer (ALB) y el tráfico WebSocket a un Network Load Balancer (NLB).
El ALB opera en la Capa 7 (HTTP), aplicando una lista de rutas permitidas explícita y rechazando cualquier solicitud a rutas no listadas con un 403 Forbidden. Esto limita la superficie de ataque. El NLB opera en la Capa 4 (TCP passthrough), reenviando el tráfico WebSocket directamente a Nakama sin inspección HTTP. Nakama se ejecuta en Amazon ECS sobre AWS Fargate. Un hook de Go, implementado como un plugin de Nakama, es el componente central para el intercambio de tokens. Este hook intercepta las solicitudes de autenticación, valida el JWT de Cognito (verificando formato, algoritmo RS256, firma contra JWKS, expiración, emisor y audiencia), extrae el 'sub' claim como el ID de usuario de Nakama, y luego Nakama emite su propio token de sesión. Las claves JWKS se cachean con un TTL de 1 hora y protección contra 'thundering herd'.
La seguridad se refuerza con grupos de seguridad que restringen el tráfico: el ALB y NLB solo aceptan tráfico de la lista de prefijos gestionada de CloudFront, y las tareas de ECS solo aceptan tráfico de los grupos de seguridad del ALB y NLB. Para la gestión del ciclo de vida de WebSockets, se implementa un modelo de cuatro capas para mitigar el timeout de inactividad de 350 segundos del NLB: Nakama envía pings WebSocket cada 10 segundos, espera pongs por 20 segundos, rechaza tokens de sesión con más de 2 horas de antigüedad en la conexión, y aplica 'single_socket: true' para cerrar conexiones antiguas del mismo usuario.
Flujo de Autenticación Dual-Token
- 1 Cliente Autentica con Amazon Cognito (USER_SRP_AUTH), recibe JWT.
- 2 Cliente Envía JWT a CloudFront (HTTPS).
- 3 CloudFront AWS WAF inspecciona. Enruta HTTP a ALB, WebSocket a NLB.
- 4 ALB (HTTP API) Valida rutas permitidas. Reenvía a Nakama.
- 5 NLB (WebSocket) TCP passthrough. Reenvía a Nakama.
- 6 Nakama (Go Hook) Valida JWT de Cognito, extrae 'sub', crea/vincula cuenta Nakama.
- 7 Nakama Emite token de sesión Nakama al cliente.
- 8 Cliente Usa token de sesión Nakama para futuras interacciones.
| Capa | Tecnología | Justificación |
|---|---|---|
| security | Amazon Cognito | Proveedor de identidad gestionado, emite JWTs, maneja USER_SRP_AUTH para seguridad de contraseña. vs Auth0, Okta, Keycloak User Pool App Client configurado como cliente público (generate_secret=false), solo permite ALLOW_USER_SRP_AUTH y ALLOW_REFRESH_TOKEN_AUTH. |
| networking | Amazon CloudFront | CDN y punto de entrada HTTPS único, enrutamiento de tráfico HTTP/WebSocket. vs Akamai, Fastly, Cloudflare |
| security | AWS WAF | Filtrado de tráfico en el borde para protección contra ataques web. vs Cloudflare WAF, Imperva WAF |
| networking | Application Load Balancer (ALB) | Balanceador de carga de Capa 7 para tráfico HTTP API, aplica reglas de enrutamiento y lista de permitidos explícita. vs Nginx, HAProxy Acción de listener por defecto 403 Forbidden, reglas para /healthcheck, /v2/account/authenticate/*, /v2/*, /v1/*. |
| networking | Network Load Balancer (NLB) | Balanceador de carga de Capa 4 para tráfico WebSocket (TCP passthrough). vs ELB Classic, HAProxy (TCP mode) TCP idle timeout de 350 segundos. |
| compute | Amazon Elastic Container Service (ECS) on AWS Fargate | Plataforma de orquestación de contenedores para ejecutar el servidor de juegos Nakama. vs Kubernetes (EKS), Google Kubernetes Engine (GKE), Azure Kubernetes Service (AKS) |
| compute | Nakama | Servidor de juegos de código abierto, gestiona sesiones de juego y lógica de negocio. vs Colyseus, Photon Plugin de Go para hooks de runtime, configuración de ping/pong WebSocket, token_expiry_sec, single_socket. |
| security | Go Runtime Hook | Componente de lógica de negocio para validar JWTs de Cognito y realizar el intercambio de tokens a sesiones de Nakama. vs Middleware en otro lenguaje (si el servidor lo permite) Implementa validación de JWT (formato, RS256, firma JWKS, expiración, emisor, audiencia), cacheo de JWKS con protección 'thundering herd'. |
| orchestration | Terraform | Infraestructura como código para desplegar y gestionar todos los recursos de AWS. vs AWS CloudFormation, Pulumi Módulos para network, compute, auth, cdn, waf-cloudfront, ops. |
Trade-offs
Ganancias
- ▲ Seguridad de identidad
- ▲ Desacoplamiento de identidad y sesión
- ▲ Reducción de superficie de ataque (ALB)
- △ Flexibilidad para tráfico HTTP/WebSocket
Costes
- △ Complejidad de infraestructura (doble LB)
- △ Gestión del ciclo de vida de WebSocket (NLB timeout)
- △ Exposición de tokens en logs (query parameter)
func InitModule(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, initializer runtime.Initializer) error {
initializer.RegisterBeforeAuthenticateCustom(beforeAuthenticateCustom)
return nil
}Fundamentos Teóricos
El problema de la autenticación y autorización en sistemas distribuidos ha sido un tema central en la investigación de seguridad informática y sistemas operativos desde sus inicios. La utilización de JSON Web Tokens (JWTs) para la identidad y tokens de sesión para la autorización se alinea con los principios de los sistemas basados en capacidades (capability-based systems), donde un token actúa como una prueba de autorización para realizar ciertas acciones. El concepto de separar la identidad de la sesión y la validación "sin estado" del JWT se remonta a los principios de los sistemas de seguridad basados en criptografía, donde la confianza se establece a través de firmas digitales en lugar de consultas a una base de datos centralizada en cada solicitud.
La validación de JWTs, incluyendo la verificación de la firma y la gestión de claves públicas (JWKS), se basa en los fundamentos de la criptografía de clave pública y los estándares como RFC 7519 (JWT) y RFC 7517 (JWKS). La protección contra ataques de "thundering herd" al refrescar el caché de JWKS es una aplicación práctica de algoritmos de concurrencia y limitación de tasas, comunes en sistemas distribuidos de alto rendimiento. El manejo del ciclo de vida de las conexiones WebSocket detrás de un balanceador de carga de Capa 4, con pings/pongs y timeouts, es una aplicación directa de los conceptos de "keep-alives" y detección de fallos en redes, esenciales para la resiliencia en sistemas distribuidos, como se discute en trabajos sobre protocolos de transporte y detección de particiones de red.