Post

Implementação de DNS Anycast com FRRouting e VyOS

Implementação de DNS Anycast com FRRouting e VyOS

Nota: Este tutorial faz parte da série “DNS BIND no Oracle Linux 9”, uma coleção abrangente de guias para implementação, configuração e gerenciamento de servidores DNS. Para obter o máximo benefício, recomendamos seguir a série completa, começando pelos Fundamentos do DNS e explorando também a Implementação de DNS Anycast com Containers.

Implementação de DNS Anycast com FRRouting e VyOS

Este é um tutorial complementar à nossa série sobre implementação e configuração do DNS BIND no Oracle Linux 9. Enquanto no tutorial anterior sobre DNS Anycast abordamos a implementação em ambientes containerizados, neste artigo exploraremos uma abordagem alternativa utilizando FRRouting e VyOS, ideal para ambientes de rede mais tradicionais ou organizações que preferem trabalhar com roteadores virtuais e físicos.

Introdução ao DNS Anycast com Roteadores

O DNS Anycast é uma técnica poderosa que permite anunciar o mesmo endereço IP a partir de múltiplos locais, direcionando as consultas DNS para o servidor mais próximo do cliente. Enquanto a implementação com containers oferece flexibilidade e portabilidade, a abordagem com roteadores dedicados proporciona:

  1. Integração direta com infraestrutura de rede existente
  2. Maior controle sobre políticas de roteamento
  3. Escalabilidade em ambientes de rede tradicionais
  4. Compatibilidade com equipamentos de rede legados
  5. Menor sobrecarga em comparação com virtualização ou containerização

Neste tutorial, utilizaremos duas tecnologias principais:

  • FRRouting (FRR): Uma suite de roteamento de código aberto que implementa protocolos como BGP, OSPF e IS-IS
  • VyOS: Um sistema operacional de rede baseado em Linux que combina múltiplas aplicações de rede em uma única plataforma

Conceitos Fundamentais do FRRouting

O que é FRRouting?

FRRouting (FRR) é uma suite de roteamento de código aberto derivada do Quagga. Ela fornece implementações de protocolos de roteamento para plataformas Unix/Linux, permitindo que servidores Linux funcionem como roteadores dedicados.

Principais Características do FRR

  • Suporte a múltiplos protocolos: BGP, OSPF, RIP, IS-IS, PIM, LDP, BFD, Babel, PBR, OpenFabric e VRRP
  • Arquitetura modular: Cada protocolo é executado como um daemon separado
  • Interface de linha de comando: Similar à de roteadores Cisco IOS
  • Suporte a IPv4 e IPv6: Implementação completa para ambos os protocolos
  • Alta performance: Otimizado para ambientes de produção
  • Comunidade ativa: Desenvolvimento contínuo e suporte da comunidade

Arquitetura do FRR

O FRR utiliza uma arquitetura modular com os seguintes componentes:

  1. zebra: Daemon central que gerencia a tabela de roteamento e interage com o kernel
  2. bgpd: Daemon que implementa o protocolo BGP
  3. ospfd/ospf6d: Daemons que implementam OSPF para IPv4 e IPv6
  4. ripd/ripngd: Daemons que implementam RIP para IPv4 e IPv6
  5. isisd: Daemon que implementa o protocolo IS-IS
  6. vtysh: Interface de linha de comando para interagir com os daemons

Arquitetura do FRR

O FRR utiliza uma arquitetura modular com os seguintes componentes:

  1. zebra: Daemon central que gerencia a tabela de roteamento e interage com o kernel
  2. bgpd: Daemon que implementa o protocolo BGP
  3. ospfd/ospf6d: Daemons que implementam OSPF para IPv4 e IPv6
  4. ripd/ripngd: Daemons que implementam RIP para IPv4 e IPv6
  5. isisd: Daemon que implementa o protocolo IS-IS
  6. vtysh: Interface de linha de comando para interagir com os daemons
+-----------------------------------------------------+
|                   Usuário/Admin                   |
+-------------------------+-------------------------+
                          | vtysh (CLI)
                          V
+-------------------------+-------------------------+
|                         zebra (Daemon Central)    |
|                     (Gerencia Tabela Roteamento)  |
+--+----------------------+----------------------+--+
   |                      |                      |
   | Comunicação          | Comunicação          | Comunicação
   | (via API interna)    | (via API interna)    | (via API interna)
   V                      V                      V
+--+-------+      +-------+-------+      +-------+--+      +-------+
|  bgpd    |      |  ospfd/ospf6d |      |  ripd/   |      | ...   |
| (BGP)    |      |  (OSPF)       |      |  ripngd  |      | (outros)|
+----------+      +---------------+      +----------+      +-------+

Figura 1: Arquitetura do FRRouting

O que é VyOS?

VyOS é um sistema operacional de rede de código aberto baseado em Debian Linux. Ele fornece uma plataforma unificada para roteamento, firewall, VPN e outras funcionalidades de rede.

Principais Características do VyOS

  • Interface de linha de comando unificada: Configuração consistente para todas as funcionalidades
  • Configuração baseada em transações: Mudanças são aplicadas como um conjunto atômico
  • Suporte a virtualização: Pode ser executado em ambientes virtuais como VMware, KVM e Hyper-V
  • Ampla gama de protocolos: Suporte a BGP, OSPF, RIP, MPLS, etc.
  • Recursos avançados: Firewall stateful, NAT, VPN (IPsec, OpenVPN, WireGuard), QoS
  • Automação: API e suporte a ferramentas de automação

Arquitetura do VyOS

O VyOS utiliza uma arquitetura baseada em componentes, onde cada funcionalidade é implementada por um pacote específico. Para roteamento, o VyOS utiliza o FRRouting como backend.

Arquitetura do VyOS

O VyOS utiliza uma arquitetura baseada em componentes, onde cada funcionalidade é implementada por um pacote específico. Para roteamento, o VyOS utiliza o FRRouting como backend.

+--------------------------------------------------------------------+
|                         VyOS System                                |
+-------------------------+-------------------------+----------------+
|       Interface CLI     |        API/Web UI       |   Automação    |
+-----------+-------------+-----------+-------------+-------+--------+
            |                         |                     |
            V                         V                     V
+-----------+-------------------------+---------------------+--------+
|                      VyOS Configuration Backend                      |
|                     (Gerencia Estado e Transações)                   |
+-------------------------+-----------+--------------------------------+
                          |           |
                          V           V
+-------------------------+-----------+--------------------------------+
|       Serviços de Rede (Implementações Backend)                      |
| +-------------+ +-------------+ +-------------+ +-------------+      |
| | Firewall    | | VPN         | | DHCP/DNS    | | Roteamento  | ...  |
| | (nftables)  | | (IPsec, etc)| | (dnsmasq)   | | (FRRouting) |      |
| +-------------+ +-------------+ +-------------+ +-------------+      |
+-------------------------+-----------+--------------------------------+
                          |           |
                          V           V
+-------------------------+-----------+--------------------------------+
|                         Kernel Linux (Debian)                        |
+--------------------------------------------------------------------+

Figura 2: Arquitetura Simplificada do VyOS

Visão Geral da Arquitetura

Nossa arquitetura de DNS Anycast com FRR e VyOS consistirá em:

  1. Servidores DNS BIND: Executando o servidor DNS BIND no Oracle Linux 9
  2. Roteadores VyOS: Anunciando os prefixos Anycast via BGP
  3. FRRouting: Implementando o protocolo BGP nos servidores Linux
  4. Monitoramento: Verificando a saúde e desempenho dos servidores DNS
  5. Automação: Gerenciando a configuração como código

