capítulo 04
Exposição & Dashboard
Abrindo o honeypot pra internet de verdade, e montando o painel que mostra o que chega.
Verificar CGNAT antes de tudo
Provedores residenciais (fibra, principalmente) às vezes não entregam IP público real — o cliente fica atrás de um NAT compartilhado da própria operadora (CGNAT). Se for o caso, nenhum port-forward vai funcionar, não importa quão certa esteja a configuração.
curl -4 ifconfig.me
Depois, de um navegador na mesma rede, abra canyouseeme.org, digite a porta que pretende expor e clique em Check. Isso confirma se o forward está alcançável de fora antes de gastar tempo depurando algo que pode ser estruturalmente impossível do seu lado.
Se confirmar CGNAT, port-forward tradicional não resolve — as alternativas são pedir IP público ao provedor, ou usar um túnel reverso (Cloudflare Tunnel, por exemplo), o que muda a arquitetura deste guia.
Configurar o encaminhamento de porta
No painel do seu roteador (nome do menu varia por fabricante: Port Forwarding, Virtual Server, NAT, Encaminhamento de Portas), crie duas regras:
| Campo | Regra SSH | Regra Telnet |
|---|---|---|
| Porta externa | 22 | 23 |
| Porta interna | 2222 | 2223 |
| IP interno | IP_DA_VM | |
| Protocolo | TCP | |
Teste de fora de verdade (dados móveis, não Wi-Fi da mesma rede):
ssh -p 22 root@SEU_IP_PUBLICO
Deve cair no shell falso do Cowrie.
Centralizar logs: Grafana Alloy
O agente que lê os arquivos de log e envia pro banco de dados de logs (Loki) roda nativo na VM — não em container, pelo mesmo motivo do Suricata: precisa de acesso direto ao sistema de arquivos.
O agente tradicionalmente usado com o Loki (Promtail) foi descontinuado — o substituto oficial é o Grafana Alloy, que usa uma linguagem de configuração própria (River) em vez de YAML.
sudo mkdir -p /etc/apt/keyrings
sudo wget -qO /etc/apt/keyrings/grafana.asc https://apt.grafana.com/gpg-full.key
sudo chmod 644 /etc/apt/keyrings/grafana.asc
echo "deb [signed-by=/etc/apt/keyrings/grafana.asc] https://apt.grafana.com stable main" | sudo tee /etc/apt/sources.list.d/grafana.list
sudo apt update
sudo apt install -y alloy
local.file_match "suricata" {
path_targets = [{"__path__" = "/var/log/suricata/eve.json", "job" = "suricata"}]
}
local.file_match "cowrie" {
path_targets = [{"__path__" = "/var/lib/docker/volumes/cowrie-honeypot_cowrie-var/_data/log/cowrie/cowrie.json", "job" = "cowrie"}]
}
loki.source.file "suricata_tail" {
targets = local.file_match.suricata.targets
forward_to = [loki.write.local.receiver]
}
loki.source.file "cowrie_tail" {
targets = local.file_match.cowrie.targets
forward_to = [loki.write.local.receiver]
}
loki.write "local" {
endpoint {
url = "http://127.0.0.1:3100/loki/api/v1/push"
}
}
O Alloy roda como usuário de sistema próprio (alloy), não root. A pasta /var/lib/docker normalmente vem com permissão drwx--x--- — só root e o grupo root atravessam. Isso bloqueia o Alloy de chegar no log do Cowrie, mesmo o arquivo final estando com leitura liberada. Resolva com uma ACL pontual, sem abrir a pasta pra mais ninguém:
sudo setfacl -m u:alloy:x /var/lib/docker
getfacl /var/lib/docker | grep alloy # confirma: user:alloy:--x
sudo systemctl enable --now alloy
sudo journalctl -u alloy --since "30 seconds ago" --no-pager | grep -i tailing
Devem aparecer duas linhas "start tailing file" — uma pro Suricata, uma pro Cowrie.
Loki + Grafana
Os dois rodam em containers separados, então precisam de uma rede Docker compartilhada pra se enxergarem — 127.0.0.1 de dentro de um container aponta pra ele mesmo, não pro vizinho.
docker network create dashboard-net
mkdir -p ~/honeypot-dashboard && cd ~/honeypot-dashboard
wget https://raw.githubusercontent.com/grafana/loki/v3.7.0/cmd/loki/loki-local-config.yaml -O loki-config.yaml
docker run --name loki -d \
--network dashboard-net \
-v $(pwd):/mnt/config \
-p 127.0.0.1:3100:3100 \
grafana/loki:3.7.0 -config.file=/mnt/config/loki-config.yaml
docker run --name grafana -d \
--network dashboard-net \
-p 127.0.0.1:3000:3000 \
grafana/grafana:latest
# garanta que sobrevivem a um reboot da VM
docker update --restart unless-stopped loki grafana
Dentro da mesma rede Docker, os containers se resolvem pelo nome via DNS interno — use http://loki:3100 como URL do Data Source no Grafana, não 127.0.0.1.
Acesse o Grafana (que está só em 127.0.0.1) via túnel SSH:
ssh -p 2200 -L 3000:127.0.0.1:3000 usuario@IP_DA_VM
Com o túnel aberto, acesse http://localhost:3000 no navegador da sua máquina.
Montando os painéis
- Connections → Data sources → Add data source → Loki, URL
http://loki:3100, Save & test. - Dashboards → New → New Dashboard → Add visualization, escolha Loki como fonte.
- No editor da query, clique em Code (o modo padrão é visual e não aceita colar a query direto) e cole uma das consultas abaixo.
Tentativas no honeypot ao longo do tempo
Tipo de visualização: Time series.
sum(count_over_time({job="cowrie"}[5m]))
Alertas do Suricata por severidade
Tipo de visualização: Bar chart.
sum by (severity) (count_over_time({job="suricata"} | json | alert_severity != "" [5m]))
Top IPs de origem
Tipo de visualização: Table.
topk(10, sum by (src_ip) (count_over_time({job="cowrie"} | json [1h])))
O painel de severidade provavelmente fica vazio no início — o ruleset padrão do Suricata dispara mais por padrão/contagem (várias tentativas de brute-force num intervalo, por exemplo) do que por conexão isolada. Ele começa a preencher conforme tráfego real de ataque for chegando.