- Wag é um projeto que adiciona autenticação multifator, restrições de rotas e registro de dispositivos ao WireGuard, permitindo separar rotas que exigem MFA de rotas públicas sempre acessíveis
- Oferece uma API para registro de novos clientes, alta disponibilidade, atualizações e notificações de usuários em tempo real, além de várias integrações de MFA, como Security Key, SSO, PAM e TOTP
- Para operar o servidor, é necessário ativar o encaminhamento de IP; na execução manual, é preciso instalar
iptableselibpame executar como root para gerenciariptablese dispositivos WireGuard - A administração pode ser feita pela interface web e pela CLI; a CLI usa os subcomandos
start,registration,devices,usersewebadminpara lidar com tokens de registro, bloqueio de dispositivos, redefinição de MFA e contas de administrador web - Entre as limitações, há suporte a apenas um
AllowedIPpor cliente; é voltado principalmente para Linux, e no Windows pode funcionar após alguns ajustes
Recursos que o Wag adiciona ao WireGuard
- Wag adiciona MFA, restrições de rotas e registro de dispositivos ao WireGuard
- As rotas podem ser definidas separando caminhos que exigem autenticação MFA e rotas públicas sempre acessíveis
- Fornece uma API simples para registro de novos clientes
- Suporta alta disponibilidade, atualizações de usuários em tempo real e notificações
- As integrações de MFA incluem os seguintes métodos
- Security Key
- SSO
- PAM
- TOTP
- A documentação está disponível em Documentation
Requisitos de instalação e execução
- O encaminhamento deve estar ativado no servidor
- Para IPv4, use a configuração
net.ipv4.ip_forward=1 - Para IPv6, use configurações
sysctlrelacionadas, comonet.ipv6.conf.all.forwarding=1
- Para IPv4, use a configuração
- O exemplo de execução com Docker Compose usa a imagem
wagvpn/wag:latest- Exemplo de porta da página de administração:
4433/tcp - Exemplo de porta da página pública de registro:
8081/tcp - Exemplo de porta do WireGuard:
53230/udp - Conecta o dispositivo
/dev/net/tunao contêiner
- Exemplo de porta da página de administração:
- A instalação manual requer
iptableselibpam - O Wag deve ser executado como root para gerenciar
iptablese o dispositivo WireGuard - Os releases binários exigem
glibc 2.31+ - A compilação a partir do código-fonte requer
go1.23.1enpm
Formas de administração
- Depois de ativar a UI de administração e configurar o Wag, ele cria o primeiro administrador e imprime a senha em STDOUT
- Depois disso, é possível fazer login na UI web para gerenciar usuários
- O usuário root pode administrar o servidor Wag pela CLI
- O formato da CLI é
wag subcommand [-options] - Os subcomandos suportados são os seguintes
start: inicia o servidor Wag e não o daemonizaregistration: cuida de criação, exclusão e listagem de tokens de registrodevices: cuida de listagem, exclusão, bloqueio, desbloqueio e consulta de sessões MFA ativas de dispositivos WireGuardusers: cuida de gerenciamento de MFA de usuários, exclusão de usuários, bloqueio de contas e redefinição de MFAwebadmin: cuida de adição, exclusão, listagem, bloqueio e desbloqueio de contas de usuários administradores da UI webversionefirewalltambém fazem parte dos comandos suportados
Tokens de registro e fluxo de MFA
- O registro de um novo dispositivo começa criando um token de registro com um comando como
wag registration -add -username tester - Ao enviar o token gerado para o endpoint público de registro, é possível receber uma resposta com a configuração do WireGuard
- A configuração retornada inclui itens como
Interface,PrivateKey,Address,Peer,Endpoint,PublicKey,AllowedIPsePersistentKeepAlive - O usuário acessa o endereço VPN do servidor e informa o código 2FA
- O tempo de duração da sessão antes de expirar é especificado no arquivo de configuração
Console de administração web
- Para entrar no console de administração,
Webserver.Management.Enableddeve ser definido comotrue - No console, adicione uma conta de administrador web com
sudo ./wag webadmin -add -username <your_username> -password <your-password-here> - Depois, acesse o endereço de escuta da administração e informe as credenciais
- A própria interface web não consegue adicionar usuários administradores
- Recomenda-se não expor o portal de administração externamente; a abordagem recomendada é definir
ListenAddresscomo127.0.0.1oulocalhoste expô-lo via encaminhamento SSH
Principais itens de configuração
NumberProxiesespecifica o número de proxies reversos confiáveis à frente do cliente, fazendo o Wag considerarX-Forward-Forao analisar o IP do clienteSocketé o socket de controle do Wag; ao alterá-lo, é possível executar várias instâncias do Wag na mesma máquinaNATativa ou desativa masquerading; quando ativado, todo o tráfego parece ter se originado no servidor VPNNATExcludeRangesespecifica os intervalos CIDR a excluir do NAT quandoNAT=trueExposePortsexpõe portas do servidor VPN aos clientes e adiciona regras deiptablesCheckUpdatesvem desativado por padrão; quando ativado, a UI de administração exibe notificações de novas versões do Wag e acessaapi.github.comAclsdefine grupos e políticas, mas é aplicado somente na primeira execução; durante o runtime, a edição é feita pela UI webWebserverinclui as configurações do endpoint público de registro, do portal MFA do túnel e do portal de administraçãoWireguardconfigura nome do dispositivo, porta de escuta, chave privada, sub-rede atendida pela VPN, MTU e servidores DNSClusteringinclui configurações relacionadas ao nome do cluster, estado do cluster etcd, nível de log, nós witness, localização do banco de dados e certificados do cluster
Comportamento das políticas de ACL
Policiesdefine as rotas que a VPN capturará e as portas e protocolos que passarão pelo Wag- A aplicação das regras usa o comprimento do prefixo da sub-rede, e a correspondência mais específica determina o nível de acesso à rota
- Por exemplo, se um
/16for definido como MFA e um/32específico dentro dele for definido como Allow, o/32mais específico terá precedência e poderá ser acessado sem MFA - Esse comportamento mudou na
v6.0.0; antes, rotas MFA sempre tinham prioridade - Se várias políticas forem definidas para uma mesma rota, elas serão compostas, com as regras de MFA tendo prioridade
- A partir de uma versão ainda não lançada, será possível bloquear o acesso a rotas com regras
Deny - Como a regra mais específica cria um novo “bucket” de regras, se houver apenas deny em um bucket
/32, o acesso a outras portas no mesmo/32também pode deixar de ser permitido
Regras de portas e protocolos
- O acesso a serviços pode ser definido por regras de portas e protocolos
- Há 3 tipos de regra suportados
- Any: se não houver regra separada ou se a palavra-chave
anyfor usada, permite todas as combinações de serviços e portas - Single Service: permite portas TCP e UDP específicas de um host, como em
192.168.1.1 22/tcp 53/udp - Ranges: especifica intervalos de portas, como em
192.168.1.1 22-1024/tcp 23-53/any
- Any: se não houver regra separada ou se a palavra-chave
- Em intervalos de portas, a porta menor deve vir primeiro
- Como ICMP não tem porta, pode ser especificado sem porta, como em
1.1.1.1 icmp
Limitações e desenvolvimento
- O Wag suporta apenas um
AllowedIPpor cliente - Essa limitação é adequada a uma estrutura em que o cliente se conecta ao servidor
- É voltado principalmente para Linux, e no Windows pode funcionar após alguns ajustes
- No modo de desenvolvimento, é possível usar uma variável de ambiente para definir como IP do cliente o IP das requisições que entram pelo túnel
- O exemplo de teste executa
sudo go test -v .eminternal/router - Contribuições externas são orientadas a escrever testes, quando possível, para adições de recursos ou correções de bugs e abrir um Pull Request
1 comentários
Comentários do Hacker News
Parece bom à primeira vista, mas algumas coisas me incomodam
Pelo exemplo
curl [http://public.server.address:8080/register_device?key=e83253...](<http://public.server.address/register_device/…;)e pela descrição de que “o serviço retorna uma resposta totalmente baseada em templates”, parece que, no processo de registro, não é o cliente que cria uma chave privada e envia a chave pública ao servidor; em vez disso, o servidor cria a chave privada e a envia ao clienteAlém disso, como o exemplo usa HTTP, seria bom mudar pelo menos essa parte para que as pessoas não pensem que HTTP também é uma opção aceitável
Também fico curioso se, quando a sessão expira, há alguma forma de o cliente perceber isso. Ou uma sessão SSH simplesmente fica travada?
De vez em quando procurei um cliente WireGuard que funcione como a detecção de portal cativo do Wi-Fi; idealmente, seria algo como adicionar uma linha
persistentkeepaliveao arquivo de configuração para buscar uma URL e verificá-la periodicamente. Se vierOK, está tudo normal; se não houver resposta, é problema de rede; se vier um cabeçalhoLocation, abrir o navegador nesse destino para reautenticar a sessão etc.Ainda não encontrei um cliente assim
pubkey, então não é preciso depender do servidor para gerar a chave privada. A documentação é insuficiente, então é compreensível a confusãoRespondendo à última pergunta: o eBPF XDP que uso só permite
PASS,DROPeREDIRECT. Por isso trato do jeito mais simples, comPASS/DROP, e a conexão simplesmente fica paradaPorém, se você adicionar a página de detecção de portal cativo à lista de MFA do wag, pode configurar a detecção por conta própria, e depois o navegador deve cuidar do resto
Não pretendo implementar no wag algo que funcione como interceptação ou proxy. Isso tornaria a expiração da autenticação ou o logout um pouco mais fáceis, mas não é a direção
Escrevi um cliente em Go para Mac e usei o
wgde linha de comando do Brew para também lidar com a geração de chaves, mas era tosco e exigiasudoSeria bom ter um app nativo de verdade usando permissões de rede, mas isso está além das minhas capacidades
Fico curioso se vocês já lidaram, ou planejam lidar, com o problema de gerenciamento de sessões
Essencialmente, uma chave WireGuard é como uma chave de sessão eterna
Acho que, se o software que implementa a camada de transporte do WireGuard é uma solução de servidor VPN adequada, ele também deveria implementar gerenciamento de sessões. Ou seja, por meio de um segundo canal com o servidor, deveria rotacionar periodicamente a chave de sessão, encerrar sessões, trocar endereços IP, configurar novas rotas e repetir a autenticação quando necessário
A chave WireGuard permite comunicação com o servidor wag, mas a sessão real é mantida em um mapa eBPF que indica se o usuário está autenticado ou não
Portanto, mesmo que alguém roube o material da chave privada, não terá acesso a rotas protegidas por MFA
Fico curioso se há proteção contra força bruta de códigos TOTP. Por exemplo, limitação de taxa ou limite de tentativas
Dei uma olhada rápida no código e não encontrei esse tratamento
O cenário que imagino é alguém abrir a UI de entrada de TOTP no navegador, abrir as ferramentas de desenvolvedor e tentar iterar por todos os códigos TOTP possíveis
A intenção também é, em especial, fazer o usuário pensar por que o dispositivo está tentando forçar autenticação. Uma situação assim pode indicar comprometimento do endpoint
Soa muito parecido com Headscale ou Tailscale. É bom ver alternativas para gerenciar redes WireGuard
Fico curioso se há algum material comparativo para entender até onde as funcionalidades se sobrepõem, o que foi acrescentado, o que é diferente e o que vocês não pretendem implementar no futuro
Não coloquei uma comparação direta na documentação, e esse não é o caminho que estou seguindo no momento. Este projeto atende às minhas necessidades e é bem divertido
O Wag é mais adequado a uma arquitetura hub-and-spoke com fronteiras rígidas, em vez de uma malha ao estilo Tailscale, em que tudo pode se comunicar e as regras definem o overlay
Tanto wag quanto Tailscale adicionam integração com SSO e, na prática, 2FA para proteger usuários
Ambos têm métodos de registro e uma UI web para administração, mas sou um desenvolvedor solo que não gosta de desenvolvimento web, então o Tailscale certamente será muito mais polido
O que certamente não vou implementar é interceptação ou proxy TLS para redirecionar usuários após logout de sessão. O principal motivo é que fazer isso com eBPF agora é um pouco demais para mim, e para fazê-lo funcionar eu provavelmente teria que escrever componentes de DNAT/SNAT que não quero usar
Ser apenas IPv4... Para um site que escolhe WireGuard, parece que talvez tenha uma configuração mais moderna e use bastante ULA própria como serviço
Fico curioso se você tinha algo específico em mente ao mencionar ULA