Arquitetura de DNS Anycast com FRR e VyOS

Nossa arquitetura de DNS Anycast com FRR e VyOS consistirá em:

  1. Servidores DNS BIND: Executando o servidor DNS BIND no Oracle Linux 9
  2. Roteadores VyOS: Anunciando os prefixos Anycast via BGP
  3. FRRouting: Implementando o protocolo BGP nos servidores Linux
  4. Monitoramento: Verificando a saúde e desempenho dos servidores DNS
  5. Automação: Gerenciando a configuração como código
+----------------------------------------------------------------------> Internet/ISP
|                                                                         ^
| BGP Peering (ASN 65000 <-> ISP ASN)                                     | Consulta DNS (IP Anycast)
V                                                                         |
+-----------------+                                                         +---------+
| Roteador VyOS   |                                                         | Cliente |
| (Local A)       |                                                         +---------+
| ASN: 65000      |
+-------+---------+
        | BGP Peering (ASN 65000 <-> 65001)
        V
+-------+---------+      +-----------------+      +-----------------+
| Switch Local    |----->| Servidor DNS 1  |----->| Servidor DNS 2  |
| (Local A)       |      | (Oracle Linux)  |      | (Oracle Linux)  |
+-----------------+      | FRR (ASN 65001) |      | FRR (ASN 65001) |
                         | IP Anycast      |      | IP Anycast      |
                         +-----------------+      +-----------------+
                                |                        ^
                                | Anuncia/Retira Rota    |
                                +------------------------+
                                  (Baseado na Saúde DNS)

Figura 3: Arquitetura de DNS Anycast com FRR e VyOS

Servidores DNS BIND

Os servidores BIND serão implantados em múltiplos locais, cada um configurado de forma idêntica para responder às mesmas consultas DNS. Utilizaremos o Oracle Linux 9 como sistema operacional.

Roteadores VyOS

Os roteadores VyOS serão responsáveis por:

  1. Estabelecer sessões BGP com roteadores upstream
  2. Anunciar os prefixos Anycast para a internet
  3. Implementar políticas de roteamento
  4. Fornecer conectividade para os servidores DNS

FRRouting nos Servidores Linux

O FRRouting será instalado nos servidores Oracle Linux 9 para:

  1. Estabelecer sessões BGP com os roteadores VyOS locais
  2. Anunciar o prefixo Anycast quando o servidor DNS estiver saudável
  3. Retirar o anúncio em caso de falha do servidor DNS

Monitoramento

O monitoramento será implementado utilizando:

  1. Prometheus: Para coleta de métricas
  2. Grafana: Para visualização
  3. Blackbox Exporter: Para testes de disponibilidade
  4. BIND Exporter: Para métricas específicas do BIND
  5. FRR Exporter: Para métricas de roteamento

Automação

Para automação, utilizaremos:

  1. Ansible: Para configuração e implantação
  2. GitLab CI/CD: Para pipelines de integração e entrega contínua
  3. Terraform: Para provisionamento de infraestrutura (opcional)

Fluxo de Consultas DNS

Em nossa arquitetura, o fluxo de consultas DNS será:

  1. Cliente envia consulta DNS para o endereço Anycast
  2. Roteadores da internet direcionam a consulta para o roteador VyOS mais próximo
  3. O roteador VyOS encaminha a consulta para o servidor BIND local
  4. O servidor BIND processa a consulta
  5. A resposta é enviada de volta ao cliente

Preparação do Ambiente

Requisitos

  • Múltiplos servidores em diferentes locais (físicos ou virtuais)
  • Oracle Linux 9 para servidores DNS
  • VyOS 1.4 (ou superior) para roteadores
  • Acesso para configuração de BGP (próprio ASN ou acordo com provedor)
  • Bloco de endereços IP para Anycast (preferencialmente /24 ou menor)

Topologia de Rede

Para este tutorial, utilizaremos a seguinte topologia:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
                    +----------------+
                    |  Internet/ISP  |
                    +--------+-------+
                             |
                    +--------+-------+
                    |  Router VyOS   |
                    |  ASN: 65000    |
                    +--------+-------+
                             |
                    +--------+-------+
                    |  Switch Local  |
                    +---+-----+------+
                        |     |
            +-----------+     +------------+
            |                              |
+-----------+-----------+    +--------------+-----------+
| Servidor DNS Primário |    | Servidor DNS Secundário  |
| Oracle Linux 9        |    | Oracle Linux 9           |
| FRRouting             |    | FRRouting                |
| ASN: 65001            |    | ASN: 65001               |
| Anycast IP: 192.0.2.53|    | Anycast IP: 192.0.2.53   |
+------------------------+    +--------------------------+

Esta topologia será replicada em cada local onde desejamos implantar o DNS Anycast.

Configuração de Rede nos Servidores

Cada servidor DNS precisa ter:

  1. Interface de gerenciamento: Para acesso administrativo (Unicast)
  2. Interface Anycast: Para tráfego DNS Anycast

Exemplo de configuração de rede no Oracle Linux 9:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Configurar interface de gerenciamento
cat > /etc/sysconfig/network-scripts/ifcfg-eth0 << EOF
TYPE=Ethernet
BOOTPROTO=static
DEVICE=eth0
ONBOOT=yes
IPADDR=198.51.100.10
NETMASK=255.255.255.0
GATEWAY=198.51.100.1
DNS1=8.8.8.8
DNS2=8.8.4.4
EOF

# Configurar interface loopback para Anycast
cat > /etc/sysconfig/network-scripts/ifcfg-lo:1 << EOF
DEVICE=lo:1
IPADDR=192.0.2.53
NETMASK=255.255.255.255
ONBOOT=yes
EOF

# Reiniciar serviço de rede
systemctl restart NetworkManager

Instalação do BIND no Oracle Linux 9

Instalaremos o BIND conforme descrito em tutoriais anteriores:

1
2
3
4
5
6
# Instalar BIND
dnf install -y bind bind-utils bind-dnssec-utils

# Criar diretórios para zonas e logs
mkdir -p /var/named/zones /var/named/data /var/named/dynamic /var/log/named
chown -R named:named /var/named /var/log/named

Configuração Básica do BIND para Anycast

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// named.conf para Anycast
options {
    directory "/var/named";
    
    listen-on port 53 { 
        127.0.0.1;
        192.0.2.53;  // Endereço Anycast
    };
    listen-on-v6 port 53 { ::1; };
    
    allow-query { any; };
    recursion no;
    
    // Configurações de desempenho para Anycast
    tcp-clients 1000;
    tcp-listen-queue 128;
    
    // Configurações de segurança
    rate-limit {
        responses-per-second 20;
        window 5;
    };
    
    // Logging
    logging {
        channel general_log {
            file "/var/log/named/general.log" versions 3 size 5m;
            severity info;
            print-time yes;
            print-severity yes;
            print-category yes;
        };
        
        category default { general_log; };
    };
};

// Zone definitions
zone "example.com" IN {
    type master;
    file "zones/example.com.zone";
    allow-transfer { none; };
};

// Include standard zones
include "/etc/named.rfc1912.zones";

Instalação e Configuração do FRRouting

Instalação do FRRouting no Oracle Linux 9

1
2
3
4
5
6
7
8
9
10
11
12
# Adicionar repositório FRRouting
dnf install -y https://rpm.frrouting.org/repo/frr-stable-repo-1-0.el9.noarch.rpm

# Instalar FRRouting
dnf install -y frr frr-pythontools

# Habilitar daemons necessários
sed -i 's/^bgpd=no/bgpd=yes/g' /etc/frr/daemons
sed -i 's/^zebra=no/zebra=yes/g' /etc/frr/daemons

