WireGuard – Guia definitivo

Saudações. Nesse artigo e tutorial vou abordar profundamente o Wireguard (WG), um software e um protocolo de VPN extremamente simples e seguro.

O Wireguard pode parecer muito estranho no primeiro contato mas, entendendo seu esquema interno, sua configuração é prática e rápida.

Pre-requisitos

Softwares utilizados nesse artigo

  • Linux Debian 12 ou versão mais nova;
  • Wireguard para Linux;
  • Wireguard para Windows;
  • Wireguard para Android;
  • Wireguard para iPhone;

1 – O que é o Wireguard e detalhes do protocolo

Wireguard é um protocolo de VPN que define regras simples e altamente eficientes para realizar uma conexão segura entre dois ou mais participantes (roteadores, smartphones, notebooks, etc…).

Características técnicas:

  • Funciona em todos os sistemas modernos: macOS, Linux, FreeBSD, Android, iOS;
  • Funciona em roteadores embarcados: OpenWRT, RaspberryPI, BananaPI, etc…;
  • Funciona no Windows (x86_64 e ARM);
  • Funciona no Mikrotik RouterOS (versão 7 em diante);
  • Funciona sobre IPv4 e IPv6 completamente;
  • Utilizada UDP como protocolo de transporte sobre IP, permitindo seu funcionamento atravez de redes com NAT (todos os sabores de NAT são contornados: nat44, nat444, nat64, nat66, nat666, …);
  • Criptografia de ponta atingindo “estado de arte” (state-of-the-art):
    • Framework Noise Protocol;
    • Chave de criptografia assíncrona usando curvas elipticas Curve25519;
    • Chaves efêmeras usando ECDH (Elliptic-curve Diffie–Hellman) ;
    • Criptografia simétrica de fluxo ChaCha20;
    • Hash de autenticação e integridade usando Poly1305 e BLAKE2;
    • Hash SipHash24 para geração de números pseudo-randômicos;
    • HKDF para derivação de chaves;
    • Suporte a PSK para boot e negociação 100% segura (resistência quântica);
  • Aprendizado de IP móvel (roaming) permite que o usuário mude de IP sem causar a quebra da conexão do túnel VPN;
  • Linux Kernel mode: software acelerado no Kernel Linux, atinge velocidades próximas a wirespeed (velocidade máxima da interface de rede);
  • Suporta aceleração em hardware de CPUs com AES-NI (aceleração criptográfica) e AVX2/AVX-512;
  • Performa muito bem com latência baixa e alta largura de banda;

Como nem tudo é paraíso, o Wireguard não é perfeito.

Algumas desvantagens do Wireguard:

  • Não possui nenhuma forma de configurar IP das pontas dentro da VPN de maneira dinâmica, ou seja, não tem DHCP nem nenhum protocolo do tipo, você deve atribuir IP fixo nas pontas manualmente;
  • Ausência de Sistema de autenticação centralizado;
  • As chaves públicas não participam de um ambiente PKI (CA) e devem ser trocadas entre as pontas por conta própria (whatsapp, ssh, email, pombo correio, …), o mesmo se aplica a senha compartilhada PSK (uso opcional);
  • Funciona somente em UDP: embora não seja uma desvantagem real pois se usado sobre TCP resultaria em problemas de repetição dobrada em caso de perda de pacotes (TCP Meltdown – túnel repete, cliente do túnel repete);
  • Configuração 100% manual: requer configuração de cada peer manualmente especificando chaves e parâmetros o que resulta numa administração externa difícil em ambientes com muitos túneis e/ou muitos clientes, exigindo um framework de configuração (software de gerenciamento);
  • Log de erros limitadíssimos: se não funcionou você está encrencado para depurar e encontrar onde errou (o Wireguard nunca erra, sempre é você que esqueceu ou digitou algo errado);
  • Vulnerável a fingerprint de protocolo: firewalls avançados podem detectar que uma conexão IP-UDP está fazendo uso do protocolo Wireguard mesmo em túneis com uso de PSK pois o cabeçalho Wireguard tem zeros fixos presentes;
  • Overhead elevado: 80 bytes de redução, uma rede de 1500 bytes de MTU suporta o Wireguard com no máximo 1420 bytes de MTU. Para passagem segura sem fragmentação é recomendado um MTU de 1400 ou menor (em ambiente com PPPoE nunca use acima de 1412, ou seja, 1492 – 80 = 1412);
  • Opera somente como túnel de camada 3, transportando somente IPv4 e IPv6, para transporte de camada 2 é necessário fazer overlay (túnel dentro de túnel), o que degrada a performance com fragmentação e overhead;
  • Confusão entre ACL e rotas: o Wireguard só aceita encaminhar pacotes cujo IP de destino esteja enquadrado na ACL de permissão (AllowedAddress), no Windows/macOS/Android/iOS essa ACL também é convertida em rota estática para o túnel, o que causa confusão no entendimento do recurso;

