Configuração de firewall
Quais portas o HeroCtl usa, quais precisam ficar abertas, e quais nunca deveriam ser expostas à internet.
Um cluster HeroCtl saudável tem um conjunto pequeno e fixo de portas. Este documento mostra quais são, o que faz cada uma, e como configurar o firewall do sistema operacional para liberar exatamente o necessário, nem mais nem menos.
Portas em uso
| Porta | Protocolo | Função | Quem precisa acessar |
|---|---|---|---|
| 80 | TCP | Roteador de ingress (HTTP) | Internet inteira |
| 443 | TCP | Roteador de ingress (HTTPS) | Internet inteira |
| 8080 | TCP | API do plano de controle | Operadores e CLI, via VPN ou allowlist |
| 8443 | TCP | Painel web TLS | Operadores, via VPN ou allowlist |
| 4646 | TCP | Coordenação interna entre nós (consenso) | Apenas outros nós do cluster |
| 4647 | TCP | RPC entre coordenador e workers | Apenas outros nós do cluster |
| 4648 | TCP+UDP | Gossip entre nós | Apenas outros nós do cluster |
A regra geral é simples:
- 80 e 443 abrem para o mundo. É o ponto de entrada das suas aplicações.
- 8080 e 8443 nunca deveriam estar abertas para a internet pública.
- 4646, 4647 e 4648 ficam restritas aos IPs internos do cluster.
Atenção: Expor 8080 sem allowlist é o erro de configuração mais comum em clusters novos. Qualquer pessoa com o token admin pode submeter jobs. Trate essa porta como SSH.
Topologia recomendada
internet
│
┌─────┴─────┐
│ 80, 443 │ ← qualquer origem
└─────┬─────┘
│
┌───────┴───────┐
│ nós do │
│ cluster │
└───────┬───────┘
│
┌─────┴─────┐
│ 4646-4648 │ ← apenas IPs internos
└───────────┘
│
┌─────┴─────┐
│ 8080,8443 │ ← apenas VPN ou allowlist
└───────────┘
Ubuntu e Debian (ufw)
Configuração mínima para um nó 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
Em nós que são apenas worker (sem painel exposto), pule as linhas 8080 e 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 direto
Se você prefere regras explícitas, ou usa um sistema sem 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 em camada de cima
Mesmo com ufw correto em cada nó, vale ativar o firewall do provedor de nuvem como segunda camada. Se o ufw cair por mudança errada, o cloud firewall continua segurando.
DigitalOcean Cloud Firewall
Crie uma firewall e atribua a todas as droplets do cluster:
| Direção | Tipo | Origem | Porta |
|---|---|---|---|
| Inbound | TCP | Anywhere | 80, 443 |
| Inbound | TCP | IPs do operador | 22, 8080, 8443 |
| Inbound | TCP | Tag heroctl-cluster | 4646, 4647, 4648 |
| Inbound | UDP | Tag heroctl-cluster | 4648 |
| Outbound | All | Anywhere | All |
Use tags em vez de IPs para 4646-4648 — quando você adiciona um nó novo com a tag, ele já entra na regra.
AWS Security Groups
Crie dois security groups:
heroctl-public: 80 e 443 de0.0.0.0/0. Atribua a todos os nós.heroctl-cluster: 4646-4648 com origem no próprio security group (self-reference). Para 8080 e 8443, source no security group da bastion.
Hetzner Cloud Firewall
Hetzner não tem self-reference. Use a rede privada do projeto e libere 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 na frente
Para proteção contra ataques volumétricos, colocar Cloudflare em modo proxy na frente do cluster funciona bem. Pontos de atenção:
- Para emissão de certificado, use DNS-01 (não HTTP-01). O modo proxy quebra HTTP-01.
- Restrinja 80 e 443 dos nós para aceitarem apenas os ranges de IP da Cloudflare. A lista oficial fica em
https://www.cloudflare.com/ips-v4. Atualize via cron mensal. - Habilite "Full (strict)" no Cloudflare. Não use "Flexible" — isso faz a Cloudflare falar HTTP com seu cluster mesmo o usuário tendo HTTPS.
Bloqueando acesso administrativo
A regra mais importante deste documento. A porta 8080 não pode estar acessível pela internet pública. Três caminhos viáveis:
- VPN. WireGuard ou Tailscale entre máquinas dos operadores e o cluster. Bloqueia 8080 para qualquer origem fora da rede da VPN. Recomendado para times.
- Allowlist por IP fixo. Funciona para operador solo com IP residencial estável ou VPS bastion.
- SSH tunnel.
ssh -L 8080:localhost:8080 servidorcada vez que for usar a CLI. Funciona, mas atrita.
A combinação que mais aparece em produção é VPN + cloud firewall. Operador entra na VPN, cloud firewall só libera 8080 para o range da VPN, e o ufw do nó faz a mesma coisa por dentro.
Validação
Depois de aplicar as regras, valide de fora:
# da sua máquina, sem VPN, contra um IP do cluster
nmap -p 80,443,8080,8443,4646,4647,4648 <ip-do-no>
Resultado correto: 80 e 443 abertas, todas as outras fechadas (closed ou filtered).
Próximos passos
- Configurar ingress e TLS para começar a expor aplicações.
- Revisar gerenciamento de segredos.