# Iniciar e habilitar serviço FRR
systemctl enable --now frr

Configuração Básica do FRRouting

Criaremos a configuração básica do FRRouting para anunciar o endereço Anycast:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# Configurar FRRouting
cat > /etc/frr/frr.conf << EOF
frr version 8.4
frr defaults traditional
hostname anycast-dns-01
log syslog informational
service integrated-vtysh-config
!
ip route 192.0.2.53/32 lo
!
router bgp 65001
 bgp router-id 198.51.100.10
 neighbor 198.51.100.1 remote-as 65000
 !
 address-family ipv4 unicast
  network 192.0.2.53/32
  neighbor 198.51.100.1 soft-reconfiguration inbound
 exit-address-family
!
line vty
!
EOF

# Definir permissões
chown frr:frr /etc/frr/frr.conf
chmod 640 /etc/frr/frr.conf

# Reiniciar FRR
systemctl restart frr

Script de Verificação de Saúde para FRRouting

Criaremos um script para verificar a saúde do servidor DNS e controlar o anúncio BGP:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#!/bin/bash
# /usr/local/bin/anycast-health-check.sh

# Verificar se o BIND está em execução
systemctl is-active named > /dev/null
if [ $? -ne 0 ]; then
    echo "Serviço BIND não está em execução. Removendo anúncio BGP..."
    
    # Remover rota Anycast
    ip route del 192.0.2.53/32
    
    # Reconfigurar FRR para parar de anunciar
    vtysh -c "configure terminal" \
          -c "router bgp 65001" \
          -c "address-family ipv4 unicast" \
          -c "no network 192.0.2.53/32" \
          -c "end" \
          -c "write"
    
    exit 1
fi

# Verificar se o servidor está respondendo a consultas
dig @127.0.0.1 example.com SOA +short > /dev/null
if [ $? -ne 0 ]; then
    echo "Servidor DNS não está respondendo a consultas. Removendo anúncio BGP..."
    
    # Remover rota Anycast
    ip route del 192.0.2.53/32
    
    # Reconfigurar FRR para parar de anunciar
    vtysh -c "configure terminal" \
          -c "router bgp 65001" \
          -c "address-family ipv4 unicast" \
          -c "no network 192.0.2.53/32" \
          -c "end" \
          -c "write"
    
    exit 1
fi

# Verificar se o anúncio BGP está ativo
ip route show | grep 192.0.2.53/32 > /dev/null
if [ $? -ne 0 ]; then
    echo "Servidor DNS saudável. Ativando anúncio BGP..."
    
    # Adicionar rota Anycast
    ip route add 192.0.2.53/32 dev lo
    
    # Reconfigurar FRR para anunciar
    vtysh -c "configure terminal" \
          -c "router bgp 65001" \
          -c "address-family ipv4 unicast" \
          -c "network 192.0.2.53/32" \
          -c "end" \
          -c "write"
fi

exit 0

Configuração do Cron para Verificação Periódica

1
2
3
4
5
# Tornar o script executável
chmod +x /usr/local/bin/anycast-health-check.sh

# Adicionar ao crontab
echo "* * * * * /usr/local/bin/anycast-health-check.sh >> /var/log/anycast-health.log 2>&1" | crontab -

Instalação e Configuração do VyOS

Instalação do VyOS

O VyOS pode ser instalado como uma máquina virtual ou em hardware físico. Para este tutorial, assumiremos que você já tem o VyOS instalado e configurado com acesso básico.

Configuração Básica do VyOS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# Entrar no modo de configuração
configure

# Configurar interfaces
set interfaces ethernet eth0 address 203.0.113.1/24
set interfaces ethernet eth1 address 198.51.100.1/24

# Configurar sistema
set system host-name vyos-anycast-router
set system login user vyos authentication plaintext-password 'your-secure-password'

# Configurar BGP para upstream (Internet)
set protocols bgp system-as 65000
set protocols bgp neighbor 203.0.113.254 remote-as 64512
set protocols bgp neighbor 203.0.113.254 update-source 203.0.113.1
set protocols bgp address-family ipv4-unicast network 192.0.2.53/32

# Configurar BGP para servidores DNS locais
set protocols bgp neighbor 198.51.100.10 remote-as 65001
set protocols bgp neighbor 198.51.100.10 update-source 198.51.100.1
set protocols bgp neighbor 198.51.100.11 remote-as 65001
set protocols bgp neighbor 198.51.100.11 update-source 198.51.100.1

# Configurar políticas de roteamento
set policy route-map ANYCAST-OUT rule 10 action permit
set policy route-map ANYCAST-OUT rule 10 match ip address prefix-list ANYCAST-PREFIX
set policy prefix-list ANYCAST-PREFIX rule 10 action permit
set policy prefix-list ANYCAST-PREFIX rule 10 prefix 192.0.2.53/32
set policy prefix-list ANYCAST-PREFIX rule 10 le 32

# Aplicar políticas de roteamento
set protocols bgp neighbor 203.0.113.254 route-map export ANYCAST-OUT

# Configurar firewall para permitir tráfego DNS
set firewall name WAN-IN rule 10 action accept
set firewall name WAN-IN rule 10 protocol tcp
set firewall name WAN-IN rule 10 destination port 53
set firewall name WAN-IN rule 20 action accept
set firewall name WAN-IN rule 20 protocol udp
set firewall name WAN-IN rule 20 destination port 53

# Aplicar firewall à interface WAN
set interfaces ethernet eth0 firewall in name WAN-IN

# Salvar configuração
commit
save

Configuração Avançada do VyOS para Anycast

Para uma configuração mais avançada, podemos adicionar:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Configurar comunidades BGP para controle de anúncios
set policy community-list standard NO-EXPORT rule 10 action permit
set policy community-list standard NO-EXPORT rule 10 regex "65000:0"

# Configurar route-map para controlar anúncios baseados em comunidades
set policy route-map ANYCAST-OUT rule 20 action deny
set policy route-map ANYCAST-OUT rule 20 match community NO-EXPORT

# Configurar BFD para detecção rápida de falhas
set protocols bfd peer 198.51.100.10 multihop
set protocols bfd peer 198.51.100.11 multihop
set protocols bgp neighbor 198.51.100.10 bfd
set protocols bgp neighbor 198.51.100.11 bfd

# Configurar VRRP para alta disponibilidade de roteadores
set high-availability vrrp group 1 interface eth1
set high-availability vrrp group 1 virtual-address 198.51.100.254/24
set high-availability vrrp group 1 priority 200
set high-availability vrrp group 1 preempt true

# Salvar configuração
commit
save

Integração entre FRRouting e VyOS

Estabelecimento de Sessão BGP

Para verificar se a sessão BGP foi estabelecida corretamente:

No servidor Oracle Linux com FRRouting:

1
2
3
4
5
6
7
8
# Verificar status da sessão BGP
vtysh -c "show ip bgp summary"

# Verificar rotas anunciadas
vtysh -c "show ip bgp"

# Verificar se o prefixo Anycast está sendo anunciado
vtysh -c "show ip bgp 192.0.2.53/32"

No roteador VyOS:

1
2
3
4
5
6
7
8
# Verificar status da sessão BGP
show ip bgp summary

# Verificar rotas recebidas
show ip bgp

# Verificar se o prefixo Anycast está sendo recebido
show ip bgp 192.0.2.53/32

Configuração de Políticas de Roteamento

Para implementar políticas de roteamento mais avançadas:

No servidor Oracle Linux com FRRouting:

