1148 lines
48 KiB
Markdown
1148 lines
48 KiB
Markdown
|
|
# Decision: Capa de red y conectividad (punto 4)
|
|||
|
|
|
|||
|
|
## Contexto
|
|||
|
|
|
|||
|
|
El PBS actual tiene el puerto 8007 abierto a internet para recibir backups. A 100+ servidores, cada servicio de backup deberia ir por VPN privada. Ademas, ya existe PowerDNS y Traefik en uso. La capa de red organiza como se comunican los servidores entre si y con el exterior de forma segura.
|
|||
|
|
|
|||
|
|
Infraestructura fisica: servidores con 2 interfaces de red (IP publica + vRack OVH 25Gbps). Todo el direccionamiento interno sera IPv6 (ULA).
|
|||
|
|
|
|||
|
|
3 subcapas:
|
|||
|
|
- 4.1 VPN y acceso seguro entre servidores
|
|||
|
|
- 4.2 DNS y service discovery
|
|||
|
|
- 4.3 Proxy inverso y balanceo
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 4.1 VPN y acceso seguro entre servidores
|
|||
|
|
|
|||
|
|
### El problema
|
|||
|
|
|
|||
|
|
- PBS:8007 expuesto a internet para recibir backups de PVE remotos
|
|||
|
|
- Trafico de backup viaja por internet sin cifrado adicional (solo TLS de PBS)
|
|||
|
|
- vRack de OVH conecta servidores pero sin cifrado ni autenticacion (L2 privada, no segura)
|
|||
|
|
- Sin VPN, cada servicio nuevo expuesto requiere abrir puertos en firewall publico
|
|||
|
|
- La superficie de ataque crece con cada puerto abierto
|
|||
|
|
- Modelo actual de gateways: 1 VM gateway por cliente (NAT + WG), no escala
|
|||
|
|
|
|||
|
|
### Opciones evaluadas
|
|||
|
|
|
|||
|
|
| Herramienta | Modelo | Recursos | Complejidad | Estado |
|
|||
|
|
|-------------|--------|----------|-------------|--------|
|
|||
|
|
| **WireGuard** | Punto a punto, hub-spoke | Kernel module, ~0 overhead | Baja (config manual, Ansible) | **ELEGIDA** |
|
|||
|
|
| **Tailscale** | Mesh VPN, SaaS | Agente ligero | Muy baja | Descartada (SaaS, dependencia externa) |
|
|||
|
|
| **Headscale** | Tailscale self-hosted | ~200MB RAM | Baja-media | Posible evolucion futura si escala |
|
|||
|
|
| **Nebula** | Overlay con certificados | Agente ligero | Media | Descartada (menor comunidad) |
|
|||
|
|
| **Netbird** | Mesh con SSO | ~300MB RAM | Media | Descartada (muy joven) |
|
|||
|
|
| **BGP/OSPF entre hubs** | Routing dinamico | FRRouting | Alta | Descartado (overengineering a esta escala) |
|
|||
|
|
|
|||
|
|
### DECISION 4.1 (confirmada)
|
|||
|
|
|
|||
|
|
#### WireGuard + wgdashboard + IPv6 ULA
|
|||
|
|
|
|||
|
|
Todo el direccionamiento WireGuard en IPv6 ULA (fd00::/8). No ruteable a internet, privado por diseño.
|
|||
|
|
|
|||
|
|
#### Tres roles de WireGuard
|
|||
|
|
|
|||
|
|
**Rol 1: PBS como servidor WG (backups)**
|
|||
|
|
|
|||
|
|
Cada PBS fisico es un servidor WireGuard cuyos unicos peers son los PVE que le envian backups.
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
PBS-1 (wg server) PBS-2 (wg server)
|
|||
|
|
├── peer: PVE-A ├── peer: PVE-D
|
|||
|
|
├── peer: PVE-B └── peer: PVE-E
|
|||
|
|
└── peer: PVE-C
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
- PVE apunta su PBS storage a [fdab:1234:bkp::1]:8007 (IP WG del PBS)
|
|||
|
|
- PBS:8007 deja de escuchar en IP publica
|
|||
|
|
- Los peers PVE NO se ven entre ellos (ip forwarding desactivado, AllowedIPs /128 por peer)
|
|||
|
|
- Trafico por vRack (25Gbps) cuando estan en el mismo DC
|
|||
|
|
|
|||
|
|
**Rol 2: WG Hub (acceso clientes + tecnicos + VMs)**
|
|||
|
|
|
|||
|
|
Hub centralizado donde se conectan:
|
|||
|
|
- Usuarios remotos (tecnicos, clientes)
|
|||
|
|
- Mikrotiks de oficinas de clientes
|
|||
|
|
- VMs de clientes que necesitan red privada
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
WG Hub (par HA con keepalived)
|
|||
|
|
├── peer: tecnico David
|
|||
|
|
├── peer: tecnico Juan
|
|||
|
|
├── peer: cliente ACME usuario remoto
|
|||
|
|
├── peer: cliente ACME mikrotik oficina
|
|||
|
|
├── peer: VM-web ACME (en PVE-1)
|
|||
|
|
├── peer: VM-db ACME (en PVE-2)
|
|||
|
|
├── peer: cliente BETA usuario remoto
|
|||
|
|
├── peer: VM-app BETA (en PVE-1)
|
|||
|
|
└── ...
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
- ip forwarding ACTIVADO (los peers deben verse entre ellos)
|
|||
|
|
- Aislamiento por cliente con nftables: peers de ACME solo ven peers de ACME
|
|||
|
|
- VMs en PVEs distintos se ven via WG Hub (cross-PVE transparente)
|
|||
|
|
- Panel futuro para que el cliente defina granularidad peer-a-peer
|
|||
|
|
- Reemplaza el modelo de 1 gateway VM por cliente: gateways compartidos con reglas granulares
|
|||
|
|
|
|||
|
|
**Rol 3: Mesh de gestion entre fisicos (sobre vRack)**
|
|||
|
|
|
|||
|
|
WireGuard sobre vRack para cifrar y autenticar el trafico de gestion entre servidores fisicos.
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
Fisico 1 (vRack) ◄── WG tunnel cifrado ──► Fisico 2 (vRack)
|
|||
|
|
fdab:1234:mgmt::1 fdab:1234:mgmt::2
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
- Servicios internos (Grafana, Netbox, Wazuh, Semaphore) escuchan en IP WG mesh
|
|||
|
|
- Ansible, exporters, logs viajan por WG mesh
|
|||
|
|
- Hub-spoke: todos los fisicos conectan a un hub de gestion (o al par HA)
|
|||
|
|
|
|||
|
|
#### Direccionamiento IPv6 ULA
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
fdab:1234:bkp::/48 → Red de backups (PBS ↔ PVE)
|
|||
|
|
fdab:1234:bkp:1::/64 PBS-1 y sus PVEs
|
|||
|
|
fdab:1234:bkp:2::/64 PBS-2 y sus PVEs
|
|||
|
|
|
|||
|
|
fdab:1234:vpn::/48 → Red de clientes/tecnicos (WG Hub)
|
|||
|
|
fdab:1234:vpn:acme::/64 Cliente ACME (VMs + usuarios)
|
|||
|
|
fdab:1234:vpn:beta::/64 Cliente BETA
|
|||
|
|
|
|||
|
|
fdab:1234:mgmt::/48 → Red de gestion (mesh entre fisicos)
|
|||
|
|
fdab:1234:mgmt::1 Hub/Fisico 1
|
|||
|
|
fdab:1234:mgmt::2 Fisico 2
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### Arquitectura del WG Hub
|
|||
|
|
|
|||
|
|
Debian minimal dedicado exclusivamente a WireGuard:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
┌──────────────────────────────────┐
|
|||
|
|
│ Debian minimal │
|
|||
|
|
│ │
|
|||
|
|
│ Kernel: WireGuard module │
|
|||
|
|
│ Host: nftables (aislamiento │
|
|||
|
|
│ por cliente) │
|
|||
|
|
│ Host: /etc/wireguard/*.conf │
|
|||
|
|
│ │
|
|||
|
|
│ Docker: wgdashboard │
|
|||
|
|
│ └─ UI web (gestion de peers) │
|
|||
|
|
│ └─ API REST (→ ICSManager) │
|
|||
|
|
│ └─ Escribe /etc/wireguard/ │
|
|||
|
|
│ └─ Recarga WG (wg syncconf) │
|
|||
|
|
│ │
|
|||
|
|
│ Nada mas. Sin PBS, sin VMs, │
|
|||
|
|
│ sin otros servicios. │
|
|||
|
|
└──────────────────────────────────┘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### Alta disponibilidad: par HA con keepalived
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
┌─────────────┐ ┌─────────────┐
|
|||
|
|
│ WG Hub A │ │ WG Hub B │
|
|||
|
|
│ (MASTER) │ │ (BACKUP) │
|
|||
|
|
│ fdab::1 │ │ fdab::2 │
|
|||
|
|
└──────┬──────┘ └──────┬──────┘
|
|||
|
|
│ │
|
|||
|
|
└───── VIP ─────────┘
|
|||
|
|
fdab:1234:vpn::1
|
|||
|
|
(IP flotante)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
- Misma config WG en ambos (mismas claves, mismos peers)
|
|||
|
|
- Keepalived gestiona VIP sobre vRack
|
|||
|
|
- Failover en <2 segundos
|
|||
|
|
- Los peers no se enteran: su endpoint es la VIP, no cambia
|
|||
|
|
- Para endpoint publico (usuarios remotos): VIP publica o DNS con TTL bajo
|
|||
|
|
|
|||
|
|
#### Aislamiento entre clientes (nftables en el hub)
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# nftables en WG Hub
|
|||
|
|
# Cliente ACME: sus peers se ven entre ellos
|
|||
|
|
nft add rule inet filter forward \
|
|||
|
|
iifname "wg-hub" ip6 saddr fdab:1234:vpn:acme::/64 \
|
|||
|
|
ip6 daddr fdab:1234:vpn:acme::/64 accept
|
|||
|
|
|
|||
|
|
# Cliente BETA: sus peers se ven entre ellos
|
|||
|
|
nft add rule inet filter forward \
|
|||
|
|
iifname "wg-hub" ip6 saddr fdab:1234:vpn:beta::/64 \
|
|||
|
|
ip6 daddr fdab:1234:vpn:beta::/64 accept
|
|||
|
|
|
|||
|
|
# DEFAULT: nadie ve a nadie de otro cliente
|
|||
|
|
nft add rule inet filter forward iifname "wg-hub" drop
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Cada cliente tiene su /64. Las reglas son por subnet, no por peer individual (mas simple). Panel futuro para granularidad peer-a-peer dentro del /64.
|
|||
|
|
|
|||
|
|
#### Cambio de modelo: gateways compartidos
|
|||
|
|
|
|||
|
|
| Modelo actual | Modelo nuevo |
|
|||
|
|
|---|---|
|
|||
|
|
| 1 VM gateway por cliente | 2 VM WG Hub (par HA) compartidos |
|
|||
|
|
| 50 clientes = 50 VMs gateway | 50 clientes = 2 VMs hub |
|
|||
|
|
| NAT por cliente | Sin NAT (peers directos IPv6) |
|
|||
|
|
| Cada GW consume RAM/CPU | Recursos compartidos |
|
|||
|
|
| Aislamiento por VM | Aislamiento por nftables |
|
|||
|
|
| Sin HA (si el GW cae, el cliente cae) | HA con keepalived (<2 seg failover) |
|
|||
|
|
|
|||
|
|
Mitigacion de riesgo: tests automatizados de aislamiento (playbook que verifica que cada cliente solo alcanza sus recursos).
|
|||
|
|
|
|||
|
|
#### Exposicion resultante del servidor fisico
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
eth0 (IP publica):
|
|||
|
|
- Firewall: solo WG UDP (1 puerto) + SSH bastion
|
|||
|
|
- PBS:8007 CERRADO desde internet
|
|||
|
|
- PVE:8006 CERRADO desde internet
|
|||
|
|
- Todo lo demas: DROP
|
|||
|
|
|
|||
|
|
eth1 (vRack 25Gbps):
|
|||
|
|
- WG mesh cifrado (gestion + backups)
|
|||
|
|
- Servicios internos solo escuchan en IP WG
|
|||
|
|
|
|||
|
|
wg-hub (overlay IPv6):
|
|||
|
|
- Clientes y tecnicos acceden a paneles por aqui
|
|||
|
|
- :8007, :8006, Grafana, etc. solo via WG
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### Fase de arranque
|
|||
|
|
|
|||
|
|
Fase inicial con solo tecnicos internos para pulir el modelo:
|
|||
|
|
1. Montar par HA de WG Hub (2 VMs Debian minimal)
|
|||
|
|
2. Peers: solo tecnicos del equipo
|
|||
|
|
3. Validar: acceso a paneles, grabacion bastion, aislamiento nftables
|
|||
|
|
4. Cuando funcione estable: abrir a clientes y VMs progresivamente
|
|||
|
|
|
|||
|
|
#### Recursos
|
|||
|
|
|
|||
|
|
| Componente | CPU | RAM | Disco |
|
|||
|
|
|-----------|-----|-----|-------|
|
|||
|
|
| WG Hub A (master) | 1 vCPU | 512 MB | 10 GB |
|
|||
|
|
| WG Hub B (backup) | 1 vCPU | 512 MB | 10 GB |
|
|||
|
|
| wgdashboard (Docker en Hub A) | incluido | ~200 MB | incluido |
|
|||
|
|
| WG en cada PBS (backup role) | kernel module | ~0 | ~0 |
|
|||
|
|
| WG en cada fisico (mesh role) | kernel module | ~0 | ~0 |
|
|||
|
|
|
|||
|
|
#### Escalabilidad futura
|
|||
|
|
|
|||
|
|
- Si un par HA no es suficiente (>200 peers): asignar clientes a hubs distintos (Hub par 1: clientes A-M, Hub par 2: clientes N-Z), con tunel WG entre hubs para cross-routing
|
|||
|
|
- Si se necesita mesh automatico: evaluar Headscale (compatible con clientes WireGuard existentes)
|
|||
|
|
- Si se necesita routing dinamico entre DCs: FRRouting con OSPF sobre tuneles WG entre hubs
|
|||
|
|
- Nada de esto es necesario para arrancar
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 4.2 DNS y service discovery
|
|||
|
|
|
|||
|
|
### Las 4 problematicas
|
|||
|
|
|
|||
|
|
1. **Autoritativo de clientes**: zonas de dominios de clientes (primario o secundario)
|
|||
|
|
2. **Resolver para clientes**: navegacion de VMs y usuarios WG, con bloqueo configurable
|
|||
|
|
3. **Naming automatico**: toda IP asignada tiene AAAA + PTR operativos desde el momento 0
|
|||
|
|
4. **Diagnostico self-service**: pagina donde el cliente verifica su conectividad antes de abrir ticket
|
|||
|
|
|
|||
|
|
### Opciones evaluadas para resolver
|
|||
|
|
|
|||
|
|
| Herramienta | Multi-tenant | Panel cliente | Bloqueo config. | API | Estado |
|
|||
|
|
|-------------|-------------|---------------|-----------------|-----|--------|
|
|||
|
|
| **Technitium DNS** | Si (por cliente/zona) | Panel web multi-usuario nativo | Si (listas por cliente) | REST completa | **ELEGIDA como resolver** |
|
|||
|
|
| **AdGuard Home** | Parcial (por IP) | Solo admin | Si (listas por IP) | REST | Descartada (no multi-tenant nativo) |
|
|||
|
|
| **Pi-hole** | No | No | Global | Limitada | Descartada |
|
|||
|
|
| **Blocky** | Si (grupos) | No tiene UI | Si (por grupo) | Si | Descartada (sin panel) |
|
|||
|
|
| **Unbound** | No | No | No | No | Descartada (solo resuelve) |
|
|||
|
|
|
|||
|
|
### DECISION 4.2 (confirmada)
|
|||
|
|
|
|||
|
|
#### Componente 1: PowerDNS Authoritative (ya existente)
|
|||
|
|
|
|||
|
|
Se mantiene y amplia. No se reemplaza.
|
|||
|
|
|
|||
|
|
| Funcion | Estado |
|
|||
|
|
|---------|--------|
|
|||
|
|
| Zonas autoritativas de clientes (primario/secundario) | Ya funciona, mantener |
|
|||
|
|
| Zona vpn6.com.es (nombres WG peers) | Crear, automatizar |
|
|||
|
|
| Zonas PTR IPv6 (reverse DNS) | Crear, automatizar |
|
|||
|
|
| API REST para creacion automatica de registros | Activar/usar |
|
|||
|
|
|
|||
|
|
Alimentado por:
|
|||
|
|
- **wgdashboard**: al crear peer WG → API PowerDNS → AAAA + PTR en vpn6.com.es
|
|||
|
|
- **Netbox (netbox-dns plugin)**: VMs sincronizadas desde PVE → registros DNS automaticos
|
|||
|
|
- **Manual**: zonas de clientes como hasta ahora, evolucionando dominio a dominio
|
|||
|
|
|
|||
|
|
#### Componente 2: Technitium DNS (resolver con bloqueo)
|
|||
|
|
|
|||
|
|
**Solo como resolver**. No toca las zonas autoritativas (eso es PowerDNS).
|
|||
|
|
|
|||
|
|
Technitium resuelve consultas DNS de:
|
|||
|
|
- VMs de clientes
|
|||
|
|
- Usuarios WG (tecnicos, clientes remotos)
|
|||
|
|
- Mikrotiks de oficinas conectados por WG
|
|||
|
|
|
|||
|
|
Funcionalidades clave:
|
|||
|
|
- **Bloqueo multi-tenant**: cada cliente (identificado por rango IP WG) tiene su perfil de bloqueo
|
|||
|
|
- **Panel web nativo multi-usuario**: cada cliente puede entrar y ver sus queries, ajustar bloqueo
|
|||
|
|
- **Categorias de bloqueo**: malware, phishing, ads, adult, custom por cliente
|
|||
|
|
- **Dashboard de trafico DNS**: top dominios, queries bloqueadas, estadisticas
|
|||
|
|
- **API REST completa**: automatizable desde ICSManager/n8n
|
|||
|
|
- **DNSSEC validation**: verifica firmas DNS
|
|||
|
|
- **DoH/DoT upstream**: consultas cifradas a upstream (Cloudflare, Google)
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
VM cliente ──────►┌──────────────────────────┐
|
|||
|
|
│ Technitium DNS │
|
|||
|
|
WG usuario ──────►│ (resolver + bloqueo) │───► Upstream DoH
|
|||
|
|
│ │ (Cloudflare/Google)
|
|||
|
|
Mikrotik ────────►│ Panel por cliente: │
|
|||
|
|
│ - ACME: malware+ads ✅ │
|
|||
|
|
│ - BETA: solo malware ✅ │
|
|||
|
|
│ - GAMMA: todo ✅ │
|
|||
|
|
│ │
|
|||
|
|
│ Zonas internas: │
|
|||
|
|
│ → reenvio a PowerDNS │
|
|||
|
|
│ para *.vpn6.com.es │
|
|||
|
|
│ y zonas de clientes │
|
|||
|
|
└──────────────────────────┘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Technitium reenvia a PowerDNS las consultas de zonas internas:
|
|||
|
|
- `*.vpn6.com.es` → PowerDNS (nombres WG)
|
|||
|
|
- `*.cliente.com` → PowerDNS (si somos autoritativo)
|
|||
|
|
- Todo lo demas → upstream DoH (navegacion)
|
|||
|
|
|
|||
|
|
Recursos: 1-2 vCPU, 512MB-1GB RAM, contenedor Docker o VM ligera.
|
|||
|
|
|
|||
|
|
#### Componente 3: Naming automatico (toda IP tiene nombre)
|
|||
|
|
|
|||
|
|
Esquema de nombres sobre `vpn6.com.es` (dominio propio):
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
Tecnicos internos:
|
|||
|
|
laptop.david.vpn6.com.es → fdab:1234:vpn::42
|
|||
|
|
movil.david.vpn6.com.es → fdab:1234:vpn::43
|
|||
|
|
|
|||
|
|
Clientes (subdominio por cliente):
|
|||
|
|
oficina.acme.vpn6.com.es → fdab:1234:vpn:acme::1 (mikrotik)
|
|||
|
|
portatil.juan.acme.vpn6.com.es → fdab:1234:vpn:acme::10 (usuario)
|
|||
|
|
vm-web.acme.vpn6.com.es → fdab:1234:vpn:acme::100 (VM)
|
|||
|
|
|
|||
|
|
Infraestructura:
|
|||
|
|
pbs-1.mgmt.vpn6.com.es → fdab:1234:mgmt::10
|
|||
|
|
pve-2.mgmt.vpn6.com.es → fdab:1234:mgmt::20
|
|||
|
|
grafana.mgmt.vpn6.com.es → fdab:1234:mgmt::30
|
|||
|
|
|
|||
|
|
Con dominio del cliente (si lo pide):
|
|||
|
|
vpn.acme-empresa.com → CNAME a acme.vpn6.com.es
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Flujos de creacion automatica:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
wgdashboard crea peer
|
|||
|
|
→ nombre definido en el formulario
|
|||
|
|
→ API PowerDNS: crea AAAA + PTR
|
|||
|
|
→ El peer ya tiene rDNS + forward desde el momento 0
|
|||
|
|
|
|||
|
|
PVE crea VM
|
|||
|
|
→ netbox-proxmox sincroniza VM a Netbox
|
|||
|
|
→ netbox-dns genera registro en PowerDNS
|
|||
|
|
→ La VM ya tiene nombre DNS automatico
|
|||
|
|
|
|||
|
|
Ansible despliega servidor nuevo
|
|||
|
|
→ Playbook incluye task: registrar en PowerDNS via API
|
|||
|
|
→ Servidor tiene nombre desde el primer boot
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### Componente 4: Pagina de diagnostico self-service
|
|||
|
|
|
|||
|
|
Panel web donde el cliente entra (SSO Authentik) y ve su estado:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
┌─────────────────────────────────────────┐
|
|||
|
|
│ Diagnostico de conectividad │
|
|||
|
|
│ Cliente: ACME │
|
|||
|
|
│ │
|
|||
|
|
│ ✅ Tu IP: fdab:1234:vpn:acme::10 │
|
|||
|
|
│ ✅ WireGuard: conectado (handshake 3s) │
|
|||
|
|
│ ✅ DNS: resolviendo correctamente │
|
|||
|
|
│ ❌ Certificado PBS: caduca en 3 dias │
|
|||
|
|
│ ✅ PBS:8007: accesible (120ms) │
|
|||
|
|
│ ✅ Latencia WG: 12ms │
|
|||
|
|
│ ⚠️ Tunel IPsec oficina: no detectado │
|
|||
|
|
│ │
|
|||
|
|
│ [Copiar informe] [Abrir ticket] │
|
|||
|
|
└─────────────────────────────────────────┘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Implementacion: app web ligera (Flask/FastAPI, un contenedor Docker) que:
|
|||
|
|
1. Detecta IP origen → identifica cliente (via Netbox API o tabla local)
|
|||
|
|
2. Ejecuta checks en tiempo real contra los servicios de ese cliente
|
|||
|
|
3. Genera informe copiable para pegar en ticket
|
|||
|
|
4. Login via SSO Authentik
|
|||
|
|
|
|||
|
|
**Prioridad**: mes 3+, desarrollo propio. No es critico para arrancar.
|
|||
|
|
|
|||
|
|
#### Integracion PVE → DNS via Netbox
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
PVE API ──netbox-proxmox──► Netbox
|
|||
|
|
│
|
|||
|
|
│ VM con IP asignada
|
|||
|
|
▼
|
|||
|
|
netbox-dns plugin
|
|||
|
|
│
|
|||
|
|
│ Sincroniza zona en PowerDNS
|
|||
|
|
▼
|
|||
|
|
PowerDNS API
|
|||
|
|
│
|
|||
|
|
▼
|
|||
|
|
AAAA: vm-web.acme.vpn6.com.es
|
|||
|
|
PTR: fdab:...::100 → vm-web.acme.vpn6.com.es
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
No hay hookscripts fragiles en PVE. Netbox es el intermediario fiable. Si la VM existe en Netbox con IP, tiene DNS.
|
|||
|
|
|
|||
|
|
#### Arquitectura DNS completa
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
┌───────────────────────────────────────────────────────┐
|
|||
|
|
│ │
|
|||
|
|
│ AUTORITATIVO RESOLVER │
|
|||
|
|
│ ┌──────────────────┐ ┌──────────────────┐ │
|
|||
|
|
│ │ PowerDNS Auth │ │ Technitium DNS │ │
|
|||
|
|
│ │ (ya existente) │◄─reenvio──│ (nuevo) │ │
|
|||
|
|
│ │ │ zonas │ │ │
|
|||
|
|
│ │ Zonas clientes │ internas │ Resolver + │ │
|
|||
|
|
│ │ vpn6.com.es │ │ bloqueo multi- │ │
|
|||
|
|
│ │ PTR IPv6 │ │ tenant │ │
|
|||
|
|
│ │ │ │ │ │
|
|||
|
|
│ │ ← Netbox API │ │ Panel por │ │
|
|||
|
|
│ │ ← wgdashboard │ │ cliente nativo │ │
|
|||
|
|
│ │ ← Ansible │ │ │ │
|
|||
|
|
│ └──────────────────┘ │ Upstream: DoH │ │
|
|||
|
|
│ └──────────────────┘ │
|
|||
|
|
│ │
|
|||
|
|
│ NAMING AUTOMATICO DIAGNOSTICO │
|
|||
|
|
│ ┌──────────────────┐ ┌──────────────────┐ │
|
|||
|
|
│ │ Netbox (SSOT) │ │ Panel web ligero│ │
|
|||
|
|
│ │ + netbox-dns │ │ (Flask/FastAPI) │ │
|
|||
|
|
│ │ + netbox-proxmox│ │ SSO Authentik │ │
|
|||
|
|
│ │ → PowerDNS API │ │ Checks por │ │
|
|||
|
|
│ │ │ │ cliente │ │
|
|||
|
|
│ │ wgdashboard │ │ Mes 3+ │ │
|
|||
|
|
│ │ → PowerDNS API │ └──────────────────┘ │
|
|||
|
|
│ └──────────────────┘ │
|
|||
|
|
│ │
|
|||
|
|
└───────────────────────────────────────────────────────┘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### Recursos DNS
|
|||
|
|
|
|||
|
|
| Componente | CPU | RAM | Disco | Estado |
|
|||
|
|
|-----------|-----|-----|-------|--------|
|
|||
|
|
| PowerDNS Authoritative | existente | existente | existente | Ampliar zonas |
|
|||
|
|
| Technitium DNS (resolver) | 1 vCPU | 512 MB - 1 GB | 10 GB | Nuevo |
|
|||
|
|
| netbox-dns plugin | 0 (dentro de Netbox) | 0 | 0 | Configurar |
|
|||
|
|
| Panel diagnostico | incluido en VM servicios | ~100 MB | incluido | Mes 3+ |
|
|||
|
|
|
|||
|
|
#### Prioridades despliegue DNS
|
|||
|
|
|
|||
|
|
| Prioridad | Que | Esfuerzo |
|
|||
|
|
|-----------|-----|----------|
|
|||
|
|
| **Semana 1** | Technitium DNS como resolver basico (sin bloqueo aun) | 2h |
|
|||
|
|
| **Semana 1** | Crear zona vpn6.com.es en PowerDNS | 1h |
|
|||
|
|
| **Semana 2** | Automatizar AAAA+PTR desde wgdashboard → PowerDNS API | 4h |
|
|||
|
|
| **Semana 2** | Configurar Technitium: reenvio zonas internas a PowerDNS | 1h |
|
|||
|
|
| **Mes 1** | Configurar perfiles de bloqueo por cliente en Technitium | 2h |
|
|||
|
|
| **Mes 1** | netbox-proxmox + netbox-dns: auto-registro VMs | 1 dia |
|
|||
|
|
| **Mes 2** | Abrir panel Technitium a clientes (con SSO Authentik) | 2h |
|
|||
|
|
| **Mes 3+** | Panel de diagnostico self-service | 3-5 dias desarrollo |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 4.3 Proxy inverso y publicacion de servicios
|
|||
|
|
|
|||
|
|
### El problema
|
|||
|
|
|
|||
|
|
- Tendencia a eliminar IPv4: los clientes deben poder publicar servicios sin necesitar IP publica propia
|
|||
|
|
- Cada cliente que quiere exponer un servicio web necesita SSL, reverse proxy, y DNS
|
|||
|
|
- Hoy se hace con Traefik (ya en uso) pero sin un modelo sistematico
|
|||
|
|
- Los clientes deberian poder declarar "quiero publicar este servicio" y que se configure automaticamente
|
|||
|
|
|
|||
|
|
### Opciones evaluadas
|
|||
|
|
|
|||
|
|
| Herramienta | Autodiscovery | SSL auto | API | Estado |
|
|||
|
|
|-------------|--------------|---------|-----|--------|
|
|||
|
|
| **Traefik** | Docker labels, ficheros, API | Let's Encrypt nativo | REST | **ELEGIDA** (ya en uso) |
|
|||
|
|
| **Nginx Proxy Manager** | Manual (UI web) | Let's Encrypt | No | Descartada (manual) |
|
|||
|
|
| **HAProxy** | Config estatica | Manual o con ACME | Stats | Descartada (sin auto-SSL) |
|
|||
|
|
| **Caddy** | Caddyfile, API | Automatico por defecto | REST | Alternativa viable |
|
|||
|
|
|
|||
|
|
### DECISION 4.3 (confirmada)
|
|||
|
|
|
|||
|
|
#### Traefik como proxy inverso centralizado
|
|||
|
|
|
|||
|
|
Ya se usa. Se amplia como punto de publicacion de servicios para clientes.
|
|||
|
|
|
|||
|
|
#### Modelo: cliente declara servicio → Traefik lo expone
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
Cliente ACME quiere publicar:
|
|||
|
|
- Portal web: portal.acme.com
|
|||
|
|
- API: api.acme.com
|
|||
|
|
|
|||
|
|
Flujo:
|
|||
|
|
1. Cliente declara en panel (o ICSManager): "quiero publicar portal.acme.com"
|
|||
|
|
2. DNS: AAAA de portal.acme.com → IPv6 del Traefik
|
|||
|
|
3. Traefik: route portal.acme.com → VM del cliente (por WG IPv6)
|
|||
|
|
4. SSL: Let's Encrypt automatico
|
|||
|
|
5. Cliente solo tiene IPv6 WG, Traefik pone la cara publica
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### Arquitectura
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
Internet (IPv4+IPv6)
|
|||
|
|
│
|
|||
|
|
▼
|
|||
|
|
┌──────────────────────────────────────┐
|
|||
|
|
│ Traefik (proxy inverso) │
|
|||
|
|
│ │
|
|||
|
|
│ Escucha: │
|
|||
|
|
│ - IPv4 publica :443 (legacy) │
|
|||
|
|
│ - IPv6 publica :443 (preferido) │
|
|||
|
|
│ │
|
|||
|
|
│ Routes: │
|
|||
|
|
│ portal.acme.com → [fdab:..acme::100]:8080 │
|
|||
|
|
│ api.acme.com → [fdab:..acme::101]:3000 │
|
|||
|
|
│ grafana.mgmt.vpn6.com.es → [fdab:..mgmt::30]:3000 │
|
|||
|
|
│ │
|
|||
|
|
│ SSL: Let's Encrypt (automatico) │
|
|||
|
|
│ Middleware: rate limiting, headers │
|
|||
|
|
│ │
|
|||
|
|
│ Config: ficheros dinamicos │
|
|||
|
|
│ (generados por Ansible/API) │
|
|||
|
|
└──────────────────────────────────────┘
|
|||
|
|
│
|
|||
|
|
│ WG IPv6
|
|||
|
|
▼
|
|||
|
|
┌──────────────┐ ┌──────────────┐
|
|||
|
|
│ VM cliente │ │ VM cliente │
|
|||
|
|
│ portal ACME │ │ API ACME │
|
|||
|
|
│ (solo IPv6 │ │ (solo IPv6 │
|
|||
|
|
│ WG, sin IP │ │ WG, sin IP │
|
|||
|
|
│ publica) │ │ publica) │
|
|||
|
|
└──────────────┘ └──────────────┘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### Eliminacion progresiva de IPv4
|
|||
|
|
|
|||
|
|
La tendencia es que las VMs de clientes NO tengan IPv4 publica:
|
|||
|
|
|
|||
|
|
| Antes | Despues |
|
|||
|
|
|-------|---------|
|
|||
|
|
| Cada VM con IP publica | VM solo tiene IPv6 WG |
|
|||
|
|
| SSL configurado en cada VM | SSL centralizado en Traefik |
|
|||
|
|
| Firewall por VM | Firewall centralizado |
|
|||
|
|
| El cliente gestiona su SSL | Traefik gestiona Let's Encrypt |
|
|||
|
|
|
|||
|
|
Para clientes que aun necesiten IPv4 entrante (legacy):
|
|||
|
|
- Traefik escucha en IPv4 publica y reenvia a IPv6 WG del cliente
|
|||
|
|
- El cliente no necesita IPv4 propia
|
|||
|
|
- Transicion transparente
|
|||
|
|
|
|||
|
|
#### Configuracion dinamica
|
|||
|
|
|
|||
|
|
Traefik puede leer rutas de:
|
|||
|
|
- **Ficheros YAML** (generados por Ansible al dar de alta un servicio)
|
|||
|
|
- **Docker labels** (para servicios en Docker)
|
|||
|
|
- **API** (para automatizacion)
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
# /etc/traefik/dynamic/clientes/acme.yml
|
|||
|
|
# Generado automaticamente al dar de alta el servicio
|
|||
|
|
http:
|
|||
|
|
routers:
|
|||
|
|
portal-acme:
|
|||
|
|
rule: "Host(`portal.acme.com`)"
|
|||
|
|
service: portal-acme
|
|||
|
|
tls:
|
|||
|
|
certResolver: letsencrypt
|
|||
|
|
services:
|
|||
|
|
portal-acme:
|
|||
|
|
loadBalancer:
|
|||
|
|
servers:
|
|||
|
|
- url: "http://[fdab:1234:vpn:acme::100]:8080"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Flujo automatizado:
|
|||
|
|
```
|
|||
|
|
ICSManager/Panel → API → Ansible playbook
|
|||
|
|
→ Crea fichero YAML en Traefik
|
|||
|
|
→ Crea AAAA en PowerDNS
|
|||
|
|
→ Traefik recarga automaticamente (file watcher)
|
|||
|
|
→ Servicio publicado con SSL en segundos
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### Servicios internos via Traefik
|
|||
|
|
|
|||
|
|
Los paneles internos (Grafana, Netbox, Wazuh, etc.) tambien pasan por Traefik pero solo accesibles via WG:
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
# Servicios internos - solo escuchan en IPv6 WG
|
|||
|
|
http:
|
|||
|
|
routers:
|
|||
|
|
grafana:
|
|||
|
|
rule: "Host(`grafana.mgmt.vpn6.com.es`)"
|
|||
|
|
service: grafana
|
|||
|
|
tls:
|
|||
|
|
certResolver: letsencrypt
|
|||
|
|
netbox:
|
|||
|
|
rule: "Host(`netbox.mgmt.vpn6.com.es`)"
|
|||
|
|
service: netbox
|
|||
|
|
tls:
|
|||
|
|
certResolver: letsencrypt
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Accesibles solo desde la red WG de gestion. Desde internet: no alcanzable.
|
|||
|
|
|
|||
|
|
#### Recursos
|
|||
|
|
|
|||
|
|
| Componente | CPU | RAM | Disco |
|
|||
|
|
|-----------|-----|-----|-------|
|
|||
|
|
| Traefik | 1 vCPU | 256-512 MB | 5 GB |
|
|||
|
|
|
|||
|
|
Puede correr en la VM de servicios (como contenedor Docker) o en los WG Hubs. No necesita VM dedicada.
|
|||
|
|
|
|||
|
|
#### Prioridades despliegue proxy
|
|||
|
|
|
|||
|
|
| Prioridad | Que | Esfuerzo |
|
|||
|
|
|-----------|-----|----------|
|
|||
|
|
| **Semana 1** | Traefik para servicios internos (Grafana, Netbox, etc.) | 2h |
|
|||
|
|
| **Semana 2** | SSL automatico para servicios internos | 1h |
|
|||
|
|
| **Mes 1** | Primer servicio de cliente publicado via Traefik | 2h |
|
|||
|
|
| **Mes 2** | Template Ansible para alta automatica de servicios | 4h |
|
|||
|
|
| **Mes 3+** | Panel para que clientes declaren servicios | Desarrollo |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 4.4 Salida a internet: NAT CGNAT + política restrictiva
|
|||
|
|
|
|||
|
|
### El problema
|
|||
|
|
|
|||
|
|
Las VMs de clientes son IPv6-only (WG). Necesitan salida a internet para:
|
|||
|
|
- apt update / Docker pull
|
|||
|
|
- APIs externas
|
|||
|
|
- Navegación (si aplica)
|
|||
|
|
|
|||
|
|
Sin un mecanismo de salida, las VMs están aisladas. Pero dar salida sin control abre riesgos: un cliente puede enviar spam, hacer scraping, o abusar y provocar que la IP compartida se blacklistee.
|
|||
|
|
|
|||
|
|
### DECISION 4.4 (confirmada)
|
|||
|
|
|
|||
|
|
#### Dual-stack con IPv4 CGNAT para salida
|
|||
|
|
|
|||
|
|
Cada VM de cliente tiene dual-stack:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
VM de cliente:
|
|||
|
|
- IPv6 WG: fdab:1234:vpn:acme::10 → acceso entrante (RDP, SSH, servicios)
|
|||
|
|
- IPv4 CGNAT: 100.64.1.10/24 → solo salida NAT (navegar, apt, APIs)
|
|||
|
|
|
|||
|
|
Regla de oro:
|
|||
|
|
IPv4 = solo SALE, nunca ENTRA (outbound NAT)
|
|||
|
|
IPv6 = ENTRA controlado (el cliente/técnico accede vía WG)
|
|||
|
|
Web = publicado por Traefik (HTTP/HTTPS al mundo)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### Rango CGNAT (100.64.0.0/10)
|
|||
|
|
|
|||
|
|
Se usa el rango CGNAT (RFC 6598) en vez de RFC1918 para evitar colisiones con redes de oficina de clientes:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
100.64.0.0/10 total (~4 millones de IPs)
|
|||
|
|
|
|||
|
|
Asignación: /24 por cliente
|
|||
|
|
100.64.1.0/24 → Cliente ACME
|
|||
|
|
100.64.2.0/24 → Cliente BETA
|
|||
|
|
100.64.3.0/24 → Cliente GAMMA
|
|||
|
|
...
|
|||
|
|
100.64.254.0/24 → Cliente 254
|
|||
|
|
100.65.x.0/24 → Overflow si hace falta
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Ventaja sobre 10.x o 192.168.x: un cliente con oficina en 192.168.1.0/24 conectada por WG no tiene conflicto con la IP CGNAT de su VM.
|
|||
|
|
|
|||
|
|
#### Política de salida restrictiva (nftables en WG Hub)
|
|||
|
|
|
|||
|
|
```nft
|
|||
|
|
table ip filter {
|
|||
|
|
chain forward {
|
|||
|
|
type filter hook forward priority 0; policy drop;
|
|||
|
|
|
|||
|
|
# Tráfico establecido/relacionado
|
|||
|
|
ct state established,related accept
|
|||
|
|
|
|||
|
|
# --- PERMITIDO PARA TODOS ---
|
|||
|
|
ip saddr 100.64.0.0/10 tcp dport { 80, 443 } accept # Web
|
|||
|
|
ip saddr 100.64.0.0/10 udp dport { 53, 123 } accept # DNS, NTP
|
|||
|
|
ip saddr 100.64.0.0/10 tcp dport 53 accept # DNS TCP
|
|||
|
|
|
|||
|
|
# --- SMTP: BLOQUEADO POR DEFECTO ---
|
|||
|
|
ip saddr 100.64.0.0/10 tcp dport 25 drop # NUNCA
|
|||
|
|
|
|||
|
|
# Puerto 465/587: solo whitelist
|
|||
|
|
ip saddr 100.64.0.0/10 tcp dport { 465, 587 } ip daddr @smtp_whitelist accept
|
|||
|
|
|
|||
|
|
# --- RESTO: DENEGADO ---
|
|||
|
|
ip saddr 100.64.0.0/10 log prefix "CGNAT-BLOCKED: " drop
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
table ip nat {
|
|||
|
|
chain postrouting {
|
|||
|
|
type nat hook postrouting priority 100;
|
|||
|
|
# NAT compartido (base)
|
|||
|
|
ip saddr 100.64.0.0/10 oifname "eth0" masquerade
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# Whitelist SMTP
|
|||
|
|
set smtp_whitelist {
|
|||
|
|
type ipv4_addr
|
|||
|
|
flags interval
|
|||
|
|
elements = {
|
|||
|
|
# WildDuck propio (IP interna)
|
|||
|
|
100.64.0.0/10,
|
|||
|
|
# Añadir IPs de servicios de correo autorizados según necesidad
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### Puertos permitidos por defecto
|
|||
|
|
|
|||
|
|
| Puerto | Política | Razón |
|
|||
|
|
|--------|----------|-------|
|
|||
|
|
| 80, 443 | ✅ Permitido | Navegación, APIs, apt, Docker pulls |
|
|||
|
|
| 53, 123 | ✅ Permitido | DNS, NTP |
|
|||
|
|
| 25 | ✗ Bloqueado siempre | Prevenir spam. Sin excepciones. |
|
|||
|
|
| 465, 587 | ✅ Solo whitelist | SMTP autenticado a servidores conocidos |
|
|||
|
|
| Todo lo demás | ✗ Bloqueado | El cliente pide, se evalúa, se abre específicamente |
|
|||
|
|
|
|||
|
|
Logs de intentos bloqueados → Alloy → Loki. Visibles en Grafana.
|
|||
|
|
|
|||
|
|
#### Rate limiting por cliente
|
|||
|
|
|
|||
|
|
```nft
|
|||
|
|
# Evitar abuso incluso en puertos permitidos
|
|||
|
|
ip saddr 100.64.1.0/24 tcp dport { 80, 443 } limit rate 200/second burst 50 accept
|
|||
|
|
ip saddr 100.64.1.0/24 tcp dport { 80, 443 } drop
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### Definición de producto: base vs premium
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
SALIDA INTERNET (NAT) - Definición de producto
|
|||
|
|
─────────────────────────────────────────────────
|
|||
|
|
INCLUIDO (base):
|
|||
|
|
- Salida compartida: HTTP/HTTPS, DNS, NTP
|
|||
|
|
- SMTP solo a servidores autorizados (465/587 whitelist)
|
|||
|
|
- Puerto 25 bloqueado sin excepciones
|
|||
|
|
- IP pública compartida
|
|||
|
|
- IP puede cambiar sin preaviso
|
|||
|
|
- Sin garantía de reputación de IP
|
|||
|
|
- Política restrictiva no negociable
|
|||
|
|
|
|||
|
|
PREMIUM (contratación adicional):
|
|||
|
|
- IP dedicada fija con PTR personalizable
|
|||
|
|
- Si se blacklistea, solo afecta al cliente que la contrató
|
|||
|
|
- Apertura de puertos adicionales (previa evaluación)
|
|||
|
|
- Reglas firewall personalizadas
|
|||
|
|
- Rate limits ajustados
|
|||
|
|
─────────────────────────────────────────────────
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Implementación del premium:
|
|||
|
|
|
|||
|
|
```nft
|
|||
|
|
# Cliente ACME tiene IP dedicada (premium)
|
|||
|
|
ip saddr 100.64.1.0/24 oifname "eth0" snat to 1.2.3.101
|
|||
|
|
|
|||
|
|
# Resto de clientes: IP compartida
|
|||
|
|
ip saddr 100.64.0.0/10 oifname "eth0" snat to 1.2.3.100
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### Gestión
|
|||
|
|
|
|||
|
|
- Reglas nftables gestionadas con Ansible (un fichero por cliente, versionado en Forgejo)
|
|||
|
|
- Aperturas de puertos: el cliente solicita → se evalúa → se aplica con playbook → queda en git
|
|||
|
|
- Asignación de rangos CGNAT: en Netbox (IPAM), prefijo 100.64.X.0/24 asignado al tenant
|
|||
|
|
- Alertas: logs de tráfico bloqueado correlacionados con cliente en Grafana
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 4.5 Modelo de VMs: una VM = un servicio (caja negra)
|
|||
|
|
|
|||
|
|
### El problema
|
|||
|
|
|
|||
|
|
Si varios servicios con BBDD comparten una VM:
|
|||
|
|
- Un técnico trabajando en Zammad puede afectar a Netbox
|
|||
|
|
- Diagnosticar "qué consume IO" es complejo cuando hay 5 servicios mezclados
|
|||
|
|
- Migrar un servicio a otro servidor requiere separarlo primero
|
|||
|
|
- El backup de la VM incluye todo, no puedes restaurar solo un servicio
|
|||
|
|
|
|||
|
|
### DECISION 4.5 (confirmada)
|
|||
|
|
|
|||
|
|
**Cada servicio con estado (BBDD) tiene su propia VM.** Es una caja negra: todo lo que necesita está dentro (app + BBDD + Redis). Se backupea entera, se migra entera, se diagnostica de forma aislada.
|
|||
|
|
|
|||
|
|
#### Mapa de VMs por servicio
|
|||
|
|
|
|||
|
|
| VM | Contenido (todo Docker dentro) | BBDD | Stateful |
|
|||
|
|
|----|-------------------------------|------|----------|
|
|||
|
|
| **VM Zammad** | Zammad + PostgreSQL + Redis + Elasticsearch | PostgreSQL | Sí, VM dedicada |
|
|||
|
|
| **VM Authentik** | Authentik + PostgreSQL + Redis | PostgreSQL | Sí, VM dedicada |
|
|||
|
|
| **VM Netbox** | Netbox + PostgreSQL + Redis | PostgreSQL | Sí, VM dedicada |
|
|||
|
|
| **VM Outline** | Outline + PostgreSQL + Redis | PostgreSQL | Sí, VM dedicada |
|
|||
|
|
| **VM ICSManager** | ICSManager + PostgreSQL (todo Docker) | PostgreSQL | Sí, VM dedicada |
|
|||
|
|
| **VM WildDuck** | WildDuck + MongoDB + Redis (todo Docker) | MongoDB | Sí, VM dedicada |
|
|||
|
|
| **VM Servicios** | Semaphore, Uptime Kuma, Technitium, Traefik | Ninguna pesada | Stateless/ligeros |
|
|||
|
|
| **VM Monitoring** | VictoriaMetrics, Loki, Grafana, Alertmanager | Time-series | Ya dedicada |
|
|||
|
|
| **VM Wazuh** | Wazuh Manager + Dashboard (OpenSearch) | OpenSearch | Ya dedicada |
|
|||
|
|
|
|||
|
|
#### Ventajas operativas
|
|||
|
|
|
|||
|
|
| Aspecto | Servicios mezclados | Caja negra por servicio |
|
|||
|
|
|---------|-------------------|----------------------|
|
|||
|
|
| Diagnosticar | "¿Qué de los 5 servicios consume IO?" | "La VM Zammad consume IO → es Zammad" |
|
|||
|
|
| Migrar | Separar primero, luego mover | Mover la VM entera |
|
|||
|
|
| Backup/Restore | Todo o nada | Restauras solo Zammad sin tocar nada |
|
|||
|
|
| Un técnico trabaja | Con miedo de romper otros servicios | Libertad total dentro de su VM |
|
|||
|
|
| Actualizar | Coordinar 5 servicios | Actualizar uno, si falla, rollback VM |
|
|||
|
|
| Escalar | Dar más RAM a la VM afecta a todos | Dar más RAM solo a Zammad |
|
|||
|
|
|
|||
|
|
#### WildDuck y MongoDB
|
|||
|
|
|
|||
|
|
MongoDB dockerizado dentro de la VM WildDuck. De momento es correo interno del equipo técnico, volumen bajo. Si el correo se abre a más usuarios o el volumen crece significativamente, se revalúa:
|
|||
|
|
- MongoDB en VM dedicada (si el tamaño lo justifica)
|
|||
|
|
- O migración a servicio gestionado
|
|||
|
|
|
|||
|
|
Los tokens SMTP de WildDuck para avisos de PVE son operativamente críticos. El backup de la VM WildDuck los incluye automáticamente.
|
|||
|
|
|
|||
|
|
#### Impacto en dimensionamiento
|
|||
|
|
|
|||
|
|
La tabla actualizada de VMs:
|
|||
|
|
|
|||
|
|
| VM | vCPU | RAM | Disco |
|
|||
|
|
|----|------|-----|-------|
|
|||
|
|
| Monitoring | 4 | 8-12 GB | 200-500 GB |
|
|||
|
|
| Wazuh | 4 | 12 GB | 100 GB |
|
|||
|
|
| Zammad | 2-3 | 4-6 GB | 50 GB |
|
|||
|
|
| Authentik | 1-2 | 2-3 GB | 20 GB |
|
|||
|
|
| Netbox | 1-2 | 2-3 GB | 20 GB |
|
|||
|
|
| ICSManager | 1-2 | 2-3 GB | 20 GB |
|
|||
|
|
| WildDuck | 1-2 | 2-3 GB | 30-50 GB |
|
|||
|
|
| PMG | 1-2 | 2-3 GB | 20 GB |
|
|||
|
|
| PDM | 1-2 | 1-2 GB | 20 GB |
|
|||
|
|
| Outline | 1 | 1-2 GB | 20 GB |
|
|||
|
|
| Servicios (stateless) | 1-2 | 2-3 GB | 20 GB |
|
|||
|
|
| Bastion | 1 | 1 GB | 20 GB |
|
|||
|
|
| WG Hub A | 1 | 512 MB | 10 GB |
|
|||
|
|
| WG Hub B | 1 | 512 MB | 10 GB |
|
|||
|
|
| Forgejo | exist. | exist. | exist. |
|
|||
|
|
| **Total** | **~24-32 vCPU** | **~44-58 GB** | **~580-910 GB** |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 4.6 Proxmox Datacenter Manager (PDM)
|
|||
|
|
|
|||
|
|
### El problema
|
|||
|
|
|
|||
|
|
Con múltiples PVE en distintos DCs (Francia, potencialmente otros), la gestión es por nodo o por cluster. Si un cliente necesita mover una VM de un PVE a otro (por mantenimiento, por rendimiento, o por fallo), hay que hacerlo manualmente conectándose a cada PVE.
|
|||
|
|
|
|||
|
|
### DECISION 4.6 (confirmada)
|
|||
|
|
|
|||
|
|
**PDM como panel único de gestión multi-cluster.**
|
|||
|
|
|
|||
|
|
Proxmox Datacenter Manager permite:
|
|||
|
|
- Vista global de todos los nodos PVE y clusters en un solo panel
|
|||
|
|
- Migración de VMs entre clusters/nodos (lo que los clientes necesitan)
|
|||
|
|
- Gestión centralizada de recursos, storage, red
|
|||
|
|
- Planificación de capacidad a nivel de datacenter
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
┌─────────────────────┐
|
|||
|
|
│ PDM │
|
|||
|
|
│ (panel único) │
|
|||
|
|
└──────┬──────────────┘
|
|||
|
|
│
|
|||
|
|
┌────────────┼────────────┐
|
|||
|
|
│ │ │
|
|||
|
|
┌─────▼─────┐ ┌───▼──────┐ ┌──▼────────┐
|
|||
|
|
│ PVE-1 │ │ PVE-2 │ │ PVE-3 │
|
|||
|
|
│ Francia │ │ Francia │ │ Alemania │
|
|||
|
|
│ 20 VMs │ │ 15 VMs │ │ 10 VMs │
|
|||
|
|
└───────────┘ └──────────┘ └───────────┘
|
|||
|
|
|
|||
|
|
El técnico ve todo desde PDM. Puede migrar VM-web
|
|||
|
|
de PVE-1 a PVE-2 desde la misma interfaz.
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### Recursos
|
|||
|
|
|
|||
|
|
| Componente | CPU | RAM | Disco |
|
|||
|
|
|-----------|-----|-----|-------|
|
|||
|
|
| PDM (VM dedicada) | 1-2 vCPU | 1-2 GB | 20 GB |
|
|||
|
|
|
|||
|
|
VM dedicada (patrón caja negra). Ligero: es solo plano de gestión, no compute.
|
|||
|
|
|
|||
|
|
SSO con Authentik. Accesible solo vía WG (red de gestión).
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 4.7 Proxmox Mail Gateway (PMG)
|
|||
|
|
|
|||
|
|
### El problema
|
|||
|
|
|
|||
|
|
WildDuck gestiona el correo (buzones, IMAP, SMTP, tokens). Pero no tiene filtrado avanzado de spam ni antivirus. Si se abre el correo a más usuarios (más allá del equipo técnico), el volumen de spam y malware entrante será un problema.
|
|||
|
|
|
|||
|
|
### DECISION 4.7 (confirmada)
|
|||
|
|
|
|||
|
|
**PMG como gateway de filtrado delante de WildDuck.**
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
Internet (puerto 25)
|
|||
|
|
│
|
|||
|
|
▼
|
|||
|
|
┌──────────────────────┐
|
|||
|
|
│ PMG │
|
|||
|
|
│ Proxmox Mail Gateway │
|
|||
|
|
│ │
|
|||
|
|
│ - Anti-spam │
|
|||
|
|
│ (SpamAssassin) │
|
|||
|
|
│ - Anti-virus │
|
|||
|
|
│ (ClamAV) │
|
|||
|
|
│ - Greylisting │
|
|||
|
|
│ - SPF/DKIM/DMARC │
|
|||
|
|
│ - Cuarentena con UI │
|
|||
|
|
│ - Reglas por dominio │
|
|||
|
|
│ - Reglas por usuario │
|
|||
|
|
│ │
|
|||
|
|
│ Puerto 25 entrante │
|
|||
|
|
│ → filtra │
|
|||
|
|
│ → reenvía limpio a │
|
|||
|
|
│ WildDuck │
|
|||
|
|
└──────────┬───────────┘
|
|||
|
|
│ (email limpio)
|
|||
|
|
▼
|
|||
|
|
┌──────────────────────┐
|
|||
|
|
│ WildDuck │
|
|||
|
|
│ (buzones, IMAP, │
|
|||
|
|
│ tokens SMTP PVE) │
|
|||
|
|
└──────────────────────┘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### Funcionalidades clave
|
|||
|
|
|
|||
|
|
| Función | Qué hace |
|
|||
|
|
|---------|----------|
|
|||
|
|
| **Anti-spam** | SpamAssassin + reglas custom, scoring por mensaje |
|
|||
|
|
| **Anti-virus** | ClamAV, escanea adjuntos entrantes y salientes |
|
|||
|
|
| **Greylisting** | Retrasa primer intento desde IP desconocida (mata el 80% del spam) |
|
|||
|
|
| **SPF/DKIM/DMARC** | Verifica autenticidad del remitente |
|
|||
|
|
| **Cuarentena** | UI web donde el usuario ve mensajes filtrados y puede liberar falsos positivos |
|
|||
|
|
| **Reglas por dominio** | Políticas diferentes por dominio gestionado |
|
|||
|
|
| **Reporting** | Estadísticas: spam filtrado, virus detectados, volumen |
|
|||
|
|
|
|||
|
|
#### Email saliente
|
|||
|
|
|
|||
|
|
PMG también filtra salida: si un usuario comprometido envía spam, PMG lo detecta y bloquea antes de que salga y blacklistee la IP.
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
WildDuck (usuario envía)
|
|||
|
|
│
|
|||
|
|
▼
|
|||
|
|
┌──────────────────────┐
|
|||
|
|
│ PMG │
|
|||
|
|
│ - Verifica que no │
|
|||
|
|
│ sea spam saliente │
|
|||
|
|
│ - Firma DKIM │
|
|||
|
|
│ - Rate limiting │
|
|||
|
|
└──────────┬───────────┘
|
|||
|
|
│
|
|||
|
|
▼
|
|||
|
|
Internet (destino)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### Integración con el stack
|
|||
|
|
|
|||
|
|
| Integración | Qué aporta |
|
|||
|
|
|-------------|-----------|
|
|||
|
|
| PMG → Loki (logs) | Logs de spam filtrado, virus detectados → visibles en Grafana |
|
|||
|
|
| PMG → Alertmanager | Alerta si el volumen de spam sube anómalamente |
|
|||
|
|
| PMG → Wazuh | Eventos de seguridad (virus detectados) correlacionados |
|
|||
|
|
| PMG SSO Authentik | Panel de administración con cuenta unificada |
|
|||
|
|
| PMG cuarentena → usuario | El usuario accede vía web a su cuarentena |
|
|||
|
|
|
|||
|
|
#### Recursos
|
|||
|
|
|
|||
|
|
| Componente | CPU | RAM | Disco |
|
|||
|
|
|-----------|-----|-----|-------|
|
|||
|
|
| PMG (VM dedicada) | 1-2 vCPU | 2-3 GB | 20 GB |
|
|||
|
|
|
|||
|
|
ClamAV consume la mayor parte de la RAM (~1-1.5 GB para las firmas). SpamAssassin ligero. VM dedicada siguiendo patrón caja negra.
|
|||
|
|
|
|||
|
|
#### Prioridades
|
|||
|
|
|
|||
|
|
| Paso | Qué | Cuándo |
|
|||
|
|
|------|-----|--------|
|
|||
|
|
| Desplegar PMG con reglas básicas | Cuando WildDuck se abra a más usuarios |
|
|||
|
|
| Configurar DKIM signing | Junto con el despliegue |
|
|||
|
|
| Integrar logs PMG → Loki | Semana 1 post-despliegue |
|
|||
|
|
| Cuarentena accesible a usuarios | Junto con el despliegue |
|
|||
|
|
|
|||
|
|
No es urgente mientras WildDuck solo sirva al equipo técnico. **Se despliega cuando se amplíe el correo.**
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Resumen Capa 4 completa (DECISIONES FINALES)
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
┌─────────────────────────────────────────────────────┐
|
|||
|
|
│ CAPA 4: RED Y CONECTIVIDAD │
|
|||
|
|
├─────────────────────────────────────────────────────┤
|
|||
|
|
│ │
|
|||
|
|
│ 4.1 VPN (confirmada) │
|
|||
|
|
│ ┌───────────────────────────────────┐ │
|
|||
|
|
│ │ WireGuard + wgdashboard + IPv6 │ │
|
|||
|
|
│ │ │ │
|
|||
|
|
│ │ Rol 1: PBS = WG server (backups) │ │
|
|||
|
|
│ │ - Peers: solo PVEs con storage │ │
|
|||
|
|
│ │ - Sin forwarding (aislados) │ │
|
|||
|
|
│ │ │ │
|
|||
|
|
│ │ Rol 2: WG Hub HA (clientes) │ │
|
|||
|
|
│ │ - Par HA keepalived │ │
|
|||
|
|
│ │ - Tecnicos + clientes + VMs │ │
|
|||
|
|
│ │ - nftables aislamiento/cliente │ │
|
|||
|
|
│ │ - wgdashboard (UI + API) │ │
|
|||
|
|
│ │ - Reemplaza 1-GW-por-cliente │ │
|
|||
|
|
│ │ │ │
|
|||
|
|
│ │ Rol 3: Mesh gestion (vRack) │ │
|
|||
|
|
│ │ - WG cifrado sobre vRack 25Gbps │ │
|
|||
|
|
│ │ - Servicios internos solo aqui │ │
|
|||
|
|
│ │ │ │
|
|||
|
|
│ │ Direccionamiento: IPv6 ULA │ │
|
|||
|
|
│ │ fdab:1234:bkp::/48 (backups) │ │
|
|||
|
|
│ │ fdab:1234:vpn::/48 (clientes) │ │
|
|||
|
|
│ │ fdab:1234:mgmt::/48 (gestion) │ │
|
|||
|
|
│ └───────────────────────────────────┘ │
|
|||
|
|
│ │
|
|||
|
|
│ 4.2 DNS (confirmada) │
|
|||
|
|
│ ┌───────────────────────────────────┐ │
|
|||
|
|
│ │ PowerDNS Auth (ya existente) │ │
|
|||
|
|
│ │ - Zonas clientes (pri/sec) │ │
|
|||
|
|
│ │ - vpn6.com.es (nombres WG) │ │
|
|||
|
|
│ │ - PTR IPv6 │ │
|
|||
|
|
│ │ - ← Netbox + wgdashboard API │ │
|
|||
|
|
│ │ │ │
|
|||
|
|
│ │ Technitium DNS (resolver nuevo) │ │
|
|||
|
|
│ │ - Resolver + bloqueo multi-tenant│ │
|
|||
|
|
│ │ - Panel web por cliente │ │
|
|||
|
|
│ │ - Perfiles: malware/ads/adult │ │
|
|||
|
|
│ │ - Reenvio zonas internas → PDNS │ │
|
|||
|
|
│ │ │ │
|
|||
|
|
│ │ Naming automatico: │ │
|
|||
|
|
│ │ - wgdashboard → PDNS API │ │
|
|||
|
|
│ │ - Netbox → netbox-dns → PDNS │ │
|
|||
|
|
│ │ - PVE → Netbox → DNS automatico │ │
|
|||
|
|
│ │ │ │
|
|||
|
|
│ │ Panel diagnostico (mes 3+) │ │
|
|||
|
|
│ │ - Self-service checks cliente │ │
|
|||
|
|
│ └───────────────────────────────────┘ │
|
|||
|
|
│ │
|
|||
|
|
│ 4.3 PROXY INVERSO (confirmada) │
|
|||
|
|
│ ┌───────────────────────────────────┐ │
|
|||
|
|
│ │ Traefik (ya en uso, ampliar) │ │
|
|||
|
|
│ │ - Proxy inverso centralizado │ │
|
|||
|
|
│ │ - SSL Let's Encrypt automatico │ │
|
|||
|
|
│ │ - Clientes declaran servicio → │ │
|
|||
|
|
│ │ Traefik lo publica │ │
|
|||
|
|
│ │ - VMs sin IPv4 publica │ │
|
|||
|
|
│ │ (Traefik pone la cara publica) │ │
|
|||
|
|
│ │ - Config YAML dinamica via │ │
|
|||
|
|
│ │ Ansible/API │ │
|
|||
|
|
│ │ - Servicios internos solo via WG │ │
|
|||
|
|
│ └───────────────────────────────────┘ │
|
|||
|
|
│ │
|
|||
|
|
│ 4.4 SALIDA INTERNET NAT (confirmada) │
|
|||
|
|
│ ┌───────────────────────────────────┐ │
|
|||
|
|
│ │ Dual-stack por VM: │ │
|
|||
|
|
│ │ - IPv4 CGNAT (100.64.x.x/24) │ │
|
|||
|
|
│ │ solo salida NAT, nunca entra │ │
|
|||
|
|
│ │ - IPv6 WG: acceso entrante │ │
|
|||
|
|
│ │ │ │
|
|||
|
|
│ │ Política restrictiva: │ │
|
|||
|
|
│ │ - 80,443,53,123: permitido │ │
|
|||
|
|
│ │ - Puerto 25: BLOQUEADO siempre │ │
|
|||
|
|
│ │ - 465,587: solo whitelist SMTP │ │
|
|||
|
|
│ │ - Resto: bloqueado por defecto │ │
|
|||
|
|
│ │ │ │
|
|||
|
|
│ │ Producto base: IP compartida │ │
|
|||
|
|
│ │ (puede cambiar sin preaviso) │ │
|
|||
|
|
│ │ Premium: IP dedicada fija │ │
|
|||
|
|
│ └───────────────────────────────────┘ │
|
|||
|
|
│ │
|
|||
|
|
│ 4.5 MODELO VMs (confirmada) │
|
|||
|
|
│ ┌───────────────────────────────────┐ │
|
|||
|
|
│ │ Una VM = un servicio (caja negra)│ │
|
|||
|
|
│ │ App + BBDD + Redis todo dentro │ │
|
|||
|
|
│ │ - Zammad, Authentik, Netbox, │ │
|
|||
|
|
│ │ ICSManager, WildDuck, Outline │ │
|
|||
|
|
│ │ cada uno en su VM dedicada │ │
|
|||
|
|
│ │ - Backup/migración: VM entera │ │
|
|||
|
|
│ │ - Diagnóstico aislado │ │
|
|||
|
|
│ │ - Total: ~24-32 vCPU, 44-58 GB │ │
|
|||
|
|
│ └───────────────────────────────────┘ │
|
|||
|
|
│ │
|
|||
|
|
│ 4.6 PDM (confirmada) │
|
|||
|
|
│ ┌───────────────────────────────────┐ │
|
|||
|
|
│ │ Proxmox Datacenter Manager │ │
|
|||
|
|
│ │ - Gestión multi-cluster PVE │ │
|
|||
|
|
│ │ - Migración VMs entre PVEs │ │
|
|||
|
|
│ │ - Vista global de recursos │ │
|
|||
|
|
│ │ - SSO Authentik, solo via WG │ │
|
|||
|
|
│ │ - VM dedicada: 1-2 vCPU, 1-2GB │ │
|
|||
|
|
│ └───────────────────────────────────┘ │
|
|||
|
|
│ │
|
|||
|
|
│ 4.7 PMG (confirmada, desplegar al ampliar correo) │
|
|||
|
|
│ ┌───────────────────────────────────┐ │
|
|||
|
|
│ │ Proxmox Mail Gateway │ │
|
|||
|
|
│ │ - Anti-spam (SpamAssassin) │ │
|
|||
|
|
│ │ - Anti-virus (ClamAV) │ │
|
|||
|
|
│ │ - SPF/DKIM/DMARC │ │
|
|||
|
|
│ │ - Greylisting │ │
|
|||
|
|
│ │ - Cuarentena con UI web │ │
|
|||
|
|
│ │ - Filtro saliente (anti-spam) │ │
|
|||
|
|
│ │ - Delante de WildDuck │ │
|
|||
|
|
│ │ - VM dedicada: 1-2 vCPU, 2-3GB │ │
|
|||
|
|
│ └───────────────────────────────────┘ │
|
|||
|
|
│ │
|
|||
|
|
└─────────────────────────────────────────────────────┘
|
|||
|
|
|
|||
|
|
Recursos Capa 4:
|
|||
|
|
- WG Hub A: 1 vCPU, 512 MB RAM, 10 GB disco
|
|||
|
|
- WG Hub B: 1 vCPU, 512 MB RAM, 10 GB disco
|
|||
|
|
- Technitium DNS: 1 vCPU, 512 MB - 1 GB RAM (en VM Servicios)
|
|||
|
|
- Traefik: contenedor Docker, 256-512 MB RAM (en VM Servicios)
|
|||
|
|
- PDM: 1-2 vCPU, 1-2 GB RAM, 20 GB disco
|
|||
|
|
- PMG: 1-2 vCPU, 2-3 GB RAM, 20 GB disco
|
|||
|
|
- PowerDNS: ya existente
|
|||
|
|
- WG en servidores: kernel module, 0 extra
|
|||
|
|
- NAT CGNAT: en WG Hub (nftables, 0 extra)
|
|||
|
|
|
|||
|
|
Dimensionamiento revisado (todas las VMs de gestión):
|
|||
|
|
~24-32 vCPU, ~44-58 GB RAM, ~580-910 GB disco
|
|||
|
|
Recomendación servidor: 128 GB RAM, 8-12c/16-24t, 2×2TB NVMe
|
|||
|
|
```
|