Categoria: Redes

  • Configuração de servidor DNS com BIND

    A escolha de um servidor de DNS pode trazer algumas vantagens. A Cloudflare, por exemplo, oferece publicamente os endereços de servidores de DNS 1.1.1.2, que filtra domínios com maior potencial de malware, e o 1.1.1.3, que adicionalmente filtra domínios de conteúdo adulto. O Pi-hole é um servidor de DNS instalável em dispositivos Raspberry Pi que bloqueia anúncios na sua rede.

    Ter um servidor de DNS pode resolver alguns problemas ou trazer algumas melhorias, como direcionar pra serviços internos e filtrar o que for desejado de forma flexível. Duas situações específicas tornam isso interessante no meu ambiente:

    • Mesmo quando um computador está na mesma rede que o servidor Nextcloud, o DNS resolve para o IP do proxy reverso, hospedado em uma VPS, de forma que tráfego sai da rede local, passa pela internet e retorna para o servidor na mesma rede local. Isso é lento e ineficiente comparado ao acesso direto via IP privado, o que pode ser chato para a transferência de muitos arquivos como pode ocorrer no meu script de backup com Rclone.
    • Eventualmente em ambientes de testes pode ser necessário fazer o acesso para configuração de uma plataforma interna através do nome de domínio a ser utilizado externamente, e o registro de DNS externo não pode ser alterado ou a aplicação ainda não pode ser exposta à internet.

    Em ambos os casos, um servidor de DNS com registros apontando para o IP privado da máquina na rede local resolveria o problema.

    Berkeley Internet Name Domain, conhecido como BIND é o servidor de DNS mais utilizado na internet, especialmente em ambientes tipo Unix, e tem uma configuração relativamente simples. A instalação em um servidor Debian 13 fica:

    # apt install bind9

    Para verificar que o serviço está em habilitado e em execução:

    $ systemctl status bind9

    Por padrão ele é configurado no modo recursivo, em que ele, quando ele não tem um registro de DNS, ele busca os registros de DNS em outros servidores e devolve a resposta. Você pode verificar isso com o comando do tipo:

    $ nslookup duckduckgo.com 127.0.0.1

    E ele vai retornar o endereço de IP do site. Essa é uma configuração não muito boa de se ter por padrão em um servidor exposto publicamente porque permite que o servidor seja utilizado de forma maliciosa em ataques de DDoS por amplificação de DNS. Configurações adicionais de firewall e limitação de taxa de requisições devem ser feitas.

    Alternativamente, ele pode ser utilizado apenas no modo autoritativo, de forma que ele só resolve os endereços que ele hospeda. Essa configuração pode ser feita no arquivo /etc/bind/named.conf.options, adicionando o seguinte:

    options {
        recursion no;
    };

    Uma boa configuração a se fazer também é adicionar a linha “allow-transfer { none; };” para evitar que qualquer servidor atue como secundário e possa baixar todas as configurações de zonas.

    options {
        recursion no;
        allow-transfer { none; };
    };

    Após reiniciar o serviço, verifique que ele não consegue mais resolver domínios sem zona configurada, com o nslookup obtendo resposta REFUSED ao tentar.

    Para adicionar uma zona autoritativa, basta incluí-la no /etc/bind/named.conf.local.

    zone "exemplo.com" {
            type master;
            file "/etc/bind/exemplo.com";
    };

    E configurá-la no arquivo especificado – neste caso, /etc/bind/exemplo.com.

    ; /etc/bind/exemplo.com
    ; Time to live: tempo máximo em que outros servidores devem manter essa zona em cache
    $TTL 3600
    
    ; @ - representa a própria zona de DNS
    ; IN - classe "Internet" - padrão para TCP/IP
    ; SOA - tipo de registro - Start of Authority
    ; ns0.exemplo.com. - MNAME - nameserver primário
    ; RNAME - administrator email address
    
    @       IN SOA  ns0.exemplo.com. oliveira.d.c.outlook.com. (
                    2026090603 ; serial: determina o número de versão da zona. nameservers secundários usam esse número pra determinar se a zona de dns foi alterada
                    7200       ; refresh: tempo em segundos em que o nameserver secundário deve verificar a zona no primário (este servidor)
                    540        ; retry: intervalo em que o secundário deve tentar caso tenha falha em alcançar o primário
                    604800     ; expire: caso o secundário não consiga alcançar o primério durante esse intervalo, a zona é excluida
                    3600       ; negative caching: TTL do cache de um registro negativo (NXDOMAIN)
                    )
    
    ; nameservers autoritativos
    @       IN NS   ns0.exemplo.com.
    ;@       IN NS   ns1.exemplo.com.
    
    ; sites
    @       IN   A        192.168.11.11
    zabbix  IN   A        192.168.11.10
    torre1  IN   A        192.168.11.9
    torre2  IN   CNAME    torre1.exemplo.com.
    www     IN   CNAME    exemplo.com.
    
    ; endereço dos nameservers
    ns0     IN   A        192.168.11.3
    ;ns1     IN   A        192.168.11.4

    Repare que os nameservers são resolvidos pela própria zona. Isso pode parecer problemático por ser uma dependência circular, mas isso funciona também em servidores de DNS externos, porque esse problema é resolvido pelo chamado “glue record”, um registro que é configurado na infraestrutura do domínio de topo, como .br ou .com, que traz esse mesmo vínculo entre o domínio do nameserver e o IP.

    Uma observação: alguns nomes de domínio na configuraçã da zona terminam com um ponto, outros não. A ausência do ponto indica que o nome é relativo à zona. Então www é www.exemplo.com, zabbix é zabbix.exemplo.com. O ponto ao final indica que aquele nome é completo, como no caso do registro CNAME acima.

    As configurações podem ser validadas da seguinte forma:

    $ named-checkzone exemplo.com /etc/bind/exemplo.com

    O comando deve retornar um “OK”.

    Normalmente, as zonas de DNS contam com 2 servidores de nome, um primário e um secundário. Essa redundância tem como objetivo impedir que o domínio fique indisponível caso haja algum problema ou manutenção em um dos servidores, e isso é um padrão por causa do quão crítico pra infraestrutura da internet esse tipo de serviço é.

    No caso abordado, para uma aplicação de um serviço de DNS interno, isso pode não ser tão crítico, então o servidor secundário foi comentado no arquivo de configuração da zona. No entanto, caso fosse necessário configurar um nameserver secundário, as únicas configurações necessárias são a declaração da zona de DNS no servidor secundário no arquivo /etc/bind/named.conf.local com o servidor primário apontado, e o servidor secundário precisa ser especificado na configuração do servidor primário.

    No servidor secundário:

    zone "exemplo.com" {
        type slave;
        masters { 192.168.11.3; };
        file "/var/cache/bind/exemplo.com";
    };

    No servidor primário a linha allow-transfer deve ser adicionada para permitir que o sevidor secundário tenha acesso à configuração dessa zona específica:

    zone "exemplo.com" {
            type master;
            file "/etc/bind/exemplo.com";
            allow-transfer { 192.168.11.4; };
    };

  • DMZ virtual no Proxmox com OPNsense

    Por padrão, as máquinas virtuais do Proxmox se conectam a uma bridge ligada à interface física do servidor. Dessa forma, todas as máquinas virtuais aparecem como máquinas reais na rede física onde o servidor está conectado.

    Idealmente, as máquinas virtuais com portas expostas para a internet estariam isoladas da rede principal, mas como o roteador em uso é um roteador de uso doméstico, sem a opção de criação de VLAN ou atribuição de redes diferentes a interfaces diferentes, uma alternativa se apresentou viável: instalar um firewall como máquina virtual no Proxmox e fazer com que as máquinas virtuais se conectem a ele em vez de diretamente na rede física.

    Para o firewall, temos algumas opções de sistema operacional, as mais notáveis de código livre sendo OPNsense e pfSense. O OPNsense é um fork do pfSense, que é um fork do m0n0wall. Eles são baseados no FreeBSD. OPNsense surgiu como um fork do pfSense em grande parte por uma questão de licenciamento, sendo distribuído sob a licença simplificada BSD, e é o firewall utilizado aqui.

    Antes de criar a máquina virtual, precisamos criar pelo menos uma bridge no servidor Proxmox para a LAN do OPNsense, a qual ficarão conectadas as máquinas virtuais. A bridge vmbr0 existente no Proxmox vai ser utilizada para a WAN, conectando o OPNsense à LAN física. Para isso, no Proxmox, selecione seu servidor > System > Network e crie a bridge, dando apenas um nome.

    Após criada, aplique as configurações.

    Alternativamente, pelo terminal do Proxmox, adicione a bridge ao arquivo /etc/network/interfaces:

    auto vmbr1
    iface vmbr1 inet manual
        bridge-ports none
        bridge-stp off
        bridge-fd 0
    # OPNsense LAN
    
    auto vmbr2
    iface vmbr2 inet manual
        bridge-ports none
        bridge-stp off
        bridge-fd 0
    # OPNsense LAN2

    Vale reparar que outras bridges podem ser criadas e atribuídas a uma interface de rede na máquina virtual. Eu decidi criar duas.

    Após editado o arquivo, use o seguinte comando para aplicar a configuração:

    # ifreload -a

    Finalizada a criação das bridges, crie a máquina virtual, adicione as interfaces de rede que desejar, inicie e instale o OPNsense. Ao finalizar, reinicie e atribua às interfaces o uso como WAN ou LAN – e opcionalmente OPT1, OPT2, etc.

    Feito isso, atribua um endereço IP à elas conforme necessário. Nesse caso, a WAN permaneceu em DHCP e a LAN e OPT1 foram configuradas com IP estático – e ativado o servidor DHCP para a rede.

    Então, você já pode alterar a bridge a qual estão conectadas as interfaces de rede das máquinas virtuais, e o OPNsense já deve estar acessível via web através da LAN virtual. No entanto, ele ainda não está acessível através da WAN (a LAN física). Para isso, são necessárias três configurações:

    • Vá em Interfaces > [WAN] e desabilite a caixa “Block private networks”.
    • Vá em Firewall > Settings > Advanced e habilite a caixa “Disable reply-to on WAN rules”.
    • Em Firewall > Rules, crie uma regra para a interface WAN permitindo tráfego de entrada de “WAN net” para o OPNsense.

    Agora, você deve alterar no Proxmox a configuração da interface de rede das máquinas virtuais que desejar para que elas utilizem a bridge correspondente à interface LAN do OPNsense.

    Você vai ver que, ao pingar um IP da sua LAN física a partir de uma máquina virtual conectada ao OPNsense, a máquina virtual vai receber a resposta. Agora, basta criar a regra que vai isolar a rede LAN do OPNsense da sua LAN física.

    No OPNsense, crie uma regra para a LAN, bloqueando todo tráfego de entrada na interface LAN com destino a “WAN net” e coloque essa regra ao topo das regras padrão de permissão de entrada de tráfego na interface LAN.

    Pelo fato de OPNsense ser um firewall do tipo stateful, para garantir que nenhuma conexão já estabelecida se mantenha, vá em Firewall > Diagnostics > States e, na aba Actions, resete a tabela de estado.

    Agora, toda máquina virtual que for configurada no Proxmox e precise ficar isolada da rede LAN física, deve ser conectada à bridge correspondente à LAN do OPNsense – nesse caso, vmbr1.

    Recomendação de segurança: no OPNsense, crie um usuário, inclua ao grupo admin e, após logar nele, desabilite o usuário root.

    Posteriormente, eu vi que existem algumas opções de serviço DHCP. O padrão configurado na linha de comando é o “Dnsmasq DNS & DHCP” e é o mais leve mas parecia não ter a opção de reservas DHCP, então configurei o Kea DHCP, uma implementação mais recente desenvolvida pela Internet Systems Consortium (ISC), para ser usado com as interfaces LAN e OPT1.

    A interface OPT1 foi configurada de forma parecida à LAN mas um pouco mais restrita, com acesso bloqueado tanto à “WAN net” quanto à “LAN net”. A ideia sendo que a LAN vai abrigar os servidores em uso, já relativamente bem configurados e mantidos, enquanto a rede na interface OPT1 vai abrigar máquinas virtuais de teste.

    Outra configuração feita posteriormente: foi criada uma regra no firewall para permitir o acesso da rede WAN às redes LAN e OPT1.

    Adicionalmente, no roteador da rede física, foi configurada uma rota para as redes LAN e OPT1 através do IP do firewall na WAN.

    Dessa forma, conseguimos acessar da rede física as máquinas virtuais nas redes LAN e OPT1 através do IP individual delas, sem necessidade de configuração de encaminhamento de portas para cada uma, enquanto mantendo bloqueado o acesso das redes LAN e OPT1 à WAN.

    Para a interface LAN, foi restringido o acesso à internet, criando grupos de IPs com alias e liberando o acesso a endereços essenciais, como repositórios de pacotes do Ubuntu e CentOS Stream para manter os sistemas atualizados, servidor de VPN para manter o acesso aos serviços web pelo proxy reverso, e acesso à Cloudflare para DNS sobre TLS, de modo a melhorar a segurança sem quebrar nenhum acesso previamente utilizado.

  • Configuração do FreeRADIUS para autenticação com Google LDAPS

    Sendo uma alternativa ao ambiente Microsoft, o Google Workspace também conta com um serviço de diretório. O LDAP seguro pode ser usado para autorização e autenticação de usuários. O FreeRADIUS foi usado para implementar autenticação WPA2-Enterprise na rede Wi-Fi, com um detalhe: a autenticação precisava funcionar para 2 domínios de e-mail diferentes, de dois ambientes Google Workspace independentes.

    Enquanto a autenticação com AD no FreeRADIUS é feita através do método de desafio e resposta, MSCHAPv2, o LDAP seguro do Google não implementa esse protocolo e precisa que a senha do usuário seja enviada em texto pleno dentro de um túnel SSL. Isso pode ser feito com a combinação de protocolos EAP-TTLS/PAP. Diferente do EAP-TLS, que exige o par de certificado/chave tanto do cliente quanto do servidor, o EAP-TTLS exige o par apenas do servidor.

    O servidor utilizado foi o Ubuntu 24.04 mas o processo serve também para outras versões. Primeiro passo é criar o cliente LDAP no Google Workspace. No console de administrador, vá em Apps > LDAP > Adicionar Cliente

    Atribua as permissões necessárias para o cliente:

    Em seguida, baixe os certificados e ative o serviço.

    Agora, preparando o servidor FreeRADIUS:

    # apt install freeradius freeradius-ldap

    Diferente do CentOS, o Ubuntu já gera os certificados pro TLS automaticamente no processo de instalação.

    Diferentes clientes podem ser adicionados no arquivo /etc/freeradius/3.0/clients.conf em blocos do tipo:

    client roteador0 {
    	ipaddr = 56.125.2.213
    	secret = senhaNoPost-it
    	require_message_authenticator = yes
    	shortname = rt0
    }

    Transfira o par de certificado/chave baixado do Google Workspace para o servidor, armazenando-os em /etc/freeradius/3.0/certs/google/, onde já é esperado pelo FreeRADIUS nas configurações a se seguir.

    Partindo para os arquivos de configuração, a começar pelo LDAP, fazendo uma cópia do arquivo para cada ambiente Workspace:

    # cp -a /etc/freeradius/3.0/mods-available/{ldap_google,ldap_workspace0}
    # cp -a /etc/freeradius/3.0/mods-available/{ldap_google,ldap_workspace1}

    Edite o arquivo, adicionando ou alterando as linhas:

    ldap ldap_workspace0 {
        identity = 'nomeDeClienteObtidoNoGoogleWorkspace'
        password = 'senhaDeClienteObtidaNoGoogleWorkspace'
        base_dn = 'dc=dominio0,dc=com'
        user {
            filter = "(mail=%{%{Stripped-User-Name}:-%{User-Name}})"
        }
        certificate_file = /caminho/do/cert/cliente/ldap
        private_key_file = /caminho/da/chave/cliente/ldap
    }

    Faça o mesmo para ldap_workspace1. Habilite os módulos com:

    # ln -s /etc/freeradius/3.0/mods-available/ldap_workspace0 /etc/freeradius/3.0/mods-enabled/

    No arquivo /etc/freeradius/3.0/mods-enabled/eap, adicione ou altere as seguintes configurações:

    eap {
      default_eap_type = ttls
      ttls {
        default_eap_type = pap
      }
    }

    Caso tenha alterado os certificados a serem usados, você também vai precisar editar as configurações referentes a isso no bloco de configurações comuns de TLS.

    Você pode comentar outros módulos não utilizados, como TLS, PEAP e MSCHAPv2, deixando apenas as configurações comuns de TLS e o bloco do TTLS.

    O arquivo /etc/freeradius/3.0/sites-enabled/default tem diversas opções, muitas podem (e devem) ser desabilitadas. Edite os blocos authorize e authenticate para que fiquem como abaixo:

    server default {
      authorize {
        filter_username
        preprocess
        eap
        expiration
        logintime
      }
      authenticate {
        eap
      }
    }

    No arquivo /etc/freeradius/3.0/sites-enabled/inner-tunnel, edite os mesmos blocos, adicionando a condicional para os dois domínios:

    server inner-tunnel {
    
      authorize {
        filter_username
    
        if ("%{User-Name}" =~ /@dominio0\.com$/) {
          ldap_workspace0
          update control {
            Auth-Type := ldap_workspace0
          }
        } elsif ("%{User-Name}" =~ /@dominio1\.com$/) {
          ldap_workspace1
          update control {
            Auth-Type := ldap_workspace1
          }
        } else {
          reject
        }
    
        expiration
        logintime
      }
    
      authenticate {
        Auth-Type ldap_workspace0 {
          ldap_workspace0
        }
        Auth-Type ldap_workspace1 {
          ldap_workspace1
        }
        Auth-Type PAP {
          pap
        }
      }
    
    }
    

    Terminando a edição dos arquivos, você deve reiniciar o serviço para que as configurações tenham efeito, garantindo antes que todos os arquivos pertencem ao usuário e grupo freerad.

    # chown -hR freerad:freerad /etc/freeradius
    # systemctl restart freeradius.service

    Caso necessário, você pode testar o FreeRADIUS em modo debug parando o serviço e executando-o manualmente da seguinte forma:

    # freeradius -X

    Uma funcionalidade interessante é a de atribuir uma VLAN específica dependendo da unidade organizacional do usuário no Google Workspace.

    Para isso, basta utilizar blocos desse tipo dentro do bloco de post-auth:

    if (&Client-Shortname == "rt0" && &User-Name =~ /@dominio0\.com$/i) {
    
        if (&control:LDAP-UserDN =~ /ou=RECURSOS HUMANOS/i) {
            update outer.session-state {
                Tunnel-Type := VLAN
                Tunnel-Medium-Type := IEEE-802
                Tunnel-Private-Group-Id := "2"
            }
        }
    }

    Nesse caso, a melhor abordagem foi usar a condicional considerando o cliente do RADIUS e o ambiente Workspace porque os dois ambientes podem ter UOs diferentes e VLANs com IDs diferentes.

    Como se pode ver pelo sinal =~ a checagem da UO não é exata e o mesmo nome poderia ser encontrado em outra UO, o que pode fazer com que a VLAN errada seja atribuída a um usuário.

    Uma forma mais adequada de atribuir uma VLAN seria, ao invés de usar as unidades organizacionais do Workspace para determinar a VLAN diretamente, usar as unidades organizacionais para atribuir usuários a grupos dinâmicos como rh-wifi@dominio0.com que então vão ser verificados pelo FreeRADIUS da seguinte forma:

    if (LDAP-Group == "cn=rh-wifi,ou=Groups,dc=dominio0,dc=com") {
        update outer.session-state {
            Tunnel-Type := VLAN
            Tunnel-Medium-Type := IEEE-802
            Tunnel-Private-Group-Id := "2"
        }
    }
  • Problema: timeout em sites atrás do proxy reverso via OpenVPN

    Um dia o nginx que configurei como proxy reverso aqui passou a dar timeout ao tentar carregar o Nextcloud. Ao investigar, verifiquei que mesmo ao fazer a solicitação ao servidor Nextcloud a partir do próprio servidor que hospeda o nginx/OpenVPN, através do comando abaixo, a solicitação não completava.

    $ curl -v http://10.8.0.3

    As solicitações feitas dentro da LAN funcionavam, indicando que o problema acontecia apenas dentro da VPN. No entanto, dentro da VPN o ping funcionava, solicitações para outras páginas do Nextcloud também funcionavam, como:

    $ curl -v http://10.8.0.3/status.php

    Tentei aprofundar a investigação mas eu não sou nenhum especialista em redes, só um entusiasta que se mete profissionalmente. Uma explicação que consegui foi que o problema podia ser relacionado ao MTU (maximum transmission unit) da interface virtual de rede do OpenVPN.

    Tanto a interface virtual do OpenVPN (tun0) quanto a interface de rede da máquina (eth0) possuíam o mesmo MTU: 1500 bytes. Isso pode ser verificado com:

    $ ip a

    Diminui o MTU do tun0 para 1380, tanto no servidor quanto no cliente, que foi uma sugestão que encontrei e funcionou. Esqueci o problema até acontecer com outra instalação do Nextcloud que mantenho. Mesmo problema, mesma solução. Eventualmente retornei o MTU pra 1500 e continuou funcionando.

    O blog não existia na época da primeira ocorrência com o Nextcloud. Agora, tive o mesmo problema com o WordPress e o novo Nextcloud. E o problema parece inconsistente. Tudo funciona, até que de repende para. E em momentos diferentes, sem nenhum gatilho claro, mas claramente alguma tentativa de enviar um pacote maior que não poderia ser fragmentado falhou.

    Dessa vez parei pra investigar um pouco melhor. Já que o MTU da tun0 é 1500, um ping com tamanho de 1472 bytes (-20 do cabeçalho IP -8 do cabeçalho ICMP) deve passar sem ser fragmentado. Não passou. 100% dos pacotes perdidos. Fui baixando até encontrar o ponto onde os pings tem resposta: 1396 bytes. MTU de 1424 bytes.

    Testei então: ping sem opções definidas e com tamanhos 1396 e 1397 bytes, monitorando também com o tcpdump tanto no servidor quanto no cliente:

    $ ping 10.8.0.3
    $ ping -M do -s 1396 10.8.0.3
    $ ping -M do -s 1397 10.8.0.3

    Para o tcpdump:

    # tcpdump -i tun0 icmp

    Resultados:

    • “ping 10.8.0.3” e “ping -M do -s 1396 10.8.0.3”:
      • pra cada 10 pings, 0% de perda de pacotes.
      • tcpdump reporta 20 pacotes capturados tanto no servidor quanto no cliente: solicitação e resposta

    Ótimo. Agora:

    • “ping -M do -s 1397 10.8.0.3” e valores acima:
      • pra cada 10 pings, 100% de perda de pacotes
      • tcpdump reporta 10 pacotes capturados no servidor, 20 no cliente: o pacote sai do servidor e chega ao cliente, que responde, mas as respostas do cliente não chegam ao servidor.

    O mesmo foi feito pingando do cliente para o servidor. Mesmo sucesso para pacotes de 1396 bytes e menores. Já com

    • ping -M do -s 1397 10.8.0.1:
      • pra cada 10 pings, 100% de perda de pacotes
      • tcpdump reporta 10 pacotes capturados no cliente, 0 no servidor.

    Ou seja, o problema está no envio de pacotes dos clientes para o servidor através do túnel.

    O ping não alerta que o pacote é grande demais nem dá qualquer erro específico, apenas para pings com tamanho acima de 1472 (que resultariam num pacote acima do MTU). Em vez disso, apenas falha silenciosamente.

    Adicionalmente ao ping, fiz testes com requisições às páginas que resultavam em timeout usando curl e monitorando com tcpdump.

    Solução: baixar o valor do MTU da interface tun0 do servidor e clientes da VPN para 1424 bytes: tamanho total do maior pacote do ping que funcionou (1396 de payload, 20 do cabeçalho IP e 8 do cabeçalho ICMP).

    Isso pode ser feito de forma não persistente com:

    # ip link set dev tun0 mtu 1424

    O MTU vai voltar para 1500 quando o serviço do OpenVPN for reiniciado. Para configurar de forma persistente, inclua essa linha nos arquivos de configuração do OpenVPN do servidor e dos clientes:

    tun-mtu 1424

    Eu ainda não entendi 100% o que causa esse problema e ele não parece afetar todos os clientes igualmente ou ao mesmo tempo. O servidor recebia resposta do ping com payload de 1472 de alguns clientes sem problemas, que exibiam a página e operavam com a MTU padrão de 1500 bytes no tun0.

    Até então, após a mudança para o MTU de 1424, o problema não reincidiu. Sendo mais conservador, eu colocaria um valor mais baixo, pra deixar uma margem pra possíveis alterações que possam vir a acontecer no OpenVPN ou nos outros servidores, masss eu tô aqui pra ver o que acontece.

  • Instalação do FreeRADIUS integrado com Active Directory

    RADIUS é um protocolo de rede que oferece gerenciamento centralizado de autorização e autenticação para acesso de usuários a serviços de rede. Muito usado, por exemplo, como uma alternativa mais segura de acesso a uma rede Wi-Fi, onde cada usuário usa suas credenciais para se conectar, em vez de todos compartilharem uma única senha.

    FreeRADIUS é um sistema livre e aberto que implementa esse protocolo e pode ser configurado pra usar diferentes back-ends para autorização e autenticação, um deles é o Active Directory.

    Pra configurar esse sistema, garanta antes que o servidor RADIUS possa encontrar e ingressar no domínio – aqui tratado como exemplo.com:

    • Domínio e o controlador de domínio podem ser encontrados por consulta de DNS e são acessíveis na rede.
    • O arquivo /etc/hosts do servidor deve conter o FQDN especificado, algo como:
    127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
    ::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
    192.168.0.10 radius-server.exemplo.com radius-server

    Após isso, instale e configure o Samba, que vai ser usado para ingressar o computador no domínio. A partir daqui, as instruções são válidas para sistemas da família Red Hat, tendo sido usado o CentOS Stream 9.

    # dnf install samba

    Adapte a configuração abaixo para o seu domínio, alterando ou adicionando os seguintes parâmetros no arquivo /etc/samba/smb.conf :

    [global]
        workgroup = EXEMPLO
        security = ads
        winbind use default domain = yes
        realm = EXEMPLO.COM
    
        idmap config * : backend = tdb
        idmap config * : range = 10000-19999
    
        idmap config EXEMPLO : backend = rid
        idmap config EXEMPLO : range = 20000-99999
    

    Remova também o parâmetro a seguir para evitar o risco de conflito na autenticação:

    [global]
        passdb backend = tdbsam

    Verifique se há algum erro na sua configuração com

    # testparm

    Agora, para ingressar o servidor no domínio:

    # net ads join -U Administrator

    Instale o pacote samba-winbind-clients, habilite o serviço winbind e teste a autenticação com ntlm_auth:

    # dnf install samba-winbind-clients
    # systemctl enable --now winbind.service
    # ntlm_auth --request-nt-key --username=daniel --password='senhaqueanoteinoblocodenotas'

    Um output como

    :  (0x0)

    indica sucesso.

    Agora que o servidor já faz parte do domínio e conseguimos autenticar usuários com ntlm_auth, podemos instalar os pacotes do FreeRADIUS para então configurá-lo

    # dnf install freeradius freeradius-utils

    Pra autenticação no AD, vamos usar a combinação de protocolos PEAP/MSCHAPv2.

    Edite a o módulo mschap localizado em /etc/raddb/mods-enabled/mschap para alterar as seguintes configurações

    mschap {
        use_mppe = yes
        require_encryption = yes
        require_strong = yes
        ntlm_auth = "/usr/bin/ntlm_auth --request-nt-key --username=%{%{Stripped-User-Name}:-%{%{User-Name}:-None}} --challenge=%{%{mschap:Challenge}:-00} --nt-response=%{%{mschap:NT-Response}:-00}"
    }

    Edite o módulo eap localizado em /etc/raddb/mods-enabled/eap para alterar a seguinte configuração:

    eap {
        default_eap_type = peap
    }

    Dica: os arquivos de configuração do FreeRADIUS são extensivamente comentados. Isso é ótimo porque ajuda a entender a configuração já na hora. Mas se quiser ver só a configuração, sem os comentários e linhas em branco:

    $ grep -vE '^\s*#|^\s*$' /caminho/para/arquivo.txt

    Na pasta /etc/raddb/certs, execute o arquivo bootstrap para gerar os certificados necessários para o TLS usado no PEAP.

    Adicione o usuário radiusd ao grupo wbpriv para que o FreeRADIUS tenha acesso para ler a resposta do winbind à solicitação de autenticação, através do socket em /var/lib/samba/winbindd_privileged/pipe

    # usermod -aG wbpriv radiusd

    Abra as portas necessárias no firewall:

    # firewall-cmd --permanent --add-port=1812/udp
    # firewall-cmd --permanent --add-port=1813/udp
    # firewall-cmd --reload

    E agora basta iniciar o serviço radiusd:

    # systemctl enable --now radiusd.service

    Você pode testar a autenticação pelo FreeRADIUS com

    radtest -t mschap daniel senhaqueanoteinoblocodenotas localhost 0 testing123

    e configurar outros clientes do FreeRADIUS em /etc/raddb/clients.conf

    Alguns clientes podem não aceitar o certificado gerado com as configurações padrão do FreeRADIUS, então é recomendado ajustar as configurações pra que o certificado seja emitido corretamente para o FQDN do servidor. O Easy RSA também pode ajudar a gerar e manter os certificados.

  • Configuração de servidor OpenVPN

    OpenVPN é um sistema de rede virtual privada (VPN), usado pra criar conexões seguras entre dispositivos, protegendo a troca de informações mesmo em trajetos não confiáveis, como a internet. Implementa tanto aplicação de servidor quanto de cliente e é distribuído sob a licença GPL-2.0.

    O sistema funciona com base em infraestrutura de chave pública (PKI). Pra configurar a autenticação de forma segura é necessário gerar certificados SSL e chaves para uma autoridade certificadora (CA), para o servidor e para os clientes da VPN.

    Felizmente, não precisamos tocar diretamente no OpenSSL, que é bem complexo. Em vez disso, a gente usa o EasyRSA, uma ferramenta que nos ajuda a gerar as chaves e certificados que a gente precisa.

    Considerando uma instalação do Debian ou Ubuntu server:

    # apt install openvpn easy-rsa

    Pra facilitar e deixar a configuração organizada, copie a pasta do EasyRSA para dentro da pasta de configuração do OpenVPN.

    # cp -r /usr/share/easy-rsa /etc/openvpn/

    Vá para a pasta /etc/openvpn/easy-rsa, edite copie o arquivo vars.example como var e descomente as linhas que quiser editar de acordo com a sua preferência. Configurações sugeridas:

    set_var EASYRSA_KEY_SIZE        4096
    set_var EASYRSA_CERT_EXPIRE     731
    set_var EASYRSA_CRL_DAYS        366
    set_var  EASYRSA_FIX_OFFSET 30

    Dessa forma, os certificados serão válidos por 2 anos, a lista de revogação de certificados (CRL) por 1 ano, e todos os certificados vão ser emitidos com validade fixa a partir de 30 de Janeiro.

    Após configurado, podemos iniciar nossa PKI e gerar o CA:

    # bash easyrsa init-pki
    # bash easyrsa build-ca

    Ao gerar a chave do CA, uma senha será pedida pra criptografar a chave do CA.

    Deve-se também gerar a chave de Diffie-Hellman, que é usada para gerar a chave simétrica da conexão de VPN a ser estabelecida.

    # bash easyrsa gen-dh

    Opcionalmente, para maior segurança, pode-se gerar uma chave de autenticação para que o servidor exija uma assinatura válida nos pacotes recebidos dos clientes.

    # openvpn --genkey secret pki/tls-auth.key

    Ao gerar o par de chaves do servidor, é uma boa ideia gerar a chave sem senha pra que o serviço possa ser iniciado junto com o sistema:

    # bash easyrsa build-server-full nome_do_servidor nopass

    A senha da chave do CA ainda será pedida para assinar o certificado do servidor.

    Assim como para o servidor, você pode escolher deixar as chaves dos clientes com senha ou não passando o parâmetro opcional nopass.

    # bash easyrsa build-client-full nome_do_cliente0 nopass

    Agora, a configuração do servidor e dos clientes vai depender do propósito da VPN: pode ser um gateway, pode ser apenas para conectar um cliente ao outro, pode ser pra conectar clientes à uma LAN.

    Crie um arquivo com extensão .conf na pasta /etc/openvpn server, como por exemplo config_do_servidor.conf com esse conteúdo de exemplo – adapte-o para a sua necessidade:

    # Configurações da conexão
    # Descomente a linha abaixo e coloque o IP do seu servidor caso ele esteja dentro de uma LAN
    ;local 192.168.0.10
    port 1194
    proto udp4
    dev tun0
    keepalive 10 120
    persist-key
    persist-tun
    
    # As linhas abaixo determinam a rede privada que seu servidor vai criar
    server 10.8.0.0 255.255.255.0
    topology subnet
    push "route 10.8.0.0 255.255.255.0"
    
    # Descomente a linha abaixo e substitua a LAN pela sua caso queira que os clientes tenham uma rota para a LAN do servidor
    ;push "route 192.168.0.0 255.255.255.0"
    
    # Descomente a linha abaixo caso queira que o cliente use o servidor de VPN como gateway
    ;push "redirect-gateway def1 bypass-dhcp"
    
    # Configura resolvedores de DNS alternativos
    ;push "dhcp-option DNS 208.67.222.222"
    ;push "dhcp-option DNS 208.67.220.220"
    
    # Permite que clientes da VPN possam alcançar outros
    ;client-to-client
    
    # Limita o número de clientes na VPN
    ;max-clients 5
    
    # Configurações do processo
    verb 3
    explicit-exit-notify 1
    status /var/log/openvpn/status-conext00.log
    # Reduz o privilégio de execução após inicialização para o usuário e grupo abaixo - em distribuições da família Fedora e Red Hat, existe um usuário openvpn próprio. O grupo nogroup não existe.
    user nobody
    group nogroup
    # Mantém clientes com o mesmo IP na VPN
    ;ifconfig-pool-persist /var/log/openvpn/ipp.txt
    
    # Certificados e chaves necessários gerados através do easy-rsa
    ca ../easy-rsa/pki/ca.crt
    cert ../easy-rsa/pki/issued/nome_do_servidor.crt
    key ../easy-rsa/pki/private/nome_do_servidor.key
    dh ../easy-rsa/pki/dh.pem
    
    # Lista opcional de revogação de certificados
    ;crl-verify ../easy-rsa/pki/crl.pem
    
    # Chave TLS opcional para maior segurança, exigindo que pacotes recebidos tenham uma assinatura válida
    ;tls-auth ../easy-rsa/pki/tls-auth.key 0
    

    Observe que as linhas do tipo

    push "algum parâmetro"

    são configurações que também podem ser especificadas no arquivo de configuração do cliente em vez do servidor.

    Precisa-se também configurar as permissões de firewall e habilitar no kernel o encaminhamento em IPv4.

    Para habilitar o encaminhamento no kernel, adicione um arquivo /etc/sysctl.d/98-ip-fwd.conf com a seguinte linha:

    net.ipv4.ip_forward=1

    Reinicie para que tenha efeito ou

    # sysctl -w net.ipv4.ip_forward=1

    No firewall, para permitir conexão de clientes:

    # ufw allow 1194/udp

    Caso use o servidor de VPN como um gateway ou estabeleça rota do cliente para a LAN em que o servidor está:

    # ufw route allow in on tun0 out on eth0
    # ufw route allow in on eth0 out on tun0

    E configure o protocolo NAT adicionando este trecho no topo do arquivo /etc/ufw/before.rules

    ### START OF MANUAL NAT CONFIG
    # NAT table rules
    *nat
    :POSTROUTING ACCEPT [0:0]
    
    # Forward traffic through eth0 - Change to match you out-interface
    -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE
    
    # don't delete the 'COMMIT' line or these nat table rules won't
    # be processed
    COMMIT
    ### END OF MANUAL NAT CONFIG

    Lembre-se de substituir a interface física e a rede pelas do seu servidor.

    Alternativamente ao NAT, no caso da existência de uma LAN, você pode configurar no seu roteador uma rota para 10.8.0.0/24 pelo IP privado do seu servidor.

    Agora basta habilitar e iniciar o serviço:

    # systemctl enable --now openvpn-server@config_do_servidor.service

    É isso, o servidor deve estar funcionando.

    Agora precisamos que clientes se conectem. Pra isso, eles precisam de um arquivo de configuração do mesmo tipo que foi feito para o servidor. O easy-rsa não gera esses arquivos, então eu fiz um pequeno script pra resolver esse problema, que deixo em /etc/openvpn/easy-rsa/build-client-config.sh

    Conteúdo do script:

    #!/bin/bash
    
    system=$1
    client=$2
    clients_dir=./clients
    client_template_win=./clients/client.ovpn
    client_template_lnx=./clients/client.conf
    
    
    init() {
            mkdir $clients_dir
    cat <<'EOF' > $client_template_win
    client
    dev tun
    proto udp4
    remote servidor.exemplo.com 1194
    resolv-retry infinite
    nobind
    persist-key
    persist-tun
    remote-cert-tls server
    ;key-direction 1
    verb 3
    EOF
    
    cat <<'EOF' > $client_template_lnx
    client
    dev tun
    proto udp4
    remote servidor.exemplo.com 1194
    resolv-retry infinite
    nobind
    persist-key
    persist-tun
    remote-cert-tls server
    ;key-direction 1
    verb 3
    user nobody
    group nogroup
    EOF
    
            if ! [[ -f ./pki/ca.crt ]]; then
                    echo "CA não encontrado. Encerrando."
                    exit 1
            else
                    echo "" | tee -a $client_template_lnx $client_template_win
                    echo "<ca>" | tee -a $client_template_lnx $client_template_win
                    cat pki/ca.crt | tee -a $client_template_lnx $client_template_win
                    echo "</ca>" | tee -a $client_template_lnx $client_template_win
            fi
    
            if [[ -f ./pki/tls-auth.key ]]; then
                    sed -i 's/;//g' $client_template_lnx $client_template_win
                    echo "" | tee -a $client_template_lnx $client_template_win
                    echo "<tls-auth>" | tee -a $client_template_lnx $client_template_win
                    cat pki/tls-auth.key | tee -a $client_template_lnx $client_template_win
                    echo  "</tls-auth>" | tee -a $client_template_lnx $client_template_win
            else
                    echo "tls-auth.key não encontrada, prosseguindo sem"
            fi
    }
    
    if ! [[ -d $clients_dir ]]; then
            init
            exit
    fi
    
    if ! [[ -f ./pki/issued/$client.crt ]]; then
            echo "Cliente não existe"
            exit 1
    fi
    
    if [[ $system == "-l" || $system == "--linux" ]]; then
            fileExt=conf
    elif [[ $system == "-o" || $system == "--outro" ]]; then
            fileExt=ovpn
    else
            echo "Sistema não especificado"
    fi
    
    targetFile=clients/$client.$fileExt
    
    cp clients/client.$fileExt $targetFile
    
    echo "" | tee -a $targetFile
    echo "<cert>" | tee -a $targetFile
    cat pki/issued/$client.crt | tee -a $targetFile
    echo "</cert>" | tee -a $targetFile
    
    echo "" | tee -a $targetFile
    echo "<key>" | tee -a $targetFile
    cat pki/private/$client.key | tee -a $targetFile
    echo "</key>" | tee -a $targetFile

    Pra inicializar, basta executar o script sem nenhum argumento

    # bash build-client-config.sh

    Ele vai criar uma pasta clients, com um template para Linux, client.conf, e outro para Windows, client.ovpn. Edite-os conforme necessário.

    Feito isso, é possível criar o arquivo de configuração para um cliente existente com

    # bash build-client-config.sh --linux nome_do_cliente0

    ou para Windows, macOS, iOS ou Android

    # bash build-client-config.sh --outro nome_do_cliente0