2 – Instalando o Wireguard

A instalação é simples e limpa, escolha o sistema e execute os passos.

Página de referência para download:

Instalando no Linux Debian:

Bash
# Instalar Wireguard (debian) caso ainda não tenha instalado:
    apt-get -y install wireguard
    apt-get -y install wireguard-tools

3 – Wireguard e a criptografia

O Wireguard faz uso da criptografia assimétrica Curve25519 (ECC) e a criptografia simétrica ChaCha20, ambas criadas por Daniel J. Bernstein.

O conceito fundamental da criptografia assimétrica é uso de duas chaves intrinsicamente emaranhadas:

  • Chave Privada: gerada pelo usuário e mantida em segredo, jamais é transmitida ou comunicada a terceiros;
  • Chave Pública: parte derivada da chave Privada que é transmitida a terceiros;

As duas chaves tem capacidade de criptografar um pequeno bloco de bytes:

  • Uso da chave pública: Tudo que é criptografado com a chave pública é descriptografado com a chave privada (Pub->PRIV). Como a chave pública é distribuida livremente, todo mundo pode enviar uma cifra ao proprietário da chave privada. O usuário da chave privada prova que tem a chave privada decifrando mensagens enviadas por terceiros;
  • Uso da chave privada: Tudo que é criptografado com a chave privada pode ser descriptografado com a chave pública (PRIV->Pub). Visto que todos podem ter a chave pública, criptografar algo com a chave privada não garante segurança aos dados, mas garante que a cifra foi produzida pelo dono da chave pública, logo esse sentido se chama Assinatura digital;

No Wireguard não há troca de chaves públicas usando a conexão IP-UDP.

As chaves públicas e privadas são usadas para estabelecer uma chave comum Diffie-Hellman (DHEC) em vez de trocar conteúdos cifrados assimetricamente.

Cada peer (cada ponta da VPN) deve ter a chave pública do outro peer para preencher sua configuração local.

O Wireguard não define nenhum método para que as duas partes troquem essas chaves públicas e você (administrador de rede) deve inventar uma forma (SSH, HTTPs, Email, …).

Exemplo de geração de chaves privadas e respectivas chaves públicas Curve25519 para o WireGuard:

Bash
# Gerar chave privada
    # - Gera chave privada e salva no arquivo /tmp/chave1.key
    # - Gera a chave publica e salva no arquivo /tmp/chave1.pub
    wg genkey | tee /tmp/chave1.key | wg pubkey > /tmp/chave1.pub

    # Ajuste de permissao para leitura do arquivo:
    chmod 600 /tmp/chave1.key

    # Exibindo chave privada:
    cat /tmp/chave1.key
        aD/yLOGw2CcYvv4VGX05F8Xg4hjrloQYXURwUZNORmo=

    # Exibindo chave publica:
    cat /tmp/chave1.pub
        TH0T/e4HMIELhtPOs33C2i6BOGI5yJVrHthJZqt72Q0=
    
# Forma mais simples de gerar chave:
    # Gerar chave privada
    wg genkey > /tmp/chave2.key

    # Ajuste de permissao para leitura do arquivo:
    chmod 600 /tmp/chave2.key

    # Gerar chave pública correspondente
    wg pubkey < /tmp/chave2.key > /tmp/chave2.pub

    # Exibindo chave privada:
    cat /tmp/chave1.key
        8CYYvnySMTbPeVhQ3VCdyjMBdQILSpT2eAHo/1Lbb3Q=

    # Exibindo chave publica:
    cat /tmp/chave1.pub
        AZ5Zm3J8/7egS0RV/FVs5pyKGRw/4mO8Y3i50IKG/WQ=

Opcionalmente um peer Wireguard pode fazer uso de uma senha pre-compartilhada – PSK (Pre-Shared Key).

Comparações do diagrama de criptografia:

Sem PSK:

Diagrama com fluxograma de geração de chaves de criptografia para cifragem de dados na VPN Wireguard.

