1 pontos por GN⁺ 2024-05-13 | 1 comentários | Compartilhar no WhatsApp
  • 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 iptables e libpam e executar como root para gerenciar iptables e dispositivos WireGuard
  • A administração pode ser feita pela interface web e pela CLI; a CLI usa os subcomandos start, registration, devices, users e webadmin para 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 AllowedIP por 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 sysctl relacionadas, como net.ipv6.conf.all.forwarding=1
  • 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/tun ao contêiner
  • A instalação manual requer iptables e libpam
  • O Wag deve ser executado como root para gerenciar iptables e o dispositivo WireGuard
  • Os releases binários exigem glibc 2.31+
  • A compilação a partir do código-fonte requer go1.23.1 e npm

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 daemoniza
    • registration: cuida de criação, exclusão e listagem de tokens de registro
    • devices: cuida de listagem, exclusão, bloqueio, desbloqueio e consulta de sessões MFA ativas de dispositivos WireGuard
    • users: cuida de gerenciamento de MFA de usuários, exclusão de usuários, bloqueio de contas e redefinição de MFA
    • webadmin: cuida de adição, exclusão, listagem, bloqueio e desbloqueio de contas de usuários administradores da UI web
    • version e firewall també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, AllowedIPs e PersistentKeepAlive
  • 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.Enabled deve ser definido como true
  • 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 ListenAddress como 127.0.0.1 ou localhost e expô-lo via encaminhamento SSH

Principais itens de configuração

  • NumberProxies especifica o número de proxies reversos confiáveis à frente do cliente, fazendo o Wag considerar X-Forward-For ao analisar o IP do cliente
  • Socket é o socket de controle do Wag; ao alterá-lo, é possível executar várias instâncias do Wag na mesma máquina
  • NAT ativa ou desativa masquerading; quando ativado, todo o tráfego parece ter se originado no servidor VPN
  • NATExcludeRanges especifica os intervalos CIDR a excluir do NAT quando NAT=true
  • ExposePorts expõe portas do servidor VPN aos clientes e adiciona regras de iptables
  • CheckUpdates vem desativado por padrão; quando ativado, a UI de administração exibe notificações de novas versões do Wag e acessa api.github.com
  • Acls define grupos e políticas, mas é aplicado somente na primeira execução; durante o runtime, a edição é feita pela UI web
  • Webserver inclui as configurações do endpoint público de registro, do portal MFA do túnel e do portal de administração
  • Wireguard configura nome do dispositivo, porta de escuta, chave privada, sub-rede atendida pela VPN, MTU e servidores DNS
  • Clustering inclui 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

  • Policies define 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 /16 for definido como MFA e um /32 específico dentro dele for definido como Allow, o /32 mais 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 /32 també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 any for 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
  • 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 AllowedIP por 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 . em internal/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

 
GN⁺ 2024-05-13
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 cliente
    Alé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 persistentkeepalive ao arquivo de configuração para buscar uma URL e verificá-la periodicamente. Se vier OK, está tudo normal; se não houver resposta, é problema de rede; se vier um cabeçalho Location, abrir o navegador nesse destino para reautenticar a sessão etc.
    Ainda não encontrei um cliente assim

    • A URL de registro também pode receber opcionalmente um parâmetro pubkey, então não é preciso depender do servidor para gerar a chave privada. A documentação é insuficiente, então é compreensível a confusão
      Respondendo à última pergunta: o eBPF XDP que uso só permite PASS, DROP e REDIRECT. Por isso trato do jeito mais simples, com PASS/DROP, e a conexão simplesmente fica parada
      Poré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
    • Esse recurso seria realmente muito legal, e espero que o autor deste projeto o considere
    • Já criei um servidor parecido. Ele exigia um certificado de cliente por dispositivo; com ele, o dispositivo acessava a página de login via mTLS, autenticava o usuário via OIDC e então ativava o túnel. A parte difícil foi o cliente
      Escrevi um cliente em Go para Mac e usei o wg de linha de comando do Brew para também lidar com a geração de chaves, mas era tosco e exigia sudo
      Seria 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

    • Para esse uso, eu usaria o Firezone. Ele tem uma opção para forçar os usuários a fazer login periodicamente na plataforma e, combinado via OIDC com um provedor de identidade externo, vira uma solução muito sólida e simples para gerenciamento de sessões
    • Não tenho certeza do que exatamente significa “chave de sessão eterna” no contexto do wag
      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
    • Se eu fosse criar um cliente VPN tipo GlobalProtect com WireGuard, imagino que teria uma chave de autenticação permanente por cliente para criar um túnel inicial até o controlador da VPN; dentro dele, faria a autenticação e receberia uma chave de sessão separada. O primeiro túnel seria encerrado assim que a autenticação terminasse e a chave de sessão real fosse recebida
    • Um segundo canal para rotação periódica de chaves de sessão, encerramento de sessão, troca de endereço IP, configuração de novas rotas e reautenticação não é basicamente o protocolo IKE do IPsec? Por que não simplesmente usar IPsec?
  • 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

    • Há defesa contra força bruta de códigos TOTP. Cada autenticação tem um limite de tentativas que o usuário pode fazer; se passar disso, a conta é bloqueada e um administrador precisa desbloqueá-la
      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
    • Provavelmente é aqui: https://github.com/NHAS/wag/blob/cdbdbec3393fa86bf6c823117c8...
    • Não conheço os detalhes desta implementação, mas normalmente, se alguém já tem as credenciais para chegar à etapa de TOTP, ou seja, nome de usuário e senha, esse usuário já está comprometido
  • 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

    • Sem dúvida é parecido no sentido de que usa WireGuard
      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

    • Pretendo adicionar suporte a IPv6 em breve, e também estou pensando em mapear os endereços IPv4 das pessoas para um espaço IPv6 privado, para reduzir o risco de conflito com a rede local real do usuário
      Fico curioso se você tinha algo específico em mente ao mencionar ULA
    • Fico curioso para saber quais seriam as vantagens de ULA nesse caso