Inicio / TLS / Federación

Federación y redes

Dos o más instancias de Portal se conectan y comparten recursos a través de canales cifrados y autenticados. Las rutas remotas funcionan exactamente igual que las locales — la federation es transparente.

Topología: hub routing

La federation utiliza un modelo hub-and-spoke. Un nodo con IP pública actúa como hub, retransmitiendo el tráfico entre nodos situados detrás de NAT. Los nodos NAT solo realizan conexiones salientes — nunca necesitan puertos de entrada abiertos.

Durante el handshake TLS, el hub anuncia su lista de pares conectados. Cada nodo NAT descubre todos los demás nodos a través del hub. Los pares indirectos se registran automáticamente — no se requiere configuración manual para la conectividad.

  ssip841 (NAT) ───TLS───> devtest (hub público) <───TLS─── asus (NAT)
                                    │
                     Hub reenvía: ssip841 ↔ asus

El hub inspecciona el nombre del nodo de destino en cada mensaje y lo reenvía al par correcto. Desde la perspectiva de ssip841, enviar un mensaje a asus es idéntico a enviarlo a devtest — el hub routing es invisible.

Wire protocol (PORTAL02)

Todo el tráfico de federation utiliza un wire protocol binario con prefijo de longitud en orden de bytes de red (big-endian). Cada trama en el canal sigue las mismas reglas de serialización:

Serialización de mensajes:

  • id — identificador único de solicitud para emparejar respuestas
  • method — GET, SET, EXEC, SUB, UNSUB, EVENT
  • path — recurso de destino (/node/module/resource)
  • headers — pares clave-valor de metadatos
  • body — bytes de carga útil arbitrarios
  • context — identidad de autenticación, trace ID y etiquetas (viaja extremo a extremo)

Serialización de respuestas:

  • status — código de resultado numérico (200 OK, 404 Not Found, 403 Forbidden, etc.)
  • headers — metadatos de respuesta
  • body — carga útil de respuesta

Secuencia de handshake:

  1. El iniciador envía los bytes mágicos PORTAL02
  2. Hash SHA-256 de la clave de federation
  3. Nombre del nodo local
  4. Lista de pares actualmente conectados (lista de pares anunciada)

Si el hash de la clave no coincide, la conexión se cierra inmediatamente.

Cifrado TLS

Todo el tráfico de federation se cifra mediante OpenSSL. Cada instancia de Portal mantiene su propio directorio certs/ que contiene su certificado y clave privada.

Los certificados autofirmados se generan automáticamente en la primera ejecución con portal -C. Esto hace que el despliegue sea trivial — no se necesita infraestructura de CA. La verificación de certificados es configurable: se puede desactivar para entornos autofirmados o activar cuando se utiliza una cadena de CA adecuada.

La capa TLS se sitúa por debajo del wire protocol. Las tramas binarias PORTAL02 se transmiten dentro del canal cifrado.

Autenticación por clave de federation

Los pares de federation se autentican mediante un secreto compartido. Durante el handshake, el nodo que se conecta envía un hash SHA-256 de su clave de federation configurada. El nodo receptor compara este hash con el de su propia clave.

Si los hashes no coinciden, el par es rechazado y la conexión se cierra. Esto garantiza que solo los nodos que pertenecen a la misma federation puedan comunicarse, incluso si la verificación de certificados TLS está desactivada.

La clave de federation se configura en mod_node.conf y debe ser idéntica en todos los nodos de la federation.

Pool de hilos de trabajo

Cada conexión de par está respaldada por un número configurable de hilos de trabajo (por defecto: 4). Las solicitudes entrantes de un par se distribuyen a los trabajadores en orden round-robin, lo que permite el procesamiento concurrente de múltiples mensajes del mismo par.

Cada trabajador mantiene su propia conexión TCP persistente con el par. Esto evita la sobrecarga de establecimiento de conexión y garantiza un rendimiento estable bajo carga. El número de hilos es ajustable por nodo mediante threads_per_peer en la configuración.

Reconexión automática

Las conexiones de federation son resilientes por diseño. La API de temporizadores del core monitoriza el estado de los pares y detecta conexiones atascadas o inactivas. Cuando un par configurado se desconecta, el nodo reintenta automáticamente la conexión con un programa de espera incremental.

TCP keepalive está habilitado en todos los sockets de federation con parámetros agresivos:

  • Tiempo de espera inactivo: 60 segundos antes del primer sondeo
  • Intervalo de sondeo: 30 segundos entre sondeos
  • Número de sondeos: 3 sondeos fallidos antes de declarar la conexión como muerta