Com PSK

Diagrama com fluxograma de geração de chaves de criptografia para cifragem de dados na VPN Wireguard com adição de chave pre-compartilhada (senha adicional).

O PSK adiciona no Wireguard resistência quântica, elevando a segurança para muito acima do que é provido hoje em sites HTTPS (HTTP + TLS).

Regras gerais para uso de chaves:

  • Cada lado tem sua chave privada;
  • Cada lado tem a chave pública do outro lado (peer);
  • Ambos os lados funcionam se:
    • Não usarem chave pre-compartilhada (PSK);
    • Usarem a MESMA chave pre-compartilhada;

4 – Wireguard e o protocolo IP

O Wireguard pode ser transportado sobre UDP pelos protocolos IPv4 ou IPv6.

Wireguard sobre IP

O protocolo IP tem duas versões com diferenças discretas no tamanho do cabeçalho:

  • O protocolo IPv4 tem cabeçalho padrão de 20 bytes (160 bits);
  • O protocolo IPv6 tem cabeçalho padrão de 40 byte (320 bits), suportando cabeçalhos intermediários entre o primeiro cabeçalho e último (UDP nesse caso);

Detalhes do cabeçalho IPv4:

Diagrama demonstrando o cabeçalho IPv4 com 20 bytes de overhead.

Detalhes do cabeçalho IPv6:

O cabeçalho UDP possui 8 bytes (128 bits) em 4 campos de 2 bytes cada (16 bits cada):

  • SPORT – Source Port – porta de origem – 2 bytes;
    • A porta de origem é a mais importante: ela define qual porta será alocada para o Wireguard receber pacotes e não pode ser compartilhada com outro softwares. O erro mais comum aqui é alocar para o Wireguard uma porta que já está em uso, seja por outra interface wireguard pre-configurada ou por algum software que resolvou a mesma porta escolhida;
    • Nos clientes Wireguard que se conectam a um servidor Wireguard centralizado a porta de origem não é importante e pode ser deixada em automático (o WG vai pegar alguma porta livre aleatoriamente);
  • DPORT – Destination Port – porta de destino – 2 bytes;
    • A porta de destino nos clientes define em qual porta está o servidor remoto;
    • No servidor Wireguard, a porta de destino pode ser manual ou automática, o padrão é não especificar IP e porta dos clientes e deixar o WG aprender automaticamente;
  • LEN – Length – tamanho total do segmento (cabeçalho UDP e Payload) – 2 bytes;
  • Checksum – dígito verificador (cabeçalho IP + segmento UDP) – 2 bytes;

O segmento UDP pode suportar um total de 65.535 bytes (limite para representar no campo LENGTH de 16 bits). Como o campo contabiliza o tamanho do cabeçalho UDP, a carga útil máxima 65.527 bytes (65.535 – 8 = 65527).

Detalhes do cabeçalho Wireguard:

Diagrama demonstrando o cabeçalho Wireguard com 32 bytes de overhead.

Overhead e estrangulamento do MTU

O protocolo IP está na camada 3 (roteamento, internet protocolo, inter-networking) e é responsável por um parâmetro chamado MTU (maximum transmission unit). Esse parâmetro é configurado nas interfaces de rede dos sistemas operacionais e possui um valor padrão de 1500 bytes. O MTU configurado em uma interface se aplica ao IPv4 e ao IPv6 simultaneamente.

O MTU define que nenhum pacote IP pode ser maior que o tamanho limite (padrão 1500) e se isso ocorrer por algum motivo o sistema operacional deve acionar uma das opções abaixo:

  • Fragmentar o pacote IP: o pacote IP maior que o MTU é dividido em pedaços menores que se acomodem no valor de MTU da interface de saída;
  • Descartar o pacote e emitir uma mensagem ICMP (“Packet too big”) ao remetente informando do limite de MTU do caminho, o remetente deve anotar o limite para aquele IP de destino (PMTU) e enviar os próximos pacotes dentro do limite;

Fragmentar é a comportamento padrão do IPv4.
Descartar e avisar ao remetente é o comportamento padrão do IPv6.

Para evitar violar o MTU das interfaces pelo caminho na Internet precisamos saber quais são esses limites.

