Configuración de firewall
Qué puertos usa HeroCtl, cuáles necesitan estar abiertos y cuáles nunca deberían exponerse a internet.
Un cluster HeroCtl saludable tiene un conjunto pequeño y fijo de puertos. Este documento muestra cuáles son, qué hace cada uno y cómo configurar el firewall del sistema operativo para liberar exactamente lo necesario, ni más ni menos.
Puertos en uso
| Puerto | Protocolo | Función | Quién necesita acceder |
|---|---|---|---|
| 80 | TCP | Router de ingress (HTTP) | Internet entera |
| 443 | TCP | Router de ingress (HTTPS) | Internet entera |
| 8080 | TCP | API del plano de control | Operadores y CLI, vía VPN o allowlist |
| 8443 | TCP | Panel web TLS | Operadores, vía VPN o allowlist |
| 4646 | TCP | Coordinación interna entre nodos (consenso) | Solo otros nodos del cluster |
| 4647 | TCP | RPC entre coordinador y workers | Solo otros nodos del cluster |
| 4648 | TCP+UDP | Gossip entre nodos | Solo otros nodos del cluster |
La regla general es simple:
- 80 y 443 abren al mundo. Es el punto de entrada de tus aplicaciones.
- 8080 y 8443 nunca deberían estar abiertas a internet pública.
- 4646, 4647 y 4648 quedan restringidas a los IPs internos del cluster.
Atención: Exponer 8080 sin allowlist es el error de configuración más común en clusters nuevos. Cualquier persona con el token admin puede enviar jobs. Trata ese puerto como SSH.
Topología recomendada
internet
│
┌─────┴─────┐
│ 80, 443 │ ← cualquier origen
└─────┬─────┘
│
┌───────┴───────┐
│ nós do │
│ cluster │
└───────┬───────┘
│
┌─────┴─────┐
│ 4646-4648 │ ← apenas IPs internos
└───────────┘
│
┌─────┴─────┐
│ 8080,8443 │ ← apenas VPN ou allowlist
└───────────┘
Ubuntu y Debian (ufw)
Configuración mínima para un nodo servidor:
# regras default
sudo ufw default deny incoming
sudo ufw default allow outgoing
# acesso administrativo (ajuste o IP de origem)
sudo ufw allow from 203.0.113.10 to any port 22 proto tcp comment 'SSH operador'
sudo ufw allow from 203.0.113.10 to any port 8080 proto tcp comment 'API'
sudo ufw allow from 203.0.113.10 to any port 8443 proto tcp comment 'Painel'
# tráfego público
sudo ufw allow 80/tcp comment 'Ingress HTTP'
sudo ufw allow 443/tcp comment 'Ingress HTTPS'
# comunicação interna entre nós (substitua pelos IPs reais)
for ip in 10.0.0.1 10.0.0.2 10.0.0.3 10.0.0.4; do
sudo ufw allow from $ip to any port 4646 proto tcp
sudo ufw allow from $ip to any port 4647 proto tcp
sudo ufw allow from $ip to any port 4648
done
sudo ufw enable
sudo ufw status numbered
En nodos que son solo worker (sin panel expuesto), salta las líneas 8080 y 8443.
RHEL, Fedora, AlmaLinux (firewalld)
# zonas separadas: pública para 80/443, interna para portas de cluster
sudo firewall-cmd --permanent --zone=public --add-service=http
sudo firewall-cmd --permanent --zone=public --add-service=https
# zona internal recebe os IPs do cluster
sudo firewall-cmd --permanent --zone=internal --add-source=10.0.0.0/24
sudo firewall-cmd --permanent --zone=internal --add-port=4646/tcp
sudo firewall-cmd --permanent --zone=internal --add-port=4647/tcp
sudo firewall-cmd --permanent --zone=internal --add-port=4648/tcp
sudo firewall-cmd --permanent --zone=internal --add-port=4648/udp
# acesso admin: zone trusted com IP do operador
sudo firewall-cmd --permanent --zone=trusted --add-source=203.0.113.10
sudo firewall-cmd --permanent --zone=trusted --add-port=8080/tcp
sudo firewall-cmd --permanent --zone=trusted --add-port=8443/tcp
sudo firewall-cmd --reload
sudo firewall-cmd --list-all-zones
iptables directo
Si prefieres reglas explícitas, o usas un sistema sin ufw/firewalld:
# tráfego estabelecido
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT
# ingress público
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
# admin restrito
iptables -A INPUT -p tcp -s 203.0.113.10 --dport 22 -j ACCEPT
iptables -A INPUT -p tcp -s 203.0.113.10 --dport 8080 -j ACCEPT
iptables -A INPUT -p tcp -s 203.0.113.10 --dport 8443 -j ACCEPT
# cluster interno (repita para cada IP)
iptables -A INPUT -p tcp -s 10.0.0.0/24 --dport 4646 -j ACCEPT
iptables -A INPUT -p tcp -s 10.0.0.0/24 --dport 4647 -j ACCEPT
iptables -A INPUT -p tcp -s 10.0.0.0/24 --dport 4648 -j ACCEPT
iptables -A INPUT -p udp -s 10.0.0.0/24 --dport 4648 -j ACCEPT
# default deny
iptables -P INPUT DROP
# persistir
sudo netfilter-persistent save
Cloud firewall en capa superior
Aun con ufw correcto en cada nodo, vale activar el firewall del proveedor de nube como segunda capa. Si el ufw cae por un cambio mal hecho, el cloud firewall sigue protegiendo.
DigitalOcean Cloud Firewall
Crea un firewall y asígnalo a todas las droplets del cluster:
| Dirección | Tipo | Origen | Puerto |
|---|---|---|---|
| Inbound | TCP | Anywhere | 80, 443 |
| Inbound | TCP | IPs del operador | 22, 8080, 8443 |
| Inbound | TCP | Tag heroctl-cluster | 4646, 4647, 4648 |
| Inbound | UDP | Tag heroctl-cluster | 4648 |
| Outbound | All | Anywhere | All |
Usa tags en vez de IPs para 4646-4648 — cuando agregas un nodo nuevo con la tag, ya entra en la regla.
AWS Security Groups
Crea dos security groups:
heroctl-public: 80 y 443 desde0.0.0.0/0. Asígnalo a todos los nodos.heroctl-cluster: 4646-4648 con origen en el propio security group (self-reference). Para 8080 y 8443, source en el security group del bastion.
Hetzner Cloud Firewall
Hetzner no tiene self-reference. Usa la red privada del proyecto y libera por CIDR:
allow tcp 80,443 from 0.0.0.0/0
allow tcp 4646,4647,4648 from 10.0.0.0/16
allow udp 4648 from 10.0.0.0/16
allow tcp 8080,8443 from <ip-do-operador>/32
Cloudflare al frente
Para protección contra ataques volumétricos, poner Cloudflare en modo proxy delante del cluster funciona bien. Puntos a tener en cuenta:
- Para emisión de certificado, usa DNS-01 (no HTTP-01). El modo proxy rompe HTTP-01.
- Restringe 80 y 443 de los nodos para que acepten solo los rangos de IP de Cloudflare. La lista oficial está en
https://www.cloudflare.com/ips-v4. Actualiza vía cron mensual. - Habilita "Full (strict)" en Cloudflare. No uses "Flexible" — eso hace que Cloudflare hable HTTP con tu cluster aunque el usuario tenga HTTPS.
Bloqueando acceso administrativo
La regla más importante de este documento. El puerto 8080 no puede estar accesible desde internet pública. Tres caminos viables:
- VPN. WireGuard o Tailscale entre máquinas de los operadores y el cluster. Bloquea 8080 para cualquier origen fuera de la red de la VPN. Recomendado para equipos.
- Allowlist por IP fijo. Funciona para operador solo con IP residencial estable o VPS bastion.
- SSH tunnel.
ssh -L 8080:localhost:8080 servidorcada vez que vayas a usar la CLI. Funciona, pero genera fricción.
La combinación que más aparece en producción es VPN + cloud firewall. El operador entra en la VPN, el cloud firewall solo libera 8080 para el rango de la VPN, y el ufw del nodo hace lo mismo por dentro.
Validación
Después de aplicar las reglas, valida desde fuera:
# da sua máquina, sem VPN, contra um IP do cluster
nmap -p 80,443,8080,8443,4646,4647,4648 <ip-do-no>
Resultado correcto: 80 y 443 abiertas, todas las demás cerradas (closed o filtered).
Próximos pasos
- Configurar ingress y TLS para empezar a exponer aplicaciones.
- Revisar gestión de secretos.