Matriz de Comunicaciones & Reglas de Firewall (UFW)
En una infraestructura distribuida de alta disponibilidad para Mañuti, la seguridad perimetral se rige bajo el principio estricto de Red Zero-Trust (Confianza Cero) y Mínimo Privilegio. Ningún nodo interno confía en el tráfico de la red local por el mero hecho de compartir el segmento Ethernet; cada host aísla su pila TCP/IP mediante UFW (Uncomplicated Firewall), permitiendo únicamente flujos punto a punto bidireccionalmente declarados.
1. Filosofía de Seguridad Perimetral: Red Zero-Trust
La topología distribuida de Mañuti divide los servidores físicos o virtuales en cuatro capas lógicas con políticas de descarte por defecto (Default Deny):
flowchart TD
U(["INTERNET / CLIENTES EXTERNOS"])
subgraph Capa1 ["1. CAPA DE ACCESO PÚBLICA (DMZ)"]
LB["Load Balancer (Nginx / HAProxy)<br/>Única IP con cara a Internet"]
end
subgraph Capa2 ["2. CAPA DE APLICACIÓN"]
WEB["Web-01 / Web-02 (PHP-FPM)"]
WORKER["Worker (Horizon Daemons)"]
end
subgraph Capa3 ["3. CAPA TIEMPO REAL"]
REVERB["Reverb (WebSockets)<br/>Puerto 8080 Interno"]
end
subgraph Capa4 ["4. CAPA DE PERSISTENCIA"]
MARIADB[("MariaDB Clúster (3306)")]
REDIS[("Redis Caché/Colas (6379)")]
MONGO[("MongoDB Auditoría (27017)")]
end
subgraph Capa5 ["5. CAPA DE ALMACENAMIENTO"]
MINIO[("MinIO S3 (9000/9001)")]
end
%% Conexiones desde el exterior
U -->|"HTTPS (443) / HTTP (80)"| LB
%% Conexiones desde el balanceador
LB -->|"Red Privada LAN (Tráfico Balanceado)"| WEB
LB -->|"Redirección WSS"| REVERB
%% Conexiones desde la capa de aplicación hacia persistencia/almacenamiento
WEB -->|"Consultas SQL / NoSQL"| MARIADB
WEB -->|"Redis Caché/PubSub"| REDIS
WEB --> MONGO
WEB -->|"S3 PutObject"| MINIO
WORKER --> MARIADB
WORKER --> REDIS
WORKER --> MONGO
WORKER --> MINIO
%% Conexiones desde la capa en tiempo real
REVERB --> REDIS
Reglas de Oro de la Red:
- Denegación Implícita Universal: Todos los nodos inician con
ufw default deny incoming. Si una conexión no está explícitamente autorizada con su IP de origen, el paquete se descarta de forma silenciosa (DROP). - Invisibilidad de la Capa Web: Los servidores de aplicación (
Web-01,Web-02) no tienen puertos públicos. Si un atacante intenta conectar ahttp://192.168.1.64:80saltándose el balanceador, el firewall del host rechaza la conexión. - Aislamiento de la Persistencia: MariaDB, MongoDB y Redis solo aceptan tráfico de las IPs de los servidores de aplicación y workers que ejecutan código PHP.
2. Matriz de Control de Acceso y Mapa de Puertos
A continuación se detalla la matriz maestra de interconexión.
Nota sobre el direccionamiento IP: Los parámetros
192.168.1.0/24corresponden a la subred de demostración del clúster Bare-Metal. En entornos productivos, sustituya estos valores por las IPs estáticas de su VLAN privada o VPC.
| Capa | Nodo / Host | IP Ilustrativa | Servicio | Puerto | Origen Autorizado | Justificación Operativa |
|---|---|---|---|---|---|---|
| Acceso | Load Balancer (LB) | 192.168.1.122 |
HTTP | 80/tcp |
0.0.0.0/0 (Anywhere) |
Recepción de tráfico web estándar y redirección a HTTPS. |
| HTTPS | 443/tcp |
0.0.0.0/0 (Anywhere) |
Terminación TLS/SSL para navegación web y túneles WSS. | |||
| SSH | 22/tcp |
192.168.1.0/24 (Admin) |
Gestión de infraestructura y despliegues desde el bastión. | |||
| Aplicación | Web-01 | 192.168.1.64 |
HTTP | 80/tcp |
192.168.1.122 (Solo LB) |
Recepción de tráfico HTTP inverso balanceado desde Nginx. |
| SSH | 22/tcp |
192.168.1.0/24 |
Automatización de despliegues y administración remota. | |||
| Aplicación | Web-02 | 192.168.1.130 |
HTTP | 80/tcp |
192.168.1.122 (Solo LB) |
Réplica idéntica sin estado para balanceo de carga. |
| SSH | 22/tcp |
192.168.1.0/24 |
Automatización de despliegues y administración remota. | |||
| Aplicación | Worker (Horizon) | 192.168.1.126 |
SSH | 22/tcp |
192.168.1.0/24 |
Administración. No recibe tráfico de red de usuarios. |
| Tiempo Real | Realtime (Reverb) | 192.168.1.127 |
WSS / API | 8080/tcp |
192.168.1.122 (LB) |
Túneles WebSocket de clientes derivados por Nginx. |
| HTTP API | 8080/tcp |
192.168.1.64 (Web-01) |
Emisión de eventos backend (API Push ShouldBroadcast). |
|||
| HTTP API | 8080/tcp |
192.168.1.130 (Web-02) |
Emisión de eventos backend (API Push ShouldBroadcast). |
|||
| HTTP API | 8080/tcp |
192.168.1.126 (Worker) |
Emisión de eventos desde jobs en segundo plano. | |||
| SSH | 22/tcp |
192.168.1.0/24 |
Administración y control de demonios. | |||
| Datos | SQL (MariaDB) | 192.168.1.123 |
MySQL | 3306/tcp |
192.168.1.64 (Web-01) |
Transacciones transaccionales y de identidad. |
| MySQL | 3306/tcp |
192.168.1.130 (Web-02) |
Transacciones transaccionales y de identidad. | |||
| MySQL | 3306/tcp |
192.168.1.126 (Worker) |
Procesamiento relacional asíncrono y lotes (job_batches). |
|||
| SSH | 22/tcp |
192.168.1.0/24 |
Gestión DBA y respaldos. | |||
| Datos | Caché (Redis) | 192.168.1.124 |
Redis | 6379/tcp |
192.168.1.64 (Web-01) |
Sesiones de usuario (520 B) y caché de catálogos. |
| Redis | 6379/tcp |
192.168.1.130 (Web-02) |
Sesiones de usuario (520 B) y caché de catálogos. | |||
| Redis | 6379/tcp |
192.168.1.126 (Worker) |
Broker de transporte de colas (Horizon). | |||
| Redis | 6379/tcp |
192.168.1.127 (Reverb) |
Bus Pub/Sub para escalado de WebSockets. | |||
| SSH | 22/tcp |
192.168.1.0/24 |
Administración. | |||
| Datos | NoSQL (MongoDB) | 192.168.1.120 |
Mongo | 27017/tcp |
192.168.1.64 (Web-01) |
Escritura de logs forenses de auditoría en caliente. |
| Mongo | 27017/tcp |
192.168.1.130 (Web-02) |
Escritura de logs forenses de auditoría en caliente. | |||
| Mongo | 27017/tcp |
192.168.1.126 (Worker) |
Consumo y procesamiento forense por workers de Horizon. | |||
| SSH | 22/tcp |
192.168.1.0/24 |
Administración DBA. | |||
| Storage | Object Storage (MinIO) | 192.168.1.125 |
HTTP/S | 80, 443/tcp |
0.0.0.0/0 (Anywhere) |
Descargas públicas directas de avatares y mapas (CDN). |
| S3 API | 9000/tcp |
192.168.1.64 (Web-01) |
Subida interna de avatares (PutObject). |
|||
| S3 API | 9000/tcp |
192.168.1.130 (Web-02) |
Subida interna de avatares (PutObject). |
|||
| S3 API | 9000/tcp |
192.168.1.126 (Worker) |
Subida de exportaciones ARCO y diagramas SVG. | |||
| Consola | 9001/tcp |
192.168.1.0/24 |
Panel web administrativo de MinIO Console. | |||
| SSH | 22/tcp |
192.168.1.0/24 |
Administración. |
3. Diagrama de Conectividad de Red y Flujos
flowchart TD
UserClient(["Usuario / Internet"])
subgraph CapaAcceso ["1. Capa de Acceso (Public Subnet)"]
LB["Load Balancer (Nginx)<br>192.168.1.122"]
end
subgraph CapaApp ["2. Capa de Aplicación (Private Stateless)"]
W1["Web-01<br>192.168.1.64"]
W2["Web-02<br>192.168.1.130"]
WORK["Worker (Horizon)<br>192.168.1.126"]
end
subgraph CapaRealtime ["3. Capa Tiempo Real"]
RT["Reverb (WebSockets)<br>192.168.1.127"]
end
subgraph CapaDatos ["4. Capa de Datos (Private Stateful)"]
DB[("MariaDB SQL<br>192.168.1.123")]
REDIS[("Redis In-Memory<br>192.168.1.124")]
MONGO[("MongoDB NoSQL<br>192.168.1.120")]
end
subgraph CapaStorage ["5. Capa Almacenamiento"]
ST[("MinIO S3 Storage<br>192.168.1.125")]
end
%% Flujos Externos
UserClient -->|"HTTPS:443 / HTTP:80"| LB
UserClient -.->|"Descarga CDN (80/443)"| ST
%% Balanceo HTTP
LB -->|"TCP:80 (Proxy Pass)"| W1
LB -->|"TCP:80 (Proxy Pass)"| W2
LB -->|"TCP:8080 (WSS Tunnel /app)"| RT
%% Tráfico hacia Realtime
W1 -->|"HTTP API:8080 (Push Event)"| RT
W2 -->|"HTTP API:8080 (Push Event)"| RT
WORK -->|"HTTP API:8080 (Push Event)"| RT
%% Conexiones de Datos SQL
W1 -->|"TCP:3306"| DB
W2 -->|"TCP:3306"| DB
WORK -->|"TCP:3306"| DB
%% Conexiones Redis
W1 -->|"TCP:6379 (Session/Cache)"| REDIS
W2 -->|"TCP:6379 (Session/Cache)"| REDIS
WORK -->|"TCP:6379 (Queues)"| REDIS
RT -->|"TCP:6379 (Pub/Sub)"| REDIS
%% Conexiones NoSQL MongoDB
W1 -->|"TCP:27017 (Audit)"| MONGO
W2 -->|"TCP:27017 (Audit)"| MONGO
WORK -->|"TCP:27017 (Audit)"| MONGO
%% Conexiones MinIO S3
W1 -->|"TCP:9000 (S3 PutObject)"| ST
W2 -->|"TCP:9000 (S3 PutObject)"| ST
WORK -->|"TCP:9000 (S3 PutObject)"| ST
4. Guía de Configuración Host por Host (UFW)
Para aplicar este blindaje en un despliegue Bare-Metal o máquinas virtuales Ubuntu 24.04, ejecute los bloques de comandos en sus nodos respectivos.
A. Política Base Inicial (Ejecutar en TODOS los nodos)
sudo ufw reset
sudo ufw default deny incoming
sudo ufw default allow outgoing
# Permitir SSH únicamente desde la red interna de administración
sudo ufw allow from 192.168.1.0/24 to any port 22 proto tcp comment 'Admin SSH'
B. Nodo 1: Load Balancer (192.168.1.122)
Es el único componente que expone puertos al mundo exterior:
sudo ufw allow 80/tcp comment 'HTTP Ingress'
sudo ufw allow 443/tcp comment 'HTTPS Ingress'
sudo ufw enable
sudo ufw status numbered
C. Nodos Web: Web-01 (.64) y Web-02 (.130)
Bloqueo de acceso directo. Solo atienden peticiones nacidas en la IP interna del Load Balancer:
sudo ufw allow from 192.168.1.122 to any port 80 proto tcp comment 'Trafico HTTP solo desde LB'
sudo ufw enable
D. Nodo Tiempo Real: Reverb (192.168.1.127)
Acepta dos fuentes de tráfico en el puerto 8080: el Load Balancer (clientes WebSocket) y los servidores de aplicación/worker (publicación de eventos backend):
# Tráfico de clientes web derivado por el Load Balancer
sudo ufw allow from 192.168.1.122 to any port 8080 proto tcp comment 'WSS Tunnel desde LB'
# API Push interna desde el clúster de aplicación
sudo ufw allow from 192.168.1.64 to any port 8080 proto tcp comment 'Push Event desde Web-01'
sudo ufw allow from 192.168.1.130 to any port 8080 proto tcp comment 'Push Event desde Web-02'
sudo ufw allow from 192.168.1.126 to any port 8080 proto tcp comment 'Push Event desde Worker'
sudo ufw enable
E. Nodo Base de Datos Relacional: MariaDB (192.168.1.123)
Atención: Asegúrese de configurar
bind-address = 0.0.0.0en/etc/mysql/mariadb.conf.d/50-server.cnfantes de activar el firewall.
sudo ufw allow from 192.168.1.64 to any port 3306 proto tcp comment 'SQL Web-01'
sudo ufw allow from 192.168.1.130 to any port 3306 proto tcp comment 'SQL Web-02'
sudo ufw allow from 192.168.1.126 to any port 3306 proto tcp comment 'SQL Worker Horizon'
sudo ufw enable
F. Nodo Caché y Sesiones: Redis (192.168.1.124)
Atención: Configure
bind 0.0.0.0yprotected-mode yesen/etc/redis/redis.conf.
sudo ufw allow from 192.168.1.64 to any port 6379 proto tcp comment 'Redis Sesion Web-01'
sudo ufw allow from 192.168.1.130 to any port 6379 proto tcp comment 'Redis Sesion Web-02'
sudo ufw allow from 192.168.1.126 to any port 6379 proto tcp comment 'Redis Colas Worker'
sudo ufw allow from 192.168.1.127 to any port 6379 proto tcp comment 'Redis PubSub Reverb'
sudo ufw enable
G. Nodo NoSQL: MongoDB (192.168.1.120)
Atención: Configure
net.bindIp: 0.0.0.0en/etc/mongod.conf.
sudo ufw allow from 192.168.1.64 to any port 27017 proto tcp comment 'Mongo Audit Web-01'
sudo ufw allow from 192.168.1.130 to any port 27017 proto tcp comment 'Mongo Audit Web-02'
sudo ufw allow from 192.168.1.126 to any port 27017 proto tcp comment 'Mongo Audit Worker'
sudo ufw enable
H. Nodo Storage: MinIO S3 (192.168.1.125)
Expone la API interna para subidas autenticadas y la consola de administración en la LAN:
# Acceso público CDN para descarga de avatares y mapas vectoriales
sudo ufw allow 80/tcp comment 'MinIO CDN HTTP'
sudo ufw allow 443/tcp comment 'MinIO CDN HTTPS'
# API S3 Interna (PutObject / GetObject seguro)
sudo ufw allow from 192.168.1.64 to any port 9000 proto tcp comment 'MinIO API Web-01'
sudo ufw allow from 192.168.1.130 to any port 9000 proto tcp comment 'MinIO API Web-02'
sudo ufw allow from 192.168.1.126 to any port 9000 proto tcp comment 'MinIO API Worker'
# Consola Web Administrativa (Restringida a la Subred de Gestión)
sudo ufw allow from 192.168.1.0/24 to any port 9001 proto tcp comment 'MinIO Console LAN'
sudo ufw enable
I. Nodo Worker: Horizon (192.168.1.126)
Dado que Horizon es un consumidor pasivo (inicia sockets salientes hacia Redis, MariaDB, Mongo y MinIO pero no expone ningún puerto de escucha HTTP), su configuración perimetral es la más simple y segura:
# Solo SSH permitido
sudo ufw enable
5. El Flujo de Difusión WebSocket en Dos Fases
La separación de Reverb en un nodo dedicado genera una distinción arquitectónica entre la conexión persistente del cliente y la emisión de eventos del backend:
sequenceDiagram
autonumber
actor Cliente as Navegador Web
participant LB as Load Balancer (.122)
participant RT as Reverb Daemon (.127)
participant W1 as Web-01 (.64)
participant Redis as Redis Pub/Sub (.124)
%% Fase 1
Note over Cliente, RT: FASE 1: Conexión Persistente (El Túnel WSS)
Cliente->>LB: GET /app/key (Upgrade: websocket) [Puerto 443]
LB->>RT: Proxy Pass TCP:8080 (HTTP Upgrade)
RT-->>LB: 101 Switching Protocols
LB-->>Cliente: Conexión WebSocket Abierta (Túnel WSS Activo)
%% Fase 2
Note over Cliente, Redis: FASE 2: Disparo de Evento en Backend
Cliente->>LB: POST /usuarios (Crear Usuario)
LB->>W1: Proxy Pass HTTP:80
W1->>W1: Procesa en MariaDB y despacha Evento
W1->>RT: POST http://192.168.1.127:8080/apps/id/events (API Push)
RT->>Redis: PUBLISH reverb-scaling (Payload JSON)
Redis-->>RT: Mensaje distribuido a instancias suscritas
RT-->>Cliente: Push Frame WebSocket (sessions.updated / audit.created)
- Fase 1 (El Túnel): El navegador del cliente abre un socket contra el Load Balancer (
https://dominio.com/app). Nginx detecta el encabezadoUpgrade: websockety deriva el socket al puerto8080de Reverb. Los nodos Web desconocen esta conexión. - Fase 2 (El Evento): Cuando ocurre una mutación en
Web-01(e.g. un operador desconecta a un usuario), el servidor web emite una llamada REST internaPOST http://192.168.1.127:8080/apps/.../events. Reverb recibe el paquete, se coordina mediante Redis Pub/Sub y empuja el frame a través del túnel persistente establecido en la Fase 1 hacia el navegador.
6. Procedimientos de Diagnóstico y Mantenimiento
Inspección de Reglas Numeradas
sudo ufw status numbered
Eliminación Segura de una Regla Errónea
# Elimina la regla número 3 sin alterar las demás
sudo ufw delete 3
sudo ufw reload
Validación de Conectividad Inter-Nodo (Prueba de Socket)
Ejecute desde Web-01 para verificar que el puerto de base de datos está abierto en el nodo SQL:
nc -zv 192.168.1.123 3306
# Salida esperada: Connection to 192.168.1.123 3306 port [tcp/mysql] succeeded!