Pesquisa de site

Como encaminhar portas através de um gateway Linux com Iptables


Introdução

NAT, ou conversão de endereço de rede, é um termo geral para deturpar pacotes a fim de redirecioná-los para um endereço alternativo. Geralmente, isso é usado para permitir que o tráfego transcenda os limites da rede. Um host que implementa NAT geralmente tem acesso a duas ou mais redes e é configurado para rotear o tráfego entre elas.

Encaminhamento de porta é o processo de encaminhar solicitações de uma porta específica para outro host, rede ou porta. Como esse processo modifica o destino do pacote em trânsito, é considerado um tipo de operação NAT.

Neste tutorial, demonstraremos como usar iptables para encaminhar portas para hosts atrás de um firewall usando técnicas NAT. Isso é útil se você configurou uma rede privada, mas ainda deseja permitir determinado tráfego interno por meio de uma máquina de gateway designada.

Pré-requisitos

Para acompanhar este guia, você precisará de:

  • Configuração de dois servidores Ubuntu 20.04 no mesmo datacenter com rede privada habilitada. Em cada uma dessas máquinas, você precisará configurar uma conta de usuário não root com privilégios sudo. Você pode aprender como fazer isso com nosso guia sobre o guia de configuração inicial do servidor Ubuntu 20.04. Certifique-se de pular a Etapa 4 deste guia, pois configuraremos o firewall durante este tutorial.
  • Em um de seus servidores, configure um modelo de firewall com iptables para que funcione como seu servidor de firewall. Você pode fazer isso seguindo nosso guia Como implementar um firewall básico com Iptables no Ubuntu 20.04. Depois de concluído, seu servidor de firewall deve ter o seguinte pronto para uso:
    • iptables-persistent instalado
    • Salvou o conjunto de regras padrão em /etc/iptables/rules.v4
    • Entendimento de como adicionar ou ajustar regras editando o arquivo de regras ou usando o comando iptables

    O servidor no qual você configurou seu modelo de firewall servirá como firewall e roteador para sua rede privada. Para fins de demonstração, o segundo host será configurado com um servidor web acessível apenas por meio de sua interface privada. Você estará configurando a máquina do firewall para encaminhar as solicitações recebidas em sua interface pública para o servidor web, que será acessado em sua interface privada.

    Detalhes do host

    Antes de começar, você precisa saber quais interfaces e endereços estão sendo usados por ambos os servidores.

    Encontrando os detalhes da sua rede

    Para obter os detalhes de seus próprios sistemas, comece encontrando suas interfaces de rede. Você pode encontrar as interfaces em suas máquinas e os endereços associados a elas executando o seguinte:

    1. ip -4 addr show scope global
    Sample Output
    2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 inet 203.0.113.1/18 brd 45.55.191.255 scope global eth0 valid_lft forever preferred_lft forever 3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 inet 10.0.0.1/16 brd 10.132.255.255 scope global eth1 valid_lft forever preferred_lft forever

    A saída realçada mostra duas interfaces (eth0 e eth1) e os endereços atribuídos a cada uma delas (203.0.113.1 e 10.0.0.1 respectivamente). Para descobrir qual dessas interfaces é sua interface pública, execute este comando:

    1. ip route show | grep default
    Output
    default via 111.111.111.111 dev eth0

    As informações de interface desta saída (eth0 neste exemplo) serão a interface conectada ao seu gateway padrão. Esta é quase certamente sua interface pública.

    Encontre esses valores em cada uma de suas máquinas e use-os para acompanhar o restante deste guia.

    Dados de amostra usados neste guia

    Para tornar as coisas mais claras, usaremos os seguintes endereços vazios e atribuições de interface ao longo deste tutorial. Substitua seus próprios valores pelos listados a seguir:

    Detalhes da rede do servidor Web:

    • Endereço IP público: 203.0.113.1
    • Endereço IP privado: 10.0.0.1
    • Interface pública: eth0
    • Interface privada: eth1

    Detalhes da rede de firewall:

    • Endereço IP público: 203.0.113.2
    • Endereço IP privado: 10.0.0.2
    • Interface pública: eth0
    • Interface privada: eth1

    Configurando o Servidor Web

    Comece conectando-se ao host do seu servidor web e fazendo login com seu usuário sudo.

    Instalando o Nginx

    A primeira etapa é instalar o Nginx no host do servidor da Web e bloqueá-lo para que ele ouça apenas sua interface privada. Isso garantirá que seu servidor da web só estará disponível se você configurar corretamente o encaminhamento de porta.

    Comece atualizando o cache de pacote local:

    1. sudo apt update

    Em seguida, use apt para baixar e instalar o software:

    1. sudo apt install nginx

    Restringindo o Nginx à rede privada

    Após a instalação do Nginx, abra o arquivo de configuração do bloco de servidor padrão para garantir que ele ouça apenas a interface privada. Abra o arquivo usando seu editor de texto preferido. Aqui usaremos nano:

    1. sudo nano /etc/nginx/sites-enabled/default

    Dentro, encontre a diretiva listen. Ele deve ser listado duas vezes seguidas na parte superior da configuração:

    server {
        listen 80 default_server;
        listen [::]:80 default_server ipv6only=on;
    
        . . .
    }
    

    Na primeira diretiva listen, adicione o endereço IP privado do seu servidor web e dois pontos antes do 80 para dizer ao Nginx para escutar apenas na interface privada. Estamos apenas demonstrando o encaminhamento de IPv4 neste guia, para que você possa remover a segunda diretiva de escuta, que está configurada para IPv6.

    Em seguida, modifique as diretivas listen da seguinte forma:

    server {
        listen 10.0.0.1:80 default_server;
    
        . . .
    }
    

    Salve e feche o arquivo quando terminar. Se você usou nano, pode fazer isso pressionando CTRL + X, depois Y e ENTER.

    Agora teste o arquivo para erros de sintaxe:

    1. sudo nginx -t
    Output
    nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful

    Se não houver erros na saída, reinicie o Nginx para habilitar a nova configuração:

    1. sudo systemctl restart nginx

    Verificando a restrição de rede

    Neste ponto, é útil verificar o nível de acesso que você tem ao seu servidor web.

    Do seu servidor de firewall, tente acessar seu servidor web a partir da interface privada com o seguinte comando:

    1. curl --connect-timeout 5 10.0.0.1

    Se for bem-sucedido, sua saída resultará na seguinte mensagem:

    Output
    <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> . . .

    Se você tentar usar a interface pública, receberá uma mensagem informando que não é possível conectar:

    1. curl --connect-timeout 5 203.0.113.1
    Output
    curl: (7) Failed to connect to 203.0.113.1 port 80: Connection refused

    Esses resultados são esperados.

    Configurando o Firewall para Encaminhar a Porta 80

    Agora você trabalhará na implementação do encaminhamento de porta em sua máquina de firewall.

    Ativando o encaminhamento no kernel

    A primeira coisa que você precisa fazer é ativar o encaminhamento de tráfego no nível do kernel. Por padrão, a maioria dos sistemas tem o encaminhamento desativado.

    Para ativar o encaminhamento de porta apenas para esta sessão, execute o seguinte:

    1. echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
    Output
    1

    Para ativar o encaminhamento de porta permanentemente, você terá que editar o arquivo /etc/sysctl.conf. Você pode fazer isso abrindo o arquivo com privilégios sudo:

    1. sudo nano /etc/sysctl.conf

    Dentro do arquivo, localize e descomente a linha que diz o seguinte:

    net.ipv4.ip_forward=1
    

    Salve e feche o arquivo quando terminar.

    Em seguida, aplique as configurações neste arquivo. Primeiro execute o seguinte comando:

    1. sudo sysctl -p
    Output
    net.ipv4.ip_forward = 1

    Em seguida, execute o mesmo comando, mas substitua o sinalizador -p por --system:

    1. sudo sysctl --system
    Output
    . . . * Applying /usr/lib/sysctl.d/50-pid-max.conf ... kernel.pid_max = 4194304 * Applying /etc/sysctl.d/99-cloudimg-ipv6.conf ... net.ipv6.conf.all.use_tempaddr = 0 net.ipv6.conf.default.use_tempaddr = 0 * Applying /etc/sysctl.d/99-sysctl.conf ... net.ipv4.ip_forward = 1 * Applying /usr/lib/sysctl.d/protect-links.conf ... fs.protected_fifos = 1 fs.protected_hardlinks = 1 fs.protected_regular = 2 fs.protected_symlinks = 1 * Applying /etc/sysctl.conf ... net.ipv4.ip_forward = 1

    Adicionando regras de encaminhamento ao firewall básico

    Em seguida, você configurará seu firewall para que o tráfego que flui para sua interface pública (eth0) na porta 80 seja encaminhado para sua interface privada (eth1).

    O firewall que você configurou no tutorial de pré-requisito tem sua cadeia FORWARD definida como tráfego DROP por padrão. Você precisa adicionar regras que permitirão que você encaminhe conexões para seu servidor web. Por motivos de segurança, você bloqueará isso com bastante firmeza para que apenas as conexões que você deseja encaminhar sejam permitidas.

    Na cadeia FORWARD, você aceitará novas conexões destinadas à porta 80 que vêm de sua interface pública e viajam para sua interface privada. Novas conexões são identificadas pela extensão conntrack e serão especificamente representadas por um pacote TCP SYN como no seguinte:

    1. sudo iptables -A FORWARD -i eth0 -o eth1 -p tcp --syn --dport 80 -m conntrack --ctstate NEW -j ACCEPT

    Isso permitirá que o primeiro pacote, destinado a estabelecer uma conexão, passe pelo firewall. Você também precisará permitir qualquer tráfego subsequente em ambas as direções resultante dessa conexão. Para permitir o tráfego ESTABLISHED e RELATED entre suas interfaces pública e privada, execute os seguintes comandos. Primeiro para sua interface pública:

    1. sudo iptables -A FORWARD -i eth0 -o eth1 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

    Em seguida, para sua interface privada:

    1. sudo iptables -A FORWARD -i eth1 -o eth0 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

    Verifique se sua política na cadeia FORWARD está definida como DROP:

    1. sudo iptables -P FORWARD DROP

    Neste ponto, você permitiu que certo tráfego entre suas interfaces pública e privada continuasse através de seu firewall. No entanto, você não configurou as regras que realmente dirão ao iptables como traduzir e direcionar o tráfego.

    Adicionando as regras NAT aos pacotes diretos corretamente

    Em seguida, você adicionará as regras que dirão ao iptables como rotear seu tráfego. Você precisa executar duas operações separadas para que iptables altere corretamente os pacotes para que os clientes possam se comunicar com o servidor web.

    A primeira operação, chamada DNAT, ocorrerá na cadeia PREROUTING da tabela nat. DNAT é uma operação que altera o endereço de destino de um pacote para permitir que ele seja roteado corretamente ao passar entre as redes. Os clientes da rede pública se conectarão ao seu servidor de firewall e não terão conhecimento da topologia da sua rede privada. Portanto, você precisa alterar o endereço de destino de cada pacote para que, quando for enviado em sua rede privada, saiba como chegar corretamente ao seu servidor web.

    Como você está apenas configurando o encaminhamento de porta e não realizando NAT em todos os pacotes que atingem seu firewall, convém corresponder à porta 80 em sua regra. Você combinará os pacotes destinados à porta 80 ao endereço IP privado do seu servidor web (10.0.0.1 no exemplo a seguir):

    1. sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to-destination 10.0.0.1

    Este processo cuida de metade da imagem. O pacote deve ser roteado corretamente para o seu servidor web. No entanto, neste momento, o pacote ainda terá o endereço original do cliente como endereço de origem. O servidor tentará enviar a resposta diretamente para esse endereço, o que impossibilitará o estabelecimento de uma conexão TCP legítima.

    Na DigitalOcean, os pacotes que saem de um Droplet com um endereço de origem diferente serão descartados pelo hipervisor, portanto, seus pacotes nesse estágio nunca chegarão ao servidor da Web (o que será corrigido pela implementação do SNAT momentaneamente). Essa é uma medida antispoofing implementada para evitar ataques em que grandes quantidades de dados são solicitadas a serem enviadas ao computador da vítima, falsificando o endereço de origem na solicitação. Para saber mais, leia esta resposta em nossa comunidade.

    Para configurar o roteamento adequado, você também precisa modificar o endereço de origem do pacote, pois ele sai do firewall a caminho do servidor da web. Você precisa modificar o endereço de origem para o endereço IP privado do seu servidor de firewall (10.0.0.2 no exemplo a seguir). A resposta será enviada de volta para o firewall, que pode encaminhá-la de volta para o cliente conforme o esperado.

    Para habilitar essa funcionalidade, adicione uma regra à cadeia POSTROUTING da tabela nat, que é avaliada logo antes dos pacotes serem enviados para a rede. Você combinará os pacotes destinados ao seu servidor web por endereço IP e porta:

    1. sudo iptables -t nat -A POSTROUTING -o eth1 -p tcp --dport 80 -d 10.0.0.1 -j SNAT --to-source 10.0.0.2

    Depois que essa regra estiver em vigor, seu servidor da Web deverá estar acessível apontando seu navegador da Web para o endereço público da máquina do firewall:

    1. curl 203.0.113.2
    Output
    <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> . . .

    Sua configuração de encaminhamento de porta está concluída.

    Ajustando o Conjunto de Regras Permanentes

    Agora que você configurou o encaminhamento de porta, pode salvá-lo em seu conjunto de regras permanentes.

    Se você não se importa em perder os comentários que estão em seu conjunto de regras atual, use o comando netfilter-persistent para usar o serviço iptables e salve suas regras:

    1. sudo service netfilter-persistent save
    Output
    * Saving netfilter rules... run-parts: executing /usr/share/netfilter-persistent/plugins.d/15-ip4tables save run-parts: executing /usr/share/netfilter-persistent/plugins.d/25-ip6tables save [ OK ]

    Se você gostaria de manter os comentários em seu arquivo, abra-o e edite-o manualmente:

    1. sudo nano /etc/iptables/rules.v4

    Você precisará ajustar a configuração na tabela filter para as regras da cadeia FORWARD que foram adicionadas. Você também precisará ajustar a seção que configura a tabela nat para que você possa adicionar suas regras PREROUTING e POSTROUTING. O conteúdo será semelhante ao seguinte:

    *filter
    # Allow all outgoing, but drop incoming and forwarding packets by default
    :INPUT DROP [0:0]
    :FORWARD DROP [0:0]
    :OUTPUT ACCEPT [0:0]
    
    # Custom per-protocol chains
    :UDP - [0:0]
    :TCP - [0:0]
    :ICMP - [0:0]
    
    # Acceptable UDP traffic
    
    # Acceptable TCP traffic
    -A TCP -p tcp --dport 22 -j ACCEPT
    
    # Acceptable ICMP traffic
    
    # Boilerplate acceptance policy
    -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
    -A INPUT -i lo -j ACCEPT
    
    # Drop invalid packets
    -A INPUT -m conntrack --ctstate INVALID -j DROP
    
    # Pass traffic to protocol-specific chains
    ## Only allow new connections (established and related should already be handled)
    ## For TCP, additionally only allow new SYN packets since that is the only valid
    ## method for establishing a new TCP connection
    -A INPUT -p udp -m conntrack --ctstate NEW -j UDP
    -A INPUT -p tcp --syn -m conntrack --ctstate NEW -j TCP
    -A INPUT -p icmp -m conntrack --ctstate NEW -j ICMP
    
    # Reject anything that's fallen through to this point
    ## Try to be protocol-specific w/ rejection message
    -A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable
    -A INPUT -p tcp -j REJECT --reject-with tcp-reset
    -A INPUT -j REJECT --reject-with icmp-proto-unreachable
    
    # Rules to forward port 80 to our web server
    
    # Web server network details:
    
    # * Public IP Address: 203.0.113.1
    # * Private IP Address: 10.0.0.1
    # * Public Interface: eth0
    # * Private Interface: eth1
    # 
    # Firewall network details:
    # 
    # * Public IP Address: 203.0.113.2
    # * Private IP Address: 10.0.0.2
    # * Public Interface: eth0
    # * Private Interface: eth1
    -A FORWARD -i eth0 -o eth1 -p tcp --syn --dport 80 -m conntrack --ctstate NEW -j ACCEPT
    -A FORWARD -i eth0 -o eth1 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
    -A FORWARD -i eth1 -o eth0 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
    # End of Forward filtering rules
    
    # Commit the changes
    
    COMMIT
    
    *raw
    :PREROUTING ACCEPT [0:0]
    :OUTPUT ACCEPT [0:0]
    COMMIT
    
    *nat
    :PREROUTING ACCEPT [0:0]
    :INPUT ACCEPT [0:0]
    :OUTPUT ACCEPT [0:0]
    :POSTROUTING ACCEPT [0:0]
    
    # Rules to translate requests for port 80 of the public interface
    # so that we can forward correctly to the web server using the
    # private interface.
    
    # Web server network details:
    
    # * Public IP Address: 203.0.113.1
    # * Private IP Address: 10.0.0.1
    # * Public Interface: eth0
    # * Private Interface: eth1
    # 
    # Firewall network details:
    # 
    # * Public IP Address: 203.0.113.2
    # * Private IP Address: 10.0.0.2
    # * Public Interface: eth0
    # * Private Interface: eth1
    -A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to-destination 10.0.0.1
    -A POSTROUTING -d 10.0.0.1 -o eth1 -p tcp --dport 80 -j SNAT --to-source 10.0.0.2
    # End of NAT translations for web server traffic
    COMMIT
    
    *security
    :INPUT ACCEPT [0:0]
    :FORWARD ACCEPT [0:0]
    :OUTPUT ACCEPT [0:0]
    COMMIT
    
    *mangle
    :PREROUTING ACCEPT [0:0]
    :INPUT ACCEPT [0:0]
    :FORWARD ACCEPT [0:0]
    :OUTPUT ACCEPT [0:0]
    :POSTROUTING ACCEPT [0:0]
    COMMIT
    

    Salve e feche o arquivo depois de adicionar o conteúdo e ajustar os valores para refletir seu próprio ambiente de rede.

    Em seguida, teste a sintaxe do seu arquivo de regras:

    1. sudo sh -c "iptables-restore -t < /etc/iptables/rules.v4"

    Se nenhum erro for detectado, carregue o conjunto de regras:

    1. sudo service netfilter-persistent reload
    Output
    * Loading netfilter rules... run-parts: executing /usr/share/netfilter-persistent/plugins.d/15-ip4tables start run-parts: executing /usr/share/netfilter-persistent/plugins.d/25-ip6tables start [ OK ]

    Agora teste se o seu servidor web ainda está acessível através do endereço IP público do seu firewall:

    1. curl 203.0.113.2

    Isso deve funcionar da mesma forma que antes.

    Conclusão

    Até agora, você deve estar confortável com o encaminhamento de portas em um servidor Linux com iptables. O processo envolve permitir o encaminhamento no nível do kernel, configurar o acesso para permitir o encaminhamento do tráfego da porta específica entre duas interfaces no sistema de firewall e configurar as regras NAT para que os pacotes possam ser roteados corretamente. Isso pode parecer um processo complicado, mas também demonstra a flexibilidade da estrutura de filtragem de pacotes netfilter e do firewall iptables. Isso pode ser usado para disfarçar a topologia de sua rede privada enquanto permite que o tráfego de serviço flua livremente através de sua máquina de firewall de gateway.