1
2
3
4
5
6
7
8
9
10
11
12
# Configurar route-map para adicionar comunidades BGP
vtysh -c "configure terminal" \
      -c "ip prefix-list ANYCAST-PREFIX seq 10 permit 192.0.2.53/32" \
      -c "route-map ANYCAST-OUT permit 10" \
      -c "match ip address prefix-list ANYCAST-PREFIX" \
      -c "set community 65001:100" \
      -c "exit" \
      -c "router bgp 65001" \
      -c "address-family ipv4 unicast" \
      -c "neighbor 198.51.100.1 route-map ANYCAST-OUT out" \
      -c "end" \
      -c "write"

No roteador VyOS:

1
2
3
4
5
6
7
8
9
10
11
12
13
# Configurar tratamento de comunidades BGP
set policy community-list standard PRIMARY rule 10 action permit
set policy community-list standard PRIMARY rule 10 regex "65001:100"

set policy route-map ANYCAST-UPSTREAM rule 10 action permit
set policy route-map ANYCAST-UPSTREAM rule 10 match community PRIMARY
set policy route-map ANYCAST-UPSTREAM rule 10 set community "65000:100"

set protocols bgp neighbor 203.0.113.254 route-map export ANYCAST-UPSTREAM

# Salvar configuração
commit
save

Monitoramento de DNS Anycast com FRRouting e VyOS

Monitoramento do FRRouting

Para monitorar o FRRouting, podemos usar o FRR Exporter para Prometheus:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# Instalar FRR Exporter
dnf install -y golang
go get github.com/tynany/frr_exporter
cd ~/go/src/github.com/tynany/frr_exporter
make
cp frr_exporter /usr/local/bin/

# Criar serviço systemd para FRR Exporter
cat > /etc/systemd/system/frr_exporter.service << EOF
[Unit]
Description=FRR Exporter
After=network.target

[Service]
User=frr
ExecStart=/usr/local/bin/frr_exporter
Restart=always

[Install]
WantedBy=multi-user.target
EOF

# Iniciar e habilitar serviço
systemctl enable --now frr_exporter

Monitoramento do VyOS

Para monitorar o VyOS, podemos usar SNMP:

1
2
3
4
5
6
7
8
# Configurar SNMP no VyOS
set service snmp community public authorization ro
set service snmp location "Datacenter A"
set service snmp contact "admin@example.com"

# Salvar configuração
commit
save

E então configurar o Prometheus para coletar métricas via SNMP:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# prometheus/prometheus.yml
scrape_configs:
  - job_name: 'snmp'
    static_configs:
      - targets:
        - 198.51.100.1  # VyOS router
    metrics_path: /snmp
    params:
      module: [if_mib]
    relabel_configs:
      - source_labels: [__address__]
        target_label: __param_target
      - source_labels: [__param_target]
        target_label: instance
      - target_label: __address__
        replacement: snmp_exporter:9116

Dashboard Grafana para DNS Anycast com FRR e VyOS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
{
  "annotations": {
    "list": [
      {
        "builtIn": 1,
        "datasource": "-- Grafana --",
        "enable": true,
        "hide": true,
        "iconColor": "rgba(0, 211, 255, 1)",
        "name": "Annotations & Alerts",
        "type": "dashboard"
      }
    ]
  },
  "editable": true,
  "gnetId": null,
  "graphTooltip": 0,
  "id": 1,
  "links": [],
  "panels": [
    {
      "aliasColors": {},
      "bars": false,
      "dashLength": 10,
      "dashes": false,
      "datasource": null,
      "fieldConfig": {
        "defaults": {
          "custom": {}
        },
        "overrides": []
      },
      "fill": 1,
      "fillGradient": 0,
      "gridPos": {
        "h": 8,
        "w": 12,
        "x": 0,
        "y": 0
      },
      "hiddenSeries": false,
      "id": 2,
      "legend": {
        "avg": false,
        "current": false,
        "max": false,
        "min": false,
        "show": true,
        "total": false,
        "values": false
      },
      "lines": true,
      "linewidth": 1,
      "nullPointMode": "null",
      "options": {
        "alertThreshold": true
      },
      "percentage": false,
      "pluginVersion": "7.3.7",
      "pointradius": 2,
      "points": false,
      "renderer": "flot",
      "seriesOverrides": [],
      "spaceLength": 10,
      "stack": false,
      "steppedLine": false,
      "targets": [
        {
          "expr": "frr_bgp_peer_state{peer_as=\"65000\"}",
          "interval": "",
          "legendFormat": "BGP State - {{instance}}",
          "refId": "A"
        }
      ],
      "thresholds": [],
      "timeFrom": null,
      "timeRegions": [],
      "timeShift": null,
      "title": "BGP Session State",
      "tooltip": {
        "shared": true,
        "sort": 0,
        "value_type": "individual"
      },
      "type": "graph",
      "xaxis": {
        "buckets": null,
        "mode": "time",
        "name": null,
        "show": true,
        "values": []
      },
      "yaxes": [
        {
          "format": "short",
          "label": null,
          "logBase": 1,
          "max": null,
          "min": null,
          "show": true
        },
        {
          "format": "short",
          "label": null,
          "logBase": 1,
          "max": null,
          "min": null,
          "show": true
        }
      ],
      "yaxis": {
        "align": false,
        "alignLevel": null
      }
    },
    {
      "aliasColors": {},
      "bars": false,
      "dashLength": 10,
      "dashes": false,
      "datasource": null,
      "fieldConfig": {
        "defaults": {
          "custom": {}
        },
        "overrides": []
      },
      "fill": 1,
      "fillGradient": 0,
      "gridPos": {
        "h": 8,
        "w": 12,
        "x": 12,
        "y": 0
      },
      "hiddenSeries": false,
      "id": 4,
      "legend": {
        "avg": false,
        "current": false,
        "max": false,
        "min": false,
        "show": true,
        "total": false,
        "values": false
      },
      "lines": true,
      "linewidth": 1,
      "nullPointMode": "null",
      "options": {
        "alertThreshold": true
      },
      "percentage": false,
      "pluginVersion": "7.3.7",
      "pointradius": 2,
      "points": false,
      "renderer": "flot",
      "seriesOverrides": [],
      "spaceLength": 10,
      "stack": false,
      "steppedLine": false,
      "targets": [
        {
          "expr": "frr_bgp_peer_prefixes_received{peer_as=\"65000\"}",
          "interval": "",
          "legendFormat": "Prefixes Received - {{instance}}",
          "refId": "A"
        },
        {
          "expr": "frr_bgp_peer_prefixes_sent{peer_as=\"65000\"}",
          "interval": "",
          "legendFormat": "Prefixes Sent - {{instance}}",
          "refId": "B"
        }
      ],
      "thresholds": [],
      "timeFrom": null,
      "timeRegions": [],
      "timeShift": null,
      "title": "BGP Prefixes",
      "tooltip": {
        "shared": true,
        "sort": 0,
        "value_type": "individual"
      },
      "type": "graph",
      "xaxis": {
        "buckets": null,
        "mode": "time",
        "name": null,
        "show": true,
        "values": []
      },
      "yaxes": [
        {
          "format": "short",
          "label": null,
          "logBase": 1,
          "max": null,
          "min": null,
          "show": true
        },
        {
          "format": "short",
          "label": null,
          "logBase": 1,
          "max": null,
          "min": null,
          "show": true
        }
      ],
      "yaxis": {
        "align": false,
        "alignLevel": null
      }
    },
    {
      "aliasColors": {},
      "bars": false,
      "dashLength": 10,
      "dashes": false,
      "datasource": null,
      "fieldConfig": {
        "defaults": {
          "custom": {}
        },
        "overrides": []
      },
      "fill": 1,
      "fillGradient": 0,
      "gridPos": {
        "h": 8,
        "w": 12,
        "x": 0,
        "y": 8
      },
      "hiddenSeries": false,
      "id": 6,
      "legend": {
        "avg": false,
        "current": false,
        "max": false,
        "min": false,
        "show": true,
        "total": false,
        "values": false
      },
      "lines": true,
      "linewidth": 1,
      "nullPointMode": "null",
      "options": {
        "alertThreshold": true
      },
      "percentage": false,
      "pluginVersion": "7.3.7",
      "pointradius": 2,
      "points": false,
      "renderer": "flot",
      "seriesOverrides": [],
      "spaceLength": 10,
      "stack": false,
      "steppedLine": false,
      "targets": [
        {
          "expr": "bind_incoming_queries_total",
          "interval": "",
          "legendFormat": "{{instance}} - {{type}}",
          "refId": "A"
        }
      ],
      "thresholds": [],
      "timeFrom": null,
      "timeRegions": [],
      "timeShift": null,
      "title": "DNS Queries",
      "tooltip": {
        "shared": true,
        "sort": 0,
        "value_type": "individual"
      },
      "type": "graph",
      "xaxis": {
        "buckets": null,
        "mode": "time",
        "name": null,
        "show": true,
        "values": []
      },
      "yaxes": [
        {
          "format": "short",
          "label": null,
          "logBase": 1,
          "max": null,
          "min": null,
          "show": true
        },
        {
          "format": "short",
          "label": null,
          "logBase": 1,
          "max": null,
          "min": null,
          "show": true
        }
      ],
      "yaxis": {
        "align": false,
        "alignLevel": null
      }
    },
    {
      "aliasColors": {},
      "bars": false,
      "dashLength": 10,
      "dashes": false,
      "datasource": null,
      "fieldConfig": {
        "defaults": {
          "custom": {}
        },
        "overrides": []
      },
      "fill": 1,
      "fillGradient": 0,
      "gridPos": {
        "h": 8,
        "w": 12,
        "x": 12,
        "y": 8
      },
      "hiddenSeries": false,
      "id": 8,
      "legend": {
        "avg": false,
        "current": false,
        "max": false,
        "min": false,
        "show": true,
        "total": false,
        "values": false
      },
      "lines": true,
      "linewidth": 1,
      "nullPointMode": "null",
      "options": {
        "alertThreshold": true
      },
      "percentage": false,
      "pluginVersion": "7.3.7",
      "pointradius": 2,
      "points": false,
      "renderer": "flot",
      "seriesOverrides": [],
      "spaceLength": 10,
      "stack": false,
      "steppedLine": false,
      "targets": [
        {
          "expr": "irate(ifHCInOctets{ifName=\"eth0\"}[5m])*8",
          "interval": "",
          "legendFormat": "{{instance}} - In",
          "refId": "A"
        },
        {
          "expr": "irate(ifHCOutOctets{ifName=\"eth0\"}[5m])*8",
          "interval": "",
          "legendFormat": "{{instance}} - Out",
          "refId": "B"
        }
      ],
      "thresholds": [],
      "timeFrom": null,
      "timeRegions": [],
      "timeShift": null,
      "title": "Network Traffic",
      "tooltip": {
        "shared": true,
        "sort": 0,
        "value_type": "individual"
      },
      "type": "graph",
      "xaxis": {
        "buckets": null,
        "mode": "time",
        "name": null,
        "show": true,
        "values": []
      },
      "yaxes": [
        {
          "format": "bps",
          "label": null,
          "logBase": 1,
          "max": null,
          "min": null,
          "show": true
        },
        {
          "format": "short",
          "label": null,
          "logBase": 1,
          "max": null,
          "min": null,
          "show": true
        }
      ],
      "yaxis": {
        "align": false,
        "alignLevel": null
      }
    }
  ],
  "refresh": "5s",
  "schemaVersion": 26,
  "style": "dark",
  "tags": [],
  "templating": {
    "list": []
  },
  "time": {
    "from": "now-1h",
    "to": "now"
  },
  "timepicker": {},
  "timezone": "",
  "title": "DNS Anycast with FRR and VyOS",
  "uid": "dns_anycast_frr",
  "version": 1
}