Na Internet temos os seguintes limites:

  • IPOE: 1500 bytes – limite natural sem overhead e padrão de todas os sistemas operacionais e interfaces ethernet (IP over Ethernet = IPoE = DHCP ou IP Fixo);
  • PPPOE: 1492 bytes – limite de provedores de Internet que fornecem acesso usando PPPoE, usando o protocolo PPP sobre ethernet e adicionando 8 bytes de overhead. Alguns provedores podem usar valores ainda menores perto de 1480;
  • GRE sobre IPv4 – 1476 bytes – alguns provedores e empresas usam o protocolo GRE para acessar empresas de “scrubbing center” (mitigação DDoS) e proteger a Internet durante ataque cibernéticos adicionando 24 bytes de overhead (20 de IPv4 e 4 de GRE);
  • GRE sobre IPv6 – 1456 bytes – semelhante ao caso acima usando IPv6 como base do túnel GRE, adicionando 64 bytes de overhead (40 de IPv6 e 4 de GRE);

Não é tão simples como parece, assumir um MTU 1500 para funcionamento universal pode representar problemas de acesso e fragmentação intensa, o que degrada severamente a performance e a capacidade de banda.

O acesso entre dois servidores que estão na Internet, hospedados em datacenters facilmente funcionará com MTU de 1500 pois esse é o padrão mínimo de datacenters. Já quando o acesso envolver usuários e servidores domésticos em links de provedores a coisa fica mais complexa.

Tabela de payload UDP máximo para cada MTU natural (Overhead WG em 32 bytes):

Protocolo de transporteVersão IP
do pacote
MTUOverhead
IP+UDP
Payload UDPPayload
Wireguard
IPoEIPv415002814721440
IPoEIPv615004814521420
PPPoEIPv414922814641432
PPPoEIPv614924814441412
GRE o IPv4IPv414762814481416
GRE o IPv4IPv614764814281396
GRE o IPv6IPv414562814281396
GRE o IPv6IPv614564814081376

Observe a última linha “GRE over IPv6”: vemos que usar o Wireguard em dispositivos de usuários finais fora do ambiente de datacenter pode encarar um MTU de caminho reduzido até 1456 bytes com payload UDP de 1408 e capacidade de transporte de pacotes IP dentro do túnnel WG de apenas 1376 bytes – essa é a pior das hipóteses.

O MTU de uma interface Wireguard é de 1440, e podemos perceber que esse valor é universal considerando ambientes 100% homologados em 1500 bytes usando apenas IPv4 como base do túnel.

Observe a seguinte redução simplificada de toda a Internet e gargalos de MTU que podem ser encontrados pelo caminho:

O cliente (HOME) se conecta ao servidor (SERVER). Existem dois caminhos possíveis com diferentes limites de MTU:

  • HOME até SERVER pelo caminho curto (5 saltos): menor MTU 1456
    • 1500 (lan entre PC e roteador) =>
    • 1492 (PPPoE do provedor HOME) =>
    • 1500 (Backbone do provedor HOME) =>
    • 1456 (Provedor usando GRE sobre IPv6) =>
    • 1476 (Provedor usando GRE sobre IPv4) =>
    • 1500 (Backbone do provedor destino) =>
    • 1500 (Link dedicado do servidor SERVER).
  • SERVER até HOME, resposta pelo caminho superior: menor MTU 1492
    • 1500 (Link dedicado do SERVER) =>
    • 1500 (Backbone do provedor de SERVER) =>
    • 1500 (Link BGP simples) =>
    • 9000 (Link BGP em datacenter) =>
    • 1500 (Link BGP simples) =>
    • 1500 (Backbone do provedor de HOME) =>
    • 1492 (PPPoE do provedor HOME) =>
    • 1500 (lan entre PC e roteador).

Se o pacote IP fosse um caminhão com 1500 unidades de altura e o MTU fosse a altura dos viadutos, a visão seria assim:

Esse caminhão não chega no destino inteiro.

