Zero Trust na Prática: Como Eliminei VPN Corporativa e Fiz Cada Servidor Se Autenticar Individualmente
Eu gastava 40 minutos por semana só mantendo uma VPN OpenVPN viva. Certificados expirados, rotas que sumiam depois de reboot, clientes que conectavam mas não acessavam nada — a clássica experiência de “tá conectado mas não funciona”. E o pior: quando alguém conseguia acessar a VPN, tinha acesso a tudo. Cada servidor, cada porta, cada banco de dados. Um convite aberto para o desastre.
Até que um dia eu percebi: minha rede interna era menos segura que a internet pública. Pelo menos na internet pública eu tinha firewall. Dentro da VPN? Confiança total, zero verificação. Foi aí que mergulhei de cabeça no Zero Trust Network — e descobri que não é buzzword corporativa, é o bom senso que a gente ignora há anos.

O Problema com “Confiança na Rede Interna”
Vamos ser honestos: o modelo de segurança tradicional é um ovo. Casca dura por fora, mole por dentro. Você coloca firewall na borda, VPN para acessar de fora, e dentro da rede? Liberdade total.
O problema aparece quando:
- Alguém compromete um único servidor e ganha acesso à rede inteira (movimento lateral, baby)
- Um certificado VPN vence e ninguém percebe por 3 dias (aconteceu comigo)
- Você precisa dar acesso a um freelancer para UMA máquina, mas a VPN dá acesso a TODAS
- Rotas estáticas entram em conflito e a VPN simplesmente… para de funcionar sem explicação
- Logs de acesso mostram que ninguém sabe quem acessou o quê, nem quando
O modelo de perímetro confiável nasceu nos anos 90, quando redes eram físicas e previsíveis. Hoje? Meu servidor de staging roda num VPS na Alemanha, meu banco de dados num Droplet em Nova York, e o worker de processamento num servidor caseiro no Rio Grande do Sul. Que perímetro? Qual borda?
O Que É Zero Trust (Sem o Marketing)
Zero Trust é um princípio, não um produto. A ideia central é simples:
Nunca confie, sempre verifique. Cada conexão, cada request, cada acesso — independente de onde vem ou para onde vai — precisa ser autenticado, autorizado e criptografado.
Na prática, isso significa três coisas:
- Identidade como perímetro: O que define se você pode acessar algo não é estar na rede certa, mas ser quem você diz ser
- Menor privilégio: Cada máquina e cada pessoa só acessa exatamente o que precisa — nada mais
- Verificação contínua: Não basta autenticar uma vez. Cada ação é verificada contra políticas atualizadas
Soa teórico? Não é. Com WireGuard e Tailscale, você implementa isso em uma tarde. Eu implementei.
A Stack Que Eu Uso: WireGuard + Tailscale
WireGuard é o túnel. Tailscale é o cérebro. Juntos, formam a dupla que matou minha VPN corporativa de vez.
WireGuard: O Túnel Que Deveria Ter Sempre Existido
WireGuard é um túnel VPN moderno com ~4.000 linhas de código (OpenVPN tem ~100.000). Isso não é exagero — é design. Menos código = menos bugs = menos superfície de ataque.
Vantagens reais que eu notei no dia a dia:
- Latência reduzida de ~45ms (OpenVPN) para ~8ms entre meus servidores
- Configuração que cabe num arquivo de 10 linhas (sem certificados, sem CA)
- Handshake em menos de 100ms — reconexão instantânea após sleep/wake
- Roteamento baseado em cryptokey: cada peer tem um IP virtual associado à sua chave pública
Instalação no Ubuntu/Debian:
# Instalar WireGuard
sudo apt update && sudo apt install -y wireguard
# Gerar par de chaves para o servidor
wg genkey | tee /tmp/server_private | wg pubkey > /tmp/server_public
# Gerar par de chaves para o cliente
wg genkey | tee /tmp/client_private | wg pubkey > /tmp/client_public
echo "Chave pública do servidor: $(cat /tmp/server_public)"
echo "Chave pública do cliente: $(cat /tmp/client_public)"
Configuração do servidor (/etc/wireguard/wg0.conf):
[Interface]
PrivateKey = <SERVER_PRIVATE_KEY>
Address = 10.0.0.1/24
ListenPort = 51820
# Regra de NAT para tráfego sair pela interface principal
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
[Peer]
# Cliente: worker-node
PublicKey = <CLIENT_PUBLIC_KEY>
AllowedIPs = 10.0.0.2/32
Configuração do cliente:
[Interface]
PrivateKey = <CLIENT_PRIVATE_KEY>
Address = 10.0.0.2/24
DNS = 1.1.1.1
[Peer]
# Servidor principal
PublicKey = <SERVER_PUBLIC_KEY>
Endpoint = <SERVER_PUBLIC_IP>:51820
AllowedIPs = 10.0.0.0/24
PersistentKeepalive = 25
# Ativar no servidor
sudo systemctl enable --now wg-quick@wg0
# Ativar no cliente
sudo systemctl enable --now wg-quick@wg0
# Verificar conexão
sudo wg show
# Deve mostrar: latest handshake, transfer de dados
Tailscale: WireGuard com Identidade
WireGuard puro resolve o túnel, mas não resolve a gestão de identidade. Você ainda precisa distribuir chaves manualmente, gerenciar IPs e manter configurações sincronizadas. Com 3 servidores dá conta. Com 15? Pesadelo.
Tailscale é uma camada de gerenciamento sobre WireGuard que adiciona:
- Autenticação por identidade: Login via Google, GitHub, Microsoft — sem certificados
- Descoberta automática: Máquinas se encontram sozinhas, sem config manual de endpoints
- ACLs granulares: Defina quem acessa o quê com regras declarativas
- MagicDNS: Cada máquina ganha um nome DNS dentro da tailnet (
staging.tail1234.ts.net) - Funnel: Exponha serviços internos para a internet sem abrir portas
# Instalar Tailscale
curl -fsSL https://tailscale.com/install.sh | sh
# Autenticar (abre browser para login)
sudo tailscale up
# Verificar status
tailscale status
# Deve listar: máquina, IP da tailnet, online/offline
# Testar conexão com outro nó da tailnet
ping staging.tail1234.ts.net
# Latência deve ser baixa, conexão ponto a ponto direta
Implementando Zero Trust Passo a Passo
Passo 1: Mapeamento de Ativos e Fluxos
Antes de tocar em configuração, eu fiz o que nenhum tutorial manda fazer: mapeei tudo. Cada servidor, cada serviço, cada fluxo de dados.
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ Homelab (RS) │────▶│ Staging (FRA) │────▶│ DB Primary (NY) │
│ - OpenClaw │ │ - WordPress │ │ - PostgreSQL │
│ - Monitoramento │ │ - API Gateway │ │ - Redis │
│ - Backups │ │ - Worker queues │ │ - Backups S3 │
└─────────────────┘ └──────────────────┘ └─────────────────┘
│ │
│ │
▼ ▼
┌─────────────────┐ ┌──────────────────┐
│ Dev Laptop │ │ CI/CD Runner │
│ - Deploy access │ │ - Deploy only │
│ - SSH staging │ │ - No DB access │
└─────────────────┘ └──────────────────┘
Esse mapa revelou algo constrangedor: meu laptop tinha acesso SSH a TODOS os servidores. Meu worker de CI/CD também. Um atacante que comprometesse qualquer nó teria acesso a tudo em segundos.
Passo 2: Definição de Políticas de Acesso (ACLs)
Com o mapa pronto, eu defini quem precisa acessar o quê. O princípio é simples: se não precisa, não tem.
No Tailscale, as ACLs são definidas num arquivo de configuração (HuJSON):
{
"acls": [
// Admin: acesso total (sou eu, mas mesmo assim restrito)
{
"action": "accept",
"src": ["alisson@autogmail.com"],
"dst": [
"staging:*",
"homelab:22,80,443,9090",
"db-primary:5432"
]
},
// CI/CD runner: só deploy em staging
{
"action": "accept",
"src": ["tag:ci-runner"],
"dst": [
"staging:22,80,443"
]
},
// Worker de processamento: só acessa banco e Redis
{
"action": "accept",
"src": ["tag:worker"],
"dst": [
"db-primary:5432",
"db-primary:6379"
]
},
// Monitoramento: só coleta métricas
{
"action": "accept",
"src": ["tag:monitoring"],
"dst": [
"staging:9090",
"homelab:9090",
"db-primary:9187"
]
}
],
"tagOwners": {
"tag:ci-runner": ["alisson@gmail.com"],
"tag:worker": ["alisson@gmail.com"],
"tag:monitoring": ["alisson@gmail.com"]
}
}
Notou? Cada tag tem acesso só ao que precisa. O CI runner não acessa o banco. O worker não acessa SSH. O monitoramento só bate nas portas de métricas. Se qualquer máquina for comprometida, o dano é limitado ao escopo daquela tag.
Passo 3: Autenticação por Chave + 2FA no SSH
Mesmo com a tailnet protegendo o acesso, cada servidor continua exigindo autenticação própria. Defesa em profundidade: se uma camada falha, a próxima segura.
# /etc/ssh/sshd_config — Configuração hardcore
# Desabilitar senha (só chave)
PasswordAuthentication no
PubkeyAuthentication yes
# Desabilitar root login
PermitRootLogin no
# Limitar usuários
AllowUsers deploy admin
# Timeout de sessões inativas
ClientAliveInterval 300
ClientAliveCountMax 2
# Max tentativas
MaxAuthTries 3
# Logging verboso (para auditoria)
LogLevel VERBOSE
# Desabilitar forwarding desnecessário
X11Forwarding no
AllowTcpForwarding no
AllowAgentForwarding no
# Banner de aviso legal
Banner /etc/ssh/banner
sudo systemctl restart sshd
Para 2FA no SSH, uso libpam-google-authenticator em servidores críticos:
# Instalar Google Authenticator PAM
sudo apt install -y libpam-google-authenticator
# Setup para o usuário
google-authenticator -t -d -f -r 3 -R 30 -W
# Adicionar ao PAM (/etc/pam.d/sshd)
echo 'auth required pam_google_authenticator.so' | sudo tee -a /etc/pam.d/sshd
# Habilitar challenge-response no sshd_config
echo 'KbdInteractiveAuthentication yes' | sudo tee -a /etc/ssh/sshd_config
echo 'AuthenticationMethods publickey,keyboard-interactive' | sudo tee -a /etc/ssh/sshd_config
sudo systemctl restart sshd
Agora, para acessar qualquer servidor via SSH, você precisa: (1) estar autenticado na tailnet, (2) ter a chave SSH autorizada, (3) ter o código TOTP do Google Authenticator. Três fatores, três camadas.