Automação com Ansible

Role Ansible para DNS Anycast com FRR

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# ansible/roles/dns_anycast_frr/tasks/main.yml
---
- name: Instalar dependências
  dnf:
    name:
      - bind
      - bind-utils
      - bind-dnssec-utils
      - https://rpm.frrouting.org/repo/frr-stable-repo-1-0.el9.noarch.rpm
    state: present

- name: Instalar FRRouting
  dnf:
    name:
      - frr
      - frr-pythontools
    state: present

- name: Habilitar daemons FRR
  lineinfile:
    path: /etc/frr/daemons
    regexp: "^{{ item }}=no"
    line: "{{ item }}=yes"
  loop:
    - zebra
    - bgpd
  notify: Restart FRR

- name: Configurar interface loopback para Anycast
  template:
    src: ifcfg-lo-anycast.j2
    dest: /etc/sysconfig/network-scripts/ifcfg-lo:1
    owner: root
    group: root
    mode: '0644'
  notify: Restart Network

- name: Criar diretórios para BIND
  file:
    path: "{{ item }}"
    state: directory
    owner: named
    group: named
    mode: '0750'
  loop:
    - /var/named/zones
    - /var/named/data
    - /var/named/dynamic
    - /var/log/named

- name: Configurar BIND
  template:
    src: named.conf.j2
    dest: /etc/named.conf
    owner: root
    group: named
    mode: '0640'
  notify: Restart BIND

- name: Copiar arquivos de zona
  template:
    src: "zones/{{ item }}.zone.j2"
    dest: "/var/named/zones/{{ item }}.zone"
    owner: named
    group: named
    mode: '0640'
  loop: "{{ dns_zones }}"
  notify: Restart BIND

- name: Configurar FRRouting
  template:
    src: frr.conf.j2
    dest: /etc/frr/frr.conf
    owner: frr
    group: frr
    mode: '0640'
  notify: Restart FRR

- name: Copiar script de verificação de saúde
  template:
    src: anycast-health-check.sh.j2
    dest: /usr/local/bin/anycast-health-check.sh
    owner: root
    group: root
    mode: '0755'

- name: Configurar cron para verificação de saúde
  cron:
    name: "Verificar saúde do DNS Anycast"
    job: "/usr/local/bin/anycast-health-check.sh >> /var/log/anycast-health.log 2>&1"
    minute: "*"
    state: present

- name: Iniciar e habilitar serviços
  systemd:
    name: "{{ item }}"
    state: started
    enabled: yes
  loop:
    - named
    - frr

Templates Ansible

Template para FRRouting

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# ansible/roles/dns_anycast_frr/templates/frr.conf.j2
frr version 8.4
frr defaults traditional
hostname {{ inventory_hostname }}
log syslog informational
service integrated-vtysh-config
!
ip route {{ anycast_ip }}/32 lo
!
router bgp {{ local_asn }}
 bgp router-id {{ ansible_default_ipv4.address }}
 neighbor {{ bgp_neighbor_ip }} remote-as {{ bgp_neighbor_asn }}
 !
 address-family ipv4 unicast
  network {{ anycast_ip }}/32
  neighbor {{ bgp_neighbor_ip }} soft-reconfiguration inbound
 exit-address-family
!
line vty
!

Template para Script de Verificação de Saúde

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# ansible/roles/dns_anycast_frr/templates/anycast-health-check.sh.j2
#!/bin/bash
# /usr/local/bin/anycast-health-check.sh