O pacote IPv4 sofrerá fragmentação.

  • No sentido HOME -> SERVER, o primeiro gargalo é de 1492:
    • O pacote IP de 1500 bytes será quebrado em dois pedaços, o primeiro contendo 1492 e o segundo contendo o restante com 28 bytes (8 bytes úteis + 20 do novo cabeçalho).
    • O pacote de 1492 enfrentará novo gargalo de 1456 bytes e será fragmentado em dois pedaços, o primeiro contendo 1456 e o segundo contendo 56 bytes (36 bytes úteis + 20 do novo cabeçalho).
    • 1 pacote saiu do remetente (1500) e 3 pacotes chegaram no destinatário:
      • 1456 + 56 + 28
    • O pacote original de 1500 bytes será reconstruído assim que os 3 pedaços chegarem ao destinatário, o que nivela a latência pelo maior atraso.
  • No sentido SERVER -> HOME, há apenas um gargalo d 1492:
    • O pacote IP de 1500 bytes será quebrado em dois pedaços, o primeiro contendo 1492 e o segundo contendo o restante com 28 bytes (8 bytes úteis + 20 do novo cabeçalho).
    • 1 pacote saiu do remetente (1500) e 2 pacotes chegaram no destinatário:
      • 1492 + 28
    • O pacote original de 1500 bytes será reconstruído assim que os 2 pedaços chegarem ao destinatário, o que nivela a latência pelo maior atraso.

Isso ilustra com detalhes penosos como VPNs sofrem problemas na Internet selvagem.

5 – Homologando MTU entre os peers WG

Para saber qual MTU passará sem fragmentação entre as pontas que farão o túnel WG é necessário medir a constantemente a capacidade de tamanho de pacotes IPv4 e IPv6 entre os IPs envolvidos.

Um teste simples é realizar um ping com opção “do not fragment” do cabeçalho IP, que impede que roteadores no caminho quebrem o pacote IP em pedaços, restando a eles somente a opção de deletar o pacote e emitir um aviso ICMP de retorno sobre o MTU de gargalo.

Alguns roteadores não respondem com esse aviso ICMP e destroem silenciosamente o pacote.

O ping deve ser feito com seguinte cuidado:

  • Em Windows, Linux e roteadores o tamanho do ping considera o PAYLOAD ICMP, que é acrescido de 8 bytes de cabeçalho ICMP e adição do cabeçalho IP:
    • IPv4: +20 bytes – ping 1472 => 1500 bytes de pacote IPv4 final;
      • Quase impossível fazer um ping IPv6 com payload 1473;
    • IPv6: +40 bytes – ping 1452 => 1500 bytes de pacote IPv6 final;
      • Quase impossível fazer um ping IPv6 com payload 1453;
  • No Mikrotik RouterOS o tamanho do ping considera o tamanho total do pacote IP, independente de ser IPv4 ou IPv6;

Logo, supondo que o IPv4 do servidor é 45.255.128.1 e o IPv6 é 2001:db8::1234, teste:

Bash
# Instalando comando ping e fping no Debian:
apt-get -y install iputils-ping
apt-get -y install fping

# Exemplos de teste com ping comum:
    # - IPv4 (1472+8+20=1500)
    ping -M dont -c 4 -s 1472 45.255.128.1

# Exemplos de teste com fping:
    # - IPv4 (1472+8+20=1500)
    fping -M -c 4 -b 1472  45.255.128.1
    fping -M      -b 1472  45.255.128.1

    # - IPv6 (1452+8+40=1500)
    fping -M -c 4 -b 1452  2001:db8::1234
    fping -M      -b 1452  2001:db8::1234

Se o ping não funcionar a 1500 bytes de pacote IP, reduza até encontrar o teto do caminho, exemplo de script simples:

Bash
# Tentar descobrir MTU funcional ate o destino:
DEST=45.255.128.1;
FOUND=0;
for pktsize in $(seq 1472 -1 1300); do
    MTU=$(($pkgsize+28));
    echo "# [$DEST] Testando payload $pktsize (mtu $MTU)";
    fping -M -c 1 -b 1472  $DEST 2>/dev/null 1>/dev/null;
    if [ "$?" = "0" ]; then
        FOUND=1;
        echo "# * MTU limite: $MTU";
        break;
    else
        echo "# - MTU nao suportado: $MTU";
    fi
done
if [ "$FOUND" = "0" ]; then
    echo "# - MTU limite nao encontrado.";
fi

Agora nivele o MTU do Wireguard com o seguinte cálculo:

  • Dado o MTU X (1500 por exemplo), retire o tamanho do cabeçalho IP
    • IPv4: X-20
    • IPv6: X-40
  • Retire 8 bytes do cabeçalho UDP;
  • Retire 32 bytes do cabeçalho Wireguard;

Esse será o valor funcional para um túnel sem fragmentação na Internet.

6 – Criando um servidor Wireguard – método rápido

Não há diferença prática entre um servidor e um cliente Wireguard. Normalmente ambos os peers podem apontar um para o IP e porta do outro.