Passo 4: Firewall por Servidor (Microsegmentação)
Zero Trust não elimina firewall — multiplica. Cada servidor vira sua própria fortaleza com regras individuais.
#!/bin/bash
# firewall-setup.sh — Regras UFW para servidor de staging
# Reset completo
sudo ufw --force reset
# Defaults: negar tudo
sudo ufw default deny incoming
sudo ufw default deny forwarding
sudo ufw default allow outgoing
# === REGRAS ZERO TRUST ===
# SSH: só via interface da tailnet (10.x.x.x)
sudo ufw allow in on tailscale0 to any port 22 proto tcp
# Bloquear SSH de qualquer outra interface
sudo ufw deny in on eth0 to any port 22 proto tcp
# HTTP/HTTPS: liberado para todo mundo (servidor web)
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# Métricas Prometheus: só da tailnet
sudo ufw allow in on tailscale0 to any port 9090 proto tcp
# PostgreSQL: NUNCA externo, só via tailnet
sudo ufw allow in on tailscale0 to any port 5432 proto tcp
sudo ufw deny 5432/tcp
# Bloquear todo o resto vindo da internet
sudo ufw deny from any to any port 3306,6379,27017,9200,5601 proto tcp
# Ativar
sudo ufw --force enable
sudo ufw status verbose
A chave aqui é in on tailscale0. Serviços sensíveis só aceitam conexões vindas da interface da tailnet. Se alguém tentar acessar PostgreSQL pela internet pública? Negado. Se estiver autenticado na tailnet e a ACL permitir? Acesso liberado.
Monitoramento e Auditoria: O Olho Que Nunca Pisca
Zero Trust sem monitoramento é fé cega. Você precisa saber quem acessou o quê, quando e de onde.
Logs Centralizados com Journalctl + Tailscale
# Script de auditoria: verifica acessos SSH da última hora
#!/bin/bash
# audit-ssh.sh
TAILNET_IP=$(tailscale ip -4)
echo "=== Auditoria SSH — $(hostname) ($TAILNET_IP) ==="
echo "=== $(date) ==="
echo ""
echo "--- Logins bem-sucedidos (última hora):"
journalctl -u sshd --since "1 hour ago" \
| grep -i "Accepted"
echo ""
echo "--- Tentativas falhas (última hora):"
journalctl -u sshd --since "1 hour ago" \
| grep -i "Failed"
echo ""
echo "--- Conexões ativas na tailnet:"
tailscale status
echo ""
echo "--- Portas abertas e seus processos:"
sudo ss -tlnp | grep -v "127.0.0"
# Salvar em log centralizado
echo "$(date -Iseconds) | $(hostname) | audit-complete" >> /var/log/zero-trust-audit.log
Alertas Automáticos com Script de Detecção
#!/bin/bash
# zero-trust-alert.sh — Detecta anomalias e alerta
# Quantos logins falhos são toleráveis por hora?
MAX_FAILED=5
FAILED_COUNT=$(journalctl -u sshd --since "1 hour ago" \
| grep -ci "Failed password")
if [ "$FAILED_COUNT" -ge "$MAX_FAILED" ]; then
# Alerta via webhook (Telegram, Slack, etc)
curl -s -X POST "${ALERT_WEBHOOK_URL}" \
-H "Content-Type: application/json" \
-d "{
\"text\": \"🚨 ALERTA ZERO TRUST: $(hostname) teve ${FAILED_COUNT} tentativas falhas de SSH na última hora (limite: ${MAX_FAILED})\"
}"
# Bloquear temporariamente acessos não-tailnet
sudo ufw deny in on eth0 to any port 22
echo "[$(date)] SSH bloqueado externamente após $FAILED_COUNT falhas" >> /var/log/zero-trust-audit.log
fi
# Verificar peers não reconhecidos na tailnet
EXPECTED_PEERS=5
CURRENT_PEERS=$(tailscale status | grep -c "\t")
if [ "$CURRENT_PEERS" -gt "$EXPECTED_PEERS" ]; then
curl -s -X POST "${ALERT_WEBHOOK_URL}" \
-H "Content-Type: application/json" \
-d "{\"text\": \"⚠️ ALERTA: Número de peers na tailnet mudou. Esperado: ${EXPECTED_PEERS}, Atual: ${CURRENT_PEERS}\"}"
fi
O Custo Real da Migração
Vou ser transparente sobre o que custou migrar de VPN tradicional para Zero Trust:
- Tempo: ~6 horas para mapear, configurar e testar tudo (uma tarde de sábado)
- Dinheiro: Tailscale plano pessoal é gratuito até 100 dispositivos. Meus 8 servidores estão bem dentro do limite
- Dores de cabeça: 1 reboot inesperado no DB durante migração de firewall (meu coração parou por 30 segundos)
- Melhora mensurável: Latência entre servidores caiu 80%. Incidentes de “VPN não conecta” foram a zero.
- Paz de espírito: Inestimável. Durmo melhor sabendo que um servidor comprometido não vira passaporte para o resto da infra
Checklist de Implementação Zero Trust
- ✅ Mapeou todos os servidores, serviços e fluxos de dados?
- ✅ Identificou quem precisa acessar o quê (princípio do menor privilégio)?
- ✅ Configurou WireGuard ou Tailscale em todos os nós?
- ✅ Definiu ACLs que bloqueiam tudo por padrão e liberam só o necessário?
- ✅ Desabilitou autenticação por senha em todos os SSH?
- ✅ Configurou 2FA nos servidores críticos?
- ✅ Cada servidor tem firewall individual com regras por interface?
- ✅ Logs de acesso são coletados e auditáveis?
- ✅ Tem alertas automáticos para comportamento anômalo?
- ✅ Testou o cenário de pior caso (servidor comprometido — dano é limitado)?
🧱 Perrengue de Produção: Eu configurei o firewall do banco de dados, ativei UFW, e… perdi acesso SSH. O próprio UFW bloqueou a porta 22 porque eu esqueci de adicionar a regra antes de ativar. Tive que entrar pelo console do provedor cloud (DigitalOcean), montar ISO de recovery, editar o config do UFW manualmente. Perdi 2 horas e ganhei uma regra de ouro: sempre libere SSH ANTES de ativar o firewall. Ou better yet: sempre deixe uma regra de SSH com
allow in on tailscale0antes de qualquerufw enable.
Por Que Isso Importa para Você
Se você tem mais de um servidor — e eu sei que tem, porque você está lendo um blog sobre automação — você precisa de Zero Trust. Não é luxo corporativo. É higiene básica digital.
A internet não fica mais segura com o tempo. Ataques se sofisticam. Ferramentas automatizadas escaneiam portas 24/7. Aquestão não é se alguém vai tentar invadir seus servidores — é quando. E quando acontecer, você quer que o atacante encontre uma porta aberta para tudo, ou um labirinto de portas trancadas com autenticação individual?
WireGuard é gratuito. Tailscale é gratuito para uso pessoal. O custo de implementar é uma tarde. O custo de não implementar é imprevisível — e potencialmente catastófico.
E você? Que automação de segurança quer ver aqui no blog? Já pensou em monitoramento automatizado com alertas no Telegram? Ou um script que testa suas próprias regras de firewall? Me conta nos comentários — a gente constrói juntos.