# Verificar se o BIND está em execução
systemctl is-active named > /dev/null
if [ $? -ne 0 ]; then
    echo "Serviço BIND não está em execução. Removendo anúncio BGP..."
    
    # Remover rota Anycast
    ip route del {{ anycast_ip }}/32
    
    # Reconfigurar FRR para parar de anunciar
    vtysh -c "configure terminal" \
          -c "router bgp {{ local_asn }}" \
          -c "address-family ipv4 unicast" \
          -c "no network {{ anycast_ip }}/32" \
          -c "end" \
          -c "write"
    
    exit 1
fi

# Verificar se o servidor está respondendo a consultas
dig @127.0.0.1 {{ test_domain }} SOA +short > /dev/null
if [ $? -ne 0 ]; then
    echo "Servidor DNS não está respondendo a consultas. Removendo anúncio BGP..."
    
    # Remover rota Anycast
    ip route del {{ anycast_ip }}/32
    
    # Reconfigurar FRR para parar de anunciar
    vtysh -c "configure terminal" \
          -c "router bgp {{ local_asn }}" \
          -c "address-family ipv4 unicast" \
          -c "no network {{ anycast_ip }}/32" \
          -c "end" \
          -c "write"
    
    exit 1
fi

# Verificar se o anúncio BGP está ativo
ip route show | grep {{ anycast_ip }}/32 > /dev/null
if [ $? -ne 0 ]; then
    echo "Servidor DNS saudável. Ativando anúncio BGP..."
    
    # Adicionar rota Anycast
    ip route add {{ anycast_ip }}/32 dev lo
    
    # Reconfigurar FRR para anunciar
    vtysh -c "configure terminal" \
          -c "router bgp {{ local_asn }}" \
          -c "address-family ipv4 unicast" \
          -c "network {{ anycast_ip }}/32" \
          -c "end" \
          -c "write"
fi

exit 0

Playbook Ansible para DNS Anycast com FRR

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# ansible/playbooks/dns_anycast_frr.yml
---
- name: Configurar servidores DNS Anycast com FRRouting
  hosts: dns_anycast_servers
  become: yes
  vars:
    anycast_ip: "192.0.2.53"
    local_asn: "65001"
    bgp_neighbor_ip: "{{ ansible_default_ipv4.gateway }}"
    bgp_neighbor_asn: "65000"
    test_domain: "example.com"
    dns_zones:
      - "example.com"
      - "200.168.192.in-addr.arpa"
  
  roles:
    - dns_anycast_frr

Playbook Ansible para VyOS

Para configurar o VyOS com Ansible, precisamos de um playbook específico:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# ansible/playbooks/vyos_anycast.yml
---
- name: Configurar roteadores VyOS para DNS Anycast
  hosts: vyos_routers
  gather_facts: no
  vars:
    anycast_prefix: "192.0.2.53/32"
    local_asn: "65000"
    upstream_ip: "203.0.113.254"
    upstream_asn: "64512"
    dns_server_ips:
      - "198.51.100.10"
      - "198.51.100.11"
    dns_server_asn: "65001"
  
  tasks:
    - name: Configurar interfaces
      vyos.vyos.vyos_config:
        lines:
          - set interfaces ethernet eth0 address 203.0.113.1/24
          - set interfaces ethernet eth1 address 198.51.100.1/24
    
    - name: Configurar sistema
      vyos.vyos.vyos_config:
        lines:
          - set system host-name vyos-anycast-router
    
    - name: Configurar BGP para upstream
      vyos.vyos.vyos_config:
        lines:
          - set protocols bgp system-as {{ local_asn }}
          - set protocols bgp neighbor {{ upstream_ip }} remote-as {{ upstream_asn }}
          - set protocols bgp neighbor {{ upstream_ip }} update-source 203.0.113.1
          - set protocols bgp address-family ipv4-unicast network {{ anycast_prefix }}
    
    - name: Configurar BGP para servidores DNS
      vyos.vyos.vyos_config:
        lines:
          - set protocols bgp neighbor {{ item }} remote-as {{ dns_server_asn }}
          - set protocols bgp neighbor {{ item }} update-source 198.51.100.1
      loop: "{{ dns_server_ips }}"
    
    - name: Configurar políticas de roteamento
      vyos.vyos.vyos_config:
        lines:
          - set policy route-map ANYCAST-OUT rule 10 action permit
          - set policy route-map ANYCAST-OUT rule 10 match ip address prefix-list ANYCAST-PREFIX
          - set policy prefix-list ANYCAST-PREFIX rule 10 action permit
          - set policy prefix-list ANYCAST-PREFIX rule 10 prefix {{ anycast_prefix }}
          - set policy prefix-list ANYCAST-PREFIX rule 10 le 32
    
    - name: Aplicar políticas de roteamento
      vyos.vyos.vyos_config:
        lines:
          - set protocols bgp neighbor {{ upstream_ip }} route-map export ANYCAST-OUT
    
    - name: Configurar firewall para permitir tráfego DNS
      vyos.vyos.vyos_config:
        lines:
          - set firewall name WAN-IN rule 10 action accept
          - set firewall name WAN-IN rule 10 protocol tcp
          - set firewall name WAN-IN rule 10 destination port 53
          - set firewall name WAN-IN rule 20 action accept
          - set firewall name WAN-IN rule 20 protocol udp
          - set firewall name WAN-IN rule 20 destination port 53
    
    - name: Aplicar firewall à interface WAN
      vyos.vyos.vyos_config:
        lines:
          - set interfaces ethernet eth0 firewall in name WAN-IN
    
    - name: Salvar configuração
      vyos.vyos.vyos_config:
        save: yes

Integração com GitLab CI/CD

Pipeline GitLab CI/CD para DNS Anycast com FRR e VyOS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# .gitlab-ci.yml
---
stages:
  - validate
  - build
  - test
  - deploy_dev
  - deploy_prod

variables:
  ANSIBLE_CONFIG: ansible/ansible.cfg

# Validação de sintaxe e lint
validate:
  stage: validate
  image: python:3.9-slim
  before_script:
    - apt-get update && apt-get install -y bind9utils
    - pip install ansible ansible-lint
  script:
    - ansible-playbook ansible/playbooks/dns_anycast_frr.yml --syntax-check
    - ansible-lint ansible/playbooks/dns_anycast_frr.yml
    - ansible-playbook ansible/playbooks/vyos_anycast.yml --syntax-check
    - ansible-lint ansible/playbooks/vyos_anycast.yml
  tags:
    - docker

# Testes em ambiente de desenvolvimento
test_dev:
  stage: test
  before_script:
    - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
    - eval $(ssh-agent -s)
    - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
    - mkdir -p ~/.ssh
    - chmod 700 ~/.ssh
    - echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config
  script:
    - ansible-playbook -i ansible/inventory/development/hosts.yml ansible/playbooks/dns_anycast_frr.yml --check
    - ansible-playbook -i ansible/inventory/development/hosts.yml ansible/playbooks/vyos_anycast.yml --check
  environment:
    name: development
  tags:
    - shell
  only:
    - master
    - development

# Implantação em ambiente de desenvolvimento
deploy_dev:
  stage: deploy_dev
  before_script:
    - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
    - eval $(ssh-agent -s)
    - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
    - mkdir -p ~/.ssh
    - chmod 700 ~/.ssh
    - echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config
  script:
    - ansible-playbook -i ansible/inventory/development/hosts.yml ansible/playbooks/dns_anycast_frr.yml
    - ansible-playbook -i ansible/inventory/development/hosts.yml ansible/playbooks/vyos_anycast.yml
  environment:
    name: development
  tags:
    - shell
  only:
    - master
    - development