Los pares indirectos (descubiertos a través del anuncio del hub) se eliminan cuando la conexión con el hub se pierde. Se recrean automáticamente cuando la conexión con el hub se restablece y la lista de pares se anuncia de nuevo.

Diagnósticos

La CLI de Portal proporciona herramientas integradas para inspeccionar y solucionar problemas de federation:

portal:/> ping asus                    # Medir RTT hacia un par específico
portal:/> ping all                     # Hacer ping a todos los pares conectados
portal:/> tracert /asus/core/status    # Mostrar latencia salto a salto hacia un recurso
portal:/> node peers                   # Listar todos los pares con contadores de tráfico
portal:/> node status asus             # Info TLS, workers, uptime, msgs/bytes

ping mide el tiempo de ida y vuelta enviando una sonda ligera a través del canal de federation. tracert muestra cada salto y su latencia individual cuando un mensaje atraviesa múltiples nodos. node peers y node status proporcionan el estado detallado de la conexión, incluyendo versión TLS, cifrado, utilización de hilos de trabajo, tiempo de actividad y contadores de tráfico acumulados.

Configuración

La federation se configura en mod_node.conf. Todas las opciones están documentadas en el propio archivo de configuración (Ley 11):

[mod_node]
node_name        = mynode
listen_port      = 9701
threads_per_peer = 4
tls              = true
cert_file        = /etc/portal/mynode/certs/server.crt
key_file         = /etc/portal/mynode/certs/server.key
tls_verify       = false
federation_key   = shared-secret-here

[nodes]
peer0 = hub-node=10.0.1.5:9706

La sección [nodes] lista los pares a los que esta instancia debe conectarse al iniciar. Cada entrada especifica un nombre de par y su dirección. Los nodos hub no necesitan entradas para los pares NAT — estos se conectan de forma entrante y se aceptan automáticamente si la clave de federation coincide.

Acceso transparente

Una vez establecida la federation, se accede a los recursos remotos utilizando la misma sintaxis de path que para los locales. El nombre del nodo es simplemente el primer segmento del path:

portal:/> get /devtest2/core/status     # Par directo
portal:/> get /asus/core/status         # Par NAT remoto (enrutado a través del hub)
portal:/> get /asus/iot/resources/devices # Módulo IoT en un nodo remoto

Desde HTTP, los mismos recursos son accesibles a través del endpoint API del módulo web:

curl http://host:8080/api/asus/core/status
Los módulos no saben si un path es local o remoto. Un script Lua que llama a portal.get('/warehouse/serial/com1/read') lee de forma transparente un puerto serie físico en una máquina remota a través de federation cifrada con TLS. El script escribió una sola línea.

Reenvío de puertos (mod_tunnel)

El módulo mod_tunnel permite el reenvío de puertos TCP sin procesar a través de la red de federation. Un servicio local se puede exportar para que los nodos remotos puedan alcanzarlo, y un servicio remoto se puede mapear a un puerto local para acceso directo.

Tras el handshake inicial del túnel, mod_tunnel realiza retransmisión de bytes sin sobrecarga — los bytes TCP sin procesar se reenvían a través del canal de federation cifrado sin enmarcado ni procesamiento adicional.

Esto permite casos de uso potentes como el acceso SSH a máquinas detrás de NAT. Un nodo detrás de NAT exporta su puerto SSH (22) a través del hub de federation. Cualquier par en la federation puede entonces mapear ese puerto remoto a un puerto local y conectarse con un cliente SSH estándar, como si la máquina remota estuviera en la red local.

ACL entre nodos

El wire protocol transporta el contexto completo de autenticación con cada mensaje: identidad del usuario, pertenencia a grupos y etiquetas. Este contexto se establece en el nodo de origen y se preserva extremo a extremo a través de cada salto en la federation.

Cada nodo aplica sus propias reglas ACL de forma independiente. Cuando un mensaje llega de un par remoto, el nodo receptor inspecciona el contexto de autenticación adjunto y aplica sus políticas de control de acceso locales. Un usuario que tiene acceso de lectura en el Nodo A no obtiene automáticamente acceso de escritura en el Nodo B — cada nodo es soberano sobre sus propios recursos.

Este diseño significa que la federation no debilita la seguridad. Conectar dos nodos no fusiona sus modelos de permisos. Cada nodo confía en la identidad del wire protocol pero aplica sus propias reglas.