Se um dos lados aponta para o IP e o outro não, o que apenas recebe conexões é chamado de servidor, o que aponta é chamado de cliente.

Assim, vamos montar uma interface Wireguard que não aponta para outros IPs e abre uma porta para atendimento dos clientes.

Passos:

  • Criar declaração da interface de rede;
  • Criar as chaves do lado servidor (privada e pública);
  • Criar as chaves do lado cliente 1 (privada e pública);
  • Criar as chaves do lado cliente 2 (privada e pública);
  • Criar configuração rápida/facilitada do Wireguard no servidor;
  • Ativando lado servidor;
  • Analisando detalhes da interface WG no servidor Linux;
  • Criar configuração para uso no cliente (qualquer cliente);
  • Ativando lado cliente;

Criando declaração da Interface

A interface se chamará wg-srv.

Certifique-se de que no arquivo /etc/network/interfaces existe a linha:
source /etc/network/interfaces.d/*
pois isso nos permitirá criar configurações em arquivos na pasta /etc/network/interfaces.d/ sem precisa editar o arquivo “interfaces”, que é considerado crítico para o sistema.

Conteúdo do arquivo: /etc/network/interfaces.d/wg-srv

/etc/network/interfaces.d/wg-srv
auto wg-srv
iface wg-srv inet static
    address 10.77.0.1/24
    pre-up     wg-quick  up    /etc/wireguard/wg-srv.conf wg-srv || true
    post-down  wg-quick  down  /etc/wireguard/wg-srv.conf wg-srv || true

Criando chaves do servidor

Bash
# Criar pasta de configurações e chaves Wireguard:
mkdir -p /etc/wireguard

# Gerar chave privada da interface "wg-srv" (apenas se ja nao existir)
[ -f /etc/wireguard/wg-srv.key ] || {
    ( umask 077; wg genkey > /etc/wireguard/wg-srv.key; )
}

# Ajuste de permissao para proteger a chave privada:
chmod 600 /etc/wireguard/wg-srv.key

# Gerar chave pública da interface "wg-srv"

# Gerar chave pública correspondente
wg pubkey < /etc/wireguard/wg-srv.key > /etc/wireguard/wg-srv.pub

# Exibindo chave privada (para fins educativos apenas):
    cat /etc/wireguard/wg-srv.key
        KPi3L0AadxEqzdzIdGPvni2Nh6bgBDGpOFCa5ETelFs=

    # Exibindo chave publica:
    cat /etc/wireguard/wg-srv.pub
        AVtrliS3dcFIGDJVLJCTYTM/+ZUHFDqMyC02E8inCBk=

Criando chaves dos clientes (1 e 2)

Normalmente o cliente gera a chave privada e a guarda em segredo, enviando ao adminisdrador do servidor somente a chave pública, vou desconsiderar isso e gerar no lado servidor para entregar ao cliente a configuração pronta pra uso.

Bash
# - Cliente 1
    CLI01_KEY=/etc/wireguard/wg-srv-client-01.key
    CLI01_PUB=/etc/wireguard/wg-srv-client-01.pub
    # - gerando chave privada:
    [ -f "$CLI01_KEY" ] || {
        ( umask 077; wg genkey > $CLI01_KEY; )
    }
    # - gerando chave pública:
    [ -f "$CLI01_PUB" ] || {
        wg pubkey < $CLI01_KEY > $CLI01_PUB
    }
    
    # Resultado client 01:
    # chave privada.: MM6qvnIJZRrV6GigGtdk7vdJPLN6hgS1PtWj3+i+gkQ=
    # chave pública.: bfqqb9PIylURBzmhmvD6gn9y23jkM8K0/Y26RGfUolM=

# - Cliente 2
    CLI02_KEY=/etc/wireguard/wg-srv-client-02.key
    CLI02_PUB=/etc/wireguard/wg-srv-client-02.pub
    # - gerando chave privada:
    [ -f "$CLI02_KEY" ] || {
        ( umask 077; wg genkey > $CLI02_KEY; )
    }
    # - gerando chave pública:
    [ -f "$CLI02_PUB" ] || {
        wg pubkey < $CLI02_KEY > $CLI02_PUB
    }
    
    # Resultado client 02:
    # chave privada.: CBd1QazVCADvqdXCrbRdOjyBx/B95uHZlveMv/Omel0=
    # chave pública.: inrlReody89Z82cTf68ik83rYkTfVpLmMQFUwpt/CSQ=

Criar configuração do wg-quick (modo facilitado)

Crie o arquivo /etc/wireguard/wg-srv.conf com o seguinte conteúdo:

/etc/wireguard/wg-srv.conf
[Interface]
PrivateKey = KPi3L0AadxEqzdzIdGPvni2Nh6bgBDGpOFCa5ETelFs=
Address = 10.77.0.1/24
ListenPort = 51443
MTU = 1420

# Cliente 1
[Peer]
PublicKey = bfqqb9PIylURBzmhmvD6gn9y23jkM8K0/Y26RGfUolM=
AllowedIPs = 10.77.0.11/32

# Cliente 2
[Peer]
PublicKey = inrlReody89Z82cTf68ik83rYkTfVpLmMQFUwpt/CSQ=
AllowedIPs = 10.77.0.12/32

Ajuste de permissão (o arquivo wg-srv.conf contem a chave privada e não pode ser lido por usuários comuns):

Bash
# Ajuste de permissão no arquivo de configuração do servidor
chmod 600 /etc/wireguard/wg-srv.conf

Ativando lado servidor

Vamos acionar o if-up para subir a interface de rede, simulando assim o setup durante o boot do Debian:

Bash
# Subir interface wg-srv
ifup --force  wg-srv

# Extraindo configuração aplicada:
wg showconf wg-srv

# Listando chave publica dos peers:
wg show wg-srv peers
wg show wg-srv dump

# Listando detalhes de consumo:
wg show wg-srv transfer

# Listando handshakes (negociações recentes):
 wg show wg-srv latest-handshakes
 
# Listando ACLs:
wg show wg-srv allowed-ips
 
# Exibindo configuração em execução:
wg show wg-srv
    # interface: wg-srv
    #   public key: AVtrliS3dcFIGDJVLJCTYTM/+ZUHFDqMyC02E8inCBk=
    #   private key: (hidden)
    #   listening port: 51443
    # 
    # peer: bfqqb9PIylURBzmhmvD6gn9y23jkM8K0/Y26RGfUolM=
    #   allowed ips: 10.77.0.11/32
    # 
    # peer: inrlReody89Z82cTf68ik83rYkTfVpLmMQFUwpt/CSQ=
    #   allowed ips: 10.77.0.12/32

Analisando detalhes da interface WG no servidor Linux

Bash
# Extraindo configuração aplicada:
wg showconf wg-srv
    # [Interface]
    # ListenPort = 51443
    # PrivateKey = KPi3L0AadxEqzdzIdGPvni2Nh6bgBDGpOFCa5ETelFs=
    # 
    # [Peer]
    # PublicKey = bfqqb9PIylURBzmhmvD6gn9y23jkM8K0/Y26RGfUolM=
    # AllowedIPs = 10.77.0.11/32
    # 
    # [Peer]
    # PublicKey = inrlReody89Z82cTf68ik83rYkTfVpLmMQFUwpt/CSQ=
    # AllowedIPs = 10.77.0.12/32

# Exibir porta de escuta (UDP):
wg show wg-srv listen-port
    # 51443

# Exibir chave privada da interface:
wg show wg-srv private-key
    # KPi3L0AadxEqzdzIdGPvni2Nh6bgBDGpOFCa5ETelFs=

# Exibir chave publica da interface:
wg show wg-srv public-key
    # AVtrliS3dcFIGDJVLJCTYTM/+ZUHFDqMyC02E8inCBk=

# Exibindo configuração em execução:
wg show wg-srv
    # interface: wg-srv
    #   public key: AVtrliS3dcFIGDJVLJCTYTM/+ZUHFDqMyC02E8inCBk=
    #   private key: (hidden)
    #   listening port: 51443
    # 
    # peer: bfqqb9PIylURBzmhmvD6gn9y23jkM8K0/Y26RGfUolM=
    #   allowed ips: 10.77.0.11/32
    # 
    # peer: inrlReody89Z82cTf68ik83rYkTfVpLmMQFUwpt/CSQ=
    #   allowed ips: 10.77.0.12/32

# Listando chave publica dos peers:
wg show wg-srv peers
    # bfqqb9PIylURBzmhmvD6gn9y23jkM8K0/Y26RGfUolM=
    # inrlReody89Z82cTf68ik83rYkTfVpLmMQFUwpt/CSQ=

wg show wg-srv dump
    #   (priv-key here) (pub-key here)	51443	off
    #                   (pub-key cli1 1)	(none) (none) 10.77.0.11/32 0 0 0 off
    #                   (pub-key cli1 2)	(none) (none) 10.77.0.11/32 0 0 0 off

# Listando detalhes de consumo:
wg show wg-srv transfer
    # bfqqb9PIylURBzmhmvD6gn9y23jkM8K0/Y26RGfUolM=	0	0
    # inrlReody89Z82cTf68ik83rYkTfVpLmMQFUwpt/CSQ=	0	0

# Listando handshakes (negociações recentes):
wg show wg-srv latest-handshakes
    # bfqqb9PIylURBzmhmvD6gn9y23jkM8K0/Y26RGfUolM=	0
    # inrlReody89Z82cTf68ik83rYkTfVpLmMQFUwpt/CSQ=	0

# Listando ACLs:
wg show wg-srv allowed-ips
    # bfqqb9PIylURBzmhmvD6gn9y23jkM8K0/Y26RGfUolM=	10.77.0.11/32
    # inrlReody89Z82cTf68ik83rYkTfVpLmMQFUwpt/CSQ=	10.77.0.12/32

wg show wg-srv fwmark
    # off

Criar configuração para uso no cliente 1

Crie o seguinte arquivo de configuração:

  • Na sessão [Interface] chave PrivateKey, coloque a chave privada do cliente 1;
    • xx
  • Na sessão [Interface] chave Address, coloque o IP configurado para o cliente 1 no lado servidor (em [Peer] AllowedIPs do servidor);
    • xxx
  • O lado cliente não precisa da configuração [Interface] chave ListenPort;
  • Use o mesmo valor do servidor em [Interface] chave MTU;
  • Na sessão [Peer] chave PublicKey informe a chave pública do servidor;
  • Na sessão [Peer] chave Endpoint informe o IP e porta do lado servidor;
    • Troque 45.255.128.2 pelo IP do seu servidor;
  • Na sessão [Peer] chave AllowdIPs informe quais IPs de destino deseja acessar por meio do servidor;
    • Mínimo: IP do lado servidor: 10.77.0.1/32
    • Para navegação pelo servidor: 0.0.0.0/1, 128.0.0.0/1
wg-srv-client-01.conf
# Interface lado client 1
[Interface]
PrivateKey = MM6qvnIJZRrV6GigGtdk7vdJPLN6hgS1PtWj3+i+gkQ=
Address = 10.77.0.11/24
MTU = 1420

# Lado servidor
[Peer]
PublicKey = AVtrliS3dcFIGDJVLJCTYTM/+ZUHFDqMyC02E8inCBk=
Endpoint = 45.255.128.2:51443
AllowedIPs = 10.77.0.1/32, 0.0.0.0/1, 128.0.0.0/1

Coloque o arquivo acima no Wireguard do cliente e conecte-se. Deve funcionar…

7 – Conceito de ACL e relação com rotas estáticas

O WireGuard nos clientes (Android, iOS, macOS, Windows) tratam a ACL e rotas estáticas como um conceito único, embora isso não seja algo conexo.

O WireGuard possui um estágio de ACL por peer (ponto remoto) de uma interface (sessão [Peer] chave AllowedIPs baseado no IP (IPv4 e/ou IPv6) de destino que adentra o túnel.

O mínimo que devemos fazer para que um túnel WG seja funcional é permitir ao menos o IP interno da outra ponta, se nenhum IP de destino for permitido dentro do peer que participa do túnel esse peer é ativo mas inoperante (não permite envio, só recebimento);

No servidor (Linux, FreeBSD, Mikrotik) temos opção:

  • Modo QUICK (comando wg-quick) implementado o modo rápido, onde uma ACL de um peer é automaticamente convertido em uma rota estática. Esse é o modo de todos os clientes
  • Modo manual, onde cada parâmetro do peer é inserido manualmente com o comando wg, que não faz adição de rotas estáticas, cabendo ao administrador adicionar as rotas usando ip route ou algum protocolo de roteamento:
    • Podemos autorizar 0.0.0.0/0 e ::/0 sem que o túnel seja usado para acesso geral à Internet, apenas com a finalidade de equiparar o WG às mesmas funcionalidades de um túnel GRE por exemplo.

Observe o diagrama abaixo:

x

x

x

Conclusão

O WireGuard requer um pouco de prática para ser dominado, uma vez domesticado ele será um bom amigo.

Até mais,
Patrick Brandão <patrickbrandao@gmail.com>