# Implantação em ambiente de produção
deploy_prod:
  stage: deploy_prod
  before_script:
    - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
    - eval $(ssh-agent -s)
    - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
    - mkdir -p ~/.ssh
    - chmod 700 ~/.ssh
    - echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config
  script:
    - ansible-playbook -i ansible/inventory/production/hosts.yml ansible/playbooks/dns_anycast_frr.yml
    - ansible-playbook -i ansible/inventory/production/hosts.yml ansible/playbooks/vyos_anycast.yml
  environment:
    name: production
  when: manual
  tags:
    - shell
  only:
    - master

Testes e Validação de DNS Anycast com FRR e VyOS

Testes de Funcionalidade

1
2
3
4
5
6
7
8
# Verificar se o servidor responde a consultas
dig @192.0.2.53 example.com

# Verificar latência
dig @192.0.2.53 example.com +stats

# Verificar se o servidor responde a consultas TCP
dig @192.0.2.53 example.com +tcp

Testes de Roteamento

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Verificar rota para o endereço Anycast
traceroute 192.0.2.53

# Verificar anúncios BGP no FRRouting
vtysh -c "show ip bgp"
vtysh -c "show ip bgp summary"
vtysh -c "show ip bgp neighbors"
vtysh -c "show ip bgp 192.0.2.53/32"

# Verificar anúncios BGP no VyOS
ssh vyos@198.51.100.1 "show ip bgp"
ssh vyos@198.51.100.1 "show ip bgp summary"
ssh vyos@198.51.100.1 "show ip bgp neighbors"
ssh vyos@198.51.100.1 "show ip bgp 192.0.2.53/32"

Testes de Failover

Para testar o failover, podemos simular uma falha em um dos servidores:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Parar o serviço BIND em um servidor
systemctl stop named

# Verificar se o FRRouting parou de anunciar o prefixo
vtysh -c "show ip bgp"
ip route show | grep 192.0.2.53

# Verificar se o VyOS parou de receber o anúncio
ssh vyos@198.51.100.1 "show ip bgp 192.0.2.53/32"

# Verificar se as consultas ainda são respondidas (por outro servidor)
dig @192.0.2.53 example.com

# Reiniciar o serviço
systemctl start named

# Verificar se o FRRouting voltou a anunciar o prefixo
vtysh -c "show ip bgp"
ip route show | grep 192.0.2.53

# Verificar se o VyOS voltou a receber o anúncio
ssh vyos@198.51.100.1 "show ip bgp 192.0.2.53/32"

Testes de Carga

Para testar o desempenho sob carga, podemos usar ferramentas como dnsperf:

1
2
3
4
5
6
7
8
9
10
11
12
# Instalar dnsperf
dnf install -y dnsperf

# Criar arquivo de consultas
cat > queries.txt << EOF
example.com A
www.example.com A
mail.example.com A
EOF

# Executar teste de carga
dnsperf -s 192.0.2.53 -d queries.txt -c 10 -l 30

Melhores Práticas para DNS Anycast com FRR e VyOS

Segurança

  1. Filtragem de pacotes: Implemente regras de firewall para permitir apenas tráfego DNS legítimo
  2. TSIG para transferências: Use TSIG para proteger transferências de zona
  3. DNSSEC: Implemente DNSSEC para autenticar respostas DNS
  4. Autenticação BGP: Use autenticação MD5 para sessões BGP
  5. Filtragem de prefixos: Implemente filtragem de prefixos BGP para evitar anúncios indesejados
  6. Monitoramento de segurança: Implemente monitoramento e alertas para atividades suspeitas

Desempenho

  1. Dimensionamento adequado: Garanta que cada servidor tenha recursos suficientes
  2. Otimização de cache: Configure o cache do BIND para o tamanho apropriado
  3. Tuning de rede: Otimize parâmetros de rede para tráfego UDP e TCP
  4. Distribuição geográfica: Distribua servidores estrategicamente para minimizar latência
  5. Monitoramento de desempenho: Monitore métricas de desempenho e estabeleça baselines

Alta Disponibilidade

  1. Múltiplos servidores: Implante servidores em múltiplos locais
  2. Diversidade de provedores: Use diferentes provedores de rede
  3. Verificações de saúde: Implemente verificações de saúde robustas
  4. Automação de failover: Automatize o processo de failover
  5. Testes regulares: Realize testes de failover regularmente

Operações

  1. Automação: Automatize implantação, configuração e atualizações
  2. Monitoramento centralizado: Implemente monitoramento centralizado
  3. Documentação: Mantenha documentação detalhada da infraestrutura
  4. Backups: Implemente backups regulares de configuração
  5. Atualizações sem downtime: Implemente estratégias para atualizações sem interrupção

Troubleshooting de DNS Anycast com FRR e VyOS

Problemas Comuns e Soluções

Problema: Servidor não anuncia prefixo Anycast

Sintomas:

  • O endereço Anycast não aparece nas tabelas de roteamento
  • FRRouting não mostra o prefixo nos anúncios

Verificações:

1
2
3
4
5
6
7
8
9
10
11
# Verificar se o endereço está configurado na interface loopback
ip addr show lo | grep 192.0.2.53

# Verificar configuração do FRRouting
cat /etc/frr/frr.conf

# Verificar status do FRRouting
systemctl status frr
vtysh -c "show running-config"
vtysh -c "show ip bgp summary"
vtysh -c "show ip bgp"

Possíveis Causas e Soluções:

  1. Endereço não configurado: Adicionar o endereço à interface loopback
  2. Configuração incorreta do FRRouting: Verificar e corrigir a configuração
  3. FRRouting não está em execução: Iniciar o serviço FRR
  4. Filtros BGP incorretos: Verificar e corrigir os filtros de exportação

Problema: VyOS não recebe anúncios BGP

Sintomas:

  • O prefixo Anycast não aparece nas tabelas de roteamento do VyOS
  • Sessão BGP estabelecida, mas sem prefixos recebidos

Verificações:

1
2
3
4
5
6
7
8
9
# No VyOS
show ip bgp summary
show ip bgp neighbors
show ip bgp
show ip route

# No servidor com FRRouting
vtysh -c "show ip bgp neighbors"
vtysh -c "show ip bgp neighbors 198.51.100.1 advertised-routes"

Possíveis Causas e Soluções:

  1. Políticas de roteamento incorretas: Verificar e corrigir as políticas de roteamento
  2. Filtros de prefixo: Verificar se os filtros de prefixo estão permitindo o anúncio
  3. Problemas de conectividade: Verificar conectividade entre o servidor e o VyOS
  4. Configuração de BGP incorreta: Verificar parâmetros de BGP em ambos os lados

Problema: Consultas DNS não são respondidas

Sintomas:

  • Consultas para o endereço Anycast resultam em timeout
  • O servidor não responde a consultas DNS

Verificações:

1
2
3
4
5
6
7
8
9
10
11
# Verificar se o BIND está em execução
systemctl status named

# Verificar logs do BIND
tail -f /var/log/named/general.log

# Verificar se o BIND está escutando no endereço Anycast
ss -tulpn | grep 53

# Verificar configuração do BIND
cat /etc/named.conf

Possíveis Causas e Soluções:

  1. BIND não está em execução: Iniciar o serviço BIND
  2. BIND não está escutando no endereço Anycast: Verificar a configuração listen-on
  3. Firewall bloqueando tráfego: Verificar regras de firewall
  4. Configuração incorreta do BIND: Verificar e corrigir a configuração

Script de Diagnóstico

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#!/bin/bash
# anycast-diagnose.sh - Script para diagnóstico de problemas com DNS Anycast

echo "=== Diagnóstico de DNS Anycast com FRRouting e VyOS ==="
echo

echo "=== Verificando configuração de rede ==="
ip addr show lo | grep 192.0.2.53
ip route show | grep 192.0.2.53
echo

echo "=== Verificando status do FRRouting ==="
systemctl status frr
vtysh -c "show ip bgp summary"
vtysh -c "show ip bgp"
vtysh -c "show ip bgp 192.0.2.53/32"
echo

echo "=== Verificando status do BIND ==="
systemctl status named
ss -tulpn | grep 53
echo

echo "=== Verificando logs do BIND ==="
tail -20 /var/log/named/general.log
echo

echo "=== Testando consultas DNS ==="
dig @127.0.0.1 example.com +short
dig @192.0.2.53 example.com +short
echo

echo "=== Verificando latência das consultas ==="
dig @192.0.2.53 example.com +stats | grep "Query time"
echo

echo "=== Verificando conectividade com VyOS ==="
ping -c 3 198.51.100.1
echo

echo "=== Verificando anúncios BGP para VyOS ==="
vtysh -c "show ip bgp neighbors 198.51.100.1 advertised-routes"
echo

echo "=== Diagnóstico concluído ==="

Casos de Uso Avançados

DNS Anycast com DNSSEC

Para implementar DNS Anycast com DNSSEC usando FRRouting e VyOS, precisamos garantir que todos os servidores tenham as mesmas chaves DNSSEC:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# Gerar chaves DNSSEC
dnssec-keygen -a ECDSAP256SHA256 -b 256 -n ZONE example.com
dnssec-keygen -a ECDSAP256SHA256 -b 256 -f KSK -n ZONE example.com

# Distribuir chaves para todos os servidores
ansible dns_anycast_servers -m copy -a "src=/path/to/keys/ dest=/var/named/keys/"

# Configurar BIND para usar DNSSEC
cat > /etc/named.conf << EOF
options {
    // ... outras opções ...
    
    dnssec-enable yes;
    dnssec-validation auto;
};

zone "example.com" IN {
    type master;
    file "zones/example.com.signed";
    key-directory "/var/named/keys";
    auto-dnssec maintain;
    inline-signing yes;
};
EOF

# Assinar zona
dnssec-signzone -A -3 $(head -c 16 /dev/random | od -v -t x | head -1 | cut -d' ' -f2- | tr -d ' ') -N INCREMENT -o example.com -t /var/named/zones/example.com.zone

DNS Anycast com Múltiplos Provedores

Para implementar DNS Anycast com múltiplos provedores usando FRRouting e VyOS:

No FRRouting:

1
2
3
4
5
6
7
8
9
10
11
# Configuração do FRRouting com múltiplos provedores
router bgp 65001
 bgp router-id 198.51.100.10
 neighbor 198.51.100.1 remote-as 65000
 neighbor 198.51.100.2 remote-as 65002
 !
 address-family ipv4 unicast
  network 192.0.2.53/32
  neighbor 198.51.100.1 soft-reconfiguration inbound
  neighbor 198.51.100.2 soft-reconfiguration inbound
 exit-address-family

No VyOS:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Configuração do VyOS com múltiplos provedores
set protocols bgp system-as 65000
set protocols bgp neighbor 203.0.113.254 remote-as 64512
set protocols bgp neighbor 203.0.113.253 remote-as 64513
set protocols bgp address-family ipv4-unicast network 192.0.2.53/32

# Configurar políticas de roteamento para diferentes provedores
set policy route-map PROVIDER1-OUT rule 10 action permit
set policy route-map PROVIDER1-OUT rule 10 match ip address prefix-list ANYCAST-PREFIX
set policy route-map PROVIDER1-OUT rule 10 set community "64512:100"

set policy route-map PROVIDER2-OUT rule 10 action permit
set policy route-map PROVIDER2-OUT rule 10 match ip address prefix-list ANYCAST-PREFIX
set policy route-map PROVIDER2-OUT rule 10 set community "64513:100"

# Aplicar políticas de roteamento
set protocols bgp neighbor 203.0.113.254 route-map export PROVIDER1-OUT
set protocols bgp neighbor 203.0.113.253 route-map export PROVIDER2-OUT

DNS Anycast com Balanceamento de Carga

Para implementar DNS Anycast com balanceamento de carga usando FRRouting e VyOS:

No FRRouting:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Configuração do FRRouting com balanceamento de carga
ip prefix-list ANYCAST-PREFIX seq 10 permit 192.0.2.53/32

route-map ANYCAST-OUT permit 10
 match ip address prefix-list ANYCAST-PREFIX
 set community 65001:100

router bgp 65001
 bgp router-id 198.51.100.10
 neighbor 198.51.100.1 remote-as 65000
 !
 address-family ipv4 unicast
  network 192.0.2.53/32
  neighbor 198.51.100.1 route-map ANYCAST-OUT out
 exit-address-family

No VyOS:

1
2
3
4
5
6
7
8
9
# Configuração do VyOS com balanceamento de carga
set policy community-list standard PRIMARY rule 10 action permit
set policy community-list standard PRIMARY rule 10 regex "65001:100"

set policy route-map ANYCAST-UPSTREAM rule 10 action permit
set policy route-map ANYCAST-UPSTREAM rule 10 match community PRIMARY
set policy route-map ANYCAST-UPSTREAM rule 10 set community "65000:100"

set protocols bgp neighbor 203.0.113.254 route-map export ANYCAST-UPSTREAM

Comparação: DNS Anycast com Containers vs. FRR/VyOS

AspectoContainersFRR/VyOS
FlexibilidadeAlta - Fácil de implantar em qualquer ambiente que suporte containersMédia - Requer hardware ou VMs dedicados
Integração com RedeMédia - Pode exigir configurações especiais para acesso à redeAlta - Integração direta com infraestrutura de rede existente
EscalabilidadeAlta - Fácil de escalar horizontalmenteMédia - Escalabilidade limitada por hardware
DesempenhoBom - Pequena sobrecarga de containerizaçãoExcelente - Sem sobrecarga de virtualização
IsolamentoAlto - Cada instância é isoladaMédio - Compartilha recursos do sistema
GerenciamentoSimples - Ferramentas de orquestração de containersComplexo - Requer conhecimento de roteamento
CustoBaixo - Eficiente em recursosMédio a Alto - Requer hardware dedicado
CompatibilidadeLimitada com equipamentos legadosAlta com infraestrutura de rede tradicional
AutomaçãoExcelente - Integração com CI/CDBoa - Através de ferramentas como Ansible
MonitoramentoIntegrado com plataformas de containersRequer ferramentas específicas de rede

Conclusão

Neste tutorial, exploramos como implementar DNS Anycast utilizando FRRouting e VyOS, uma abordagem alternativa à implementação com containers que abordamos anteriormente. Esta abordagem é particularmente valiosa para ambientes de rede mais tradicionais ou organizações que preferem trabalhar com roteadores virtuais e físicos.

Abordamos desde os conceitos fundamentais do FRRouting e VyOS até a implementação prática, incluindo configuração de roteamento BGP, automação com Ansible e GitLab CI/CD, monitoramento e troubleshooting.

A combinação de DNS Anycast com FRRouting e VyOS oferece uma solução robusta para organizações que precisam de uma infraestrutura DNS distribuída, resiliente e de baixa latência, com integração direta com a infraestrutura de rede existente. Ao seguir as melhores práticas e implementar as técnicas descritas neste tutorial, você estará preparado para criar e gerenciar uma infraestrutura DNS Anycast eficiente e confiável.

Referências e Recursos Adicionais

This post is licensed under CC BY 4.0 by the author.