[OpenBSD]

[Anterior: Redundância de Firewall com CARP e pfsync] [Conteúdo]

PF: Exemplo: Firewall para Casa ou Pequeno Escritório


Conteúdo


O Cenário

Neste exemplo, PF está rodando numa máquina OpenBSD agindo como firewall e gateway NAT para uma pequena rede em casa ou escritório. O objetivo geral é prover acesso à Internet para a rede interna e acesso limitado ao firewall pela Internet. Este documento irá guia-lo na criação de um conjunto de regras para esse fim.

A Rede

A rede está configurada da seguinte forma:
   
 
  [ COMP1 ]    [ COMP3 ]
      |            |                               ADSL
   ---+------+-----+------- fxp0 [ OpenBSD ] ep0 -------- ( Internet )
             |
         [ COMP2 ]

Existem vários computadores na rede interna; o diagrama mostra apenas três, mas o número real é irrelevante. Estes computadores são estações de trabalho usadas para navegar na Internet, ler email, chat, etc., exceto COMP3 que também roda um pequeno servidor web. A rede interna usa a faixa de ips 192.168.0.0 / 255.255.255.0.

O roteador OpenBSD é um Pentium 100 com duas placas de rede: uma 3com 3c509B (ep0) e uma Intel EtherExpress Pro/100 (fxp0). O roteador possui uma conexão ADSL para a Internet e faz NAT para compartilhar sua conexão com a rede interna. O endereço IP na interface externa é atribuído dinamicamente pelo Provedor de Acesso Internet.

O Objetivo

Os Objetivos são:

Preparação

Este documento assume que o host OpenBSD tenha sido corretamente configurado para funcionar como roteador, incluindo configuração de endereços IP, conectividade com a Internet e definição de net.inet.ip.forwarding para "1".

As regras

A seguir um passo a passo através das regras que realizarão os objetivos acima descritos.

Macros

As seguintes macros são definidas para facilitar a leitura e manutençao das regras:
int_if = "fxp0"
ext_if = "ep0"

tcp_services = "{ 22, 113 }"
icmp_types = "echoreq"

priv_nets = "{ 127.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8 }"

comp3 = "192.168.0.3"

As primeiras duas linhas definem a interface de rede onde a filtragem acontecerá. A terceira e quarta linhas listam os números de portas TCP dos serviços que serão abertos para a internet (SSH e ident/auth) e os tipos de pacotes ICMP que terão permissão de alcançar a máquina do firewall. A quinta linha define os endereços de loopback e blocos de endereçamento descritos na RFC 1918. Finalmente, a última linha define o endereço IP de COMP3.

Nota: Caso a conexão ADSL com a Internet necessite PPPoE, então, filtragem e NAT devem acontecer na interface tun0 não em ep0.

Opções

As duas opções seguintes definem a resposta padrão block para regras de filtragem, e fazem com que sejam logadas estatísticas de filtragem (statistics logging "on") para a interface externa:
set block-policy return
set loginterface $ext_if

Scrub

Não há razão para não utilizar scrubbing, recomendado para todo tráfego entrante, portanto a regra é simples como uma linha:
scrub in all

Tradução do Endereço de Rede (NAT)

Para fazer NAT para toda a rede interna a seguinte regra nat será usada:
nat on $ext_if from $int_if:network to any -> ($ext_if)

Já que o endereço IP da interface externa é atribuído dinamicamente, parênteses devem ser colocados em volta da interface, assim o PF notará qualquer alteração no endereço.

Redirecionamento

A primeira regra de redirecionamento necessária é ftp-proxy(8) assim, clientes FTP na rede interna local, poderão se conectar a servidores FTP na Internet.
rdr on $int_if proto tcp from any to any port 21 -> 127.0.0.1 port 8021

Note que esta regra funcionará apenas com conexões destinadas à porta 21. Caso usuários se conectem a servidores FTP em outras portas, então uma lista deve ser utilizada para especificar as portas de destino, por exemplo: from any to any port { 21, 2121 }.

A segunda regra de redirecionamento pega qualquer tentativa de conexão vinda da Internet em direção à porta 80 TCP no firewall. Tentativas de conexões legítimas nesta porta serão de usuários tentando acessar o servidor web da rede. Estas conexões devem ser redirecionadas para COMP3:

rdr on $ext_if proto tcp from any to any port 80 -> $comp3

Regras de Filtragem

Agora as regras de filtragem. Começando com negar por padrão:
block all

Neste ponto nada passará através do firewall, nem mesmo da rede interna. As regras seguintes abrem o firewall de acordo com os objetivos acima descritos, bem como quaisquer interfaces virtuais que se façam necessárias.

Todo sistema Unix possui uma interface de "loopback". É uma interface de rede virtual utilizada por aplicações para se comunicarem entre si dentro do sistema. Em geral, todo tráfego na interface loopback deve ser aceito. No OpenBSD a interface de loopback é lo(4).

pass quick on lo0 all

Depois, os endereços RFC 1918 serão bloqueados, tanto para entrada quanto saída na interface externa. Estes endereços nunca devem aparecer na Internet, portanto, filtra-los nos certificará de que o roteador não deixará "escapar" estes endereços para fora da rede interna e também bloqueará qualquer pacote vindo da Internet com qualquer desses endereços de origem.

block drop in  quick on $ext_if from $priv_nets to any
block drop out quick on $ext_if from any to $priv_nets

Note que block drop é usado, dizendo ao PF para não responder com um pacote TCP RST ou ICMP Unreachable. Já que endereços da RFC 1918 não existem na Internet, quaisquer pacotes enviados para estes endereços nunca alcançarão seu destino. A opçao quick é utilizada, informando ao PF para não se preocupar em avaliar o restante das regras de filtragem caso uma das regras acima case com o pacote; pacotes de ou para as redes $priv_nets serão descartados imediatamente.

Agora abrimos as portas usadas pelos serviços que estarão disponíveis para a Internet:

pass in on $ext_if inet proto tcp from any to ($ext_if) \
   port $tcp_services flags S/SA keep state

Especificando as portas na macro $tcp_services torna-se simples abrir mais portas para a Internet caso necessário, editando simplesmente a macro e recarregando as regras. Serviços UDP também podem ser abertos criando-se uma macro $udp_services e adicionando uma regra de filtragem similar à regra acima, que especifique proto udp.

Além de ter uma regra rdr que redireciona o tráfego para COMP3, DEVEMOS também autorizar esse tráfego através do firewall:

pass in on $ext_if proto tcp from any to $comp3 port 80 \
    flags S/SA synproxy state

Para aumentar um pouco a segurança, faremos uso de TCP SYN Proxy para proteger ainda mais o servidor web.

Para que conexões FTP ativas funcionem fora da LAN, a seguinte regra deve existir, passando a conexão ftp-data iniciada pelo servidor FTP de volta para o cliente. Como as conexões FTP estão utilizando ftp-proxy, ele mesmo terá o trabalho de aceitar as conexões ftp-data e repassa-las para o cliente na LAN.

pass in on $ext_if inet proto tcp from port 20 to ($ext_if) \
    user proxy flags S/SA keep state

Agora tráfego ICMP deve ser permitido:

pass in inet proto icmp all icmp-type $icmp_types keep state

Similar à macro $tcp_services, a macro $icmp_types pode ser facilmente editada para alterar os tipos de pacotes ICMP que terão permissão de alcançar o firewall. Note que esta regra se aplica a todas interfaces de rede.

Tráfego de e para a rede interna deve ser permitido. Assumiremos que usuários da rede interna sabem o que estão fazendo e não nos causarão problemas. Esta não é necessariamente uma suposição válida; um conjunto de regras bem mais restritivas é apropriado para a maioria dos ambientes computacionais.

pass in on $int_if from $int_if:network to any keep state

As regras acima permitem a qualquer máquina interna enviar pacotes através do firewall, contudo, não permite que o próprio firewall inicie qualquer conexão com uma máquina da rede interna. Isso é uma boa idéia? Depende dos detalhes precisos de configuração da rede. Caso o firewall seja também um servidor DHCP, ele precisa "pingar" um endereço para verificar sua disponibilidade antes de atribuí-lo a uma máquina. Permitir ao firewall se conectar à rede interna também dá permissão a alguém com uma conexão ssh no firewall pela Internet para acessar máquinas da rede interna. Tenha em mente que não permitir ao firewall se comunicar com a rede interna não traz um grande benefício em segurança; de qualquer modo, caso alguém consiga acesso ao firewall, essa pessoa provavelmente pode alterar as regras de filtragem. Adicionando a regra a seguir, o firewall poderá iniciar conexões com a rede interna.

pass out on $int_if from any to $int_if:network keep state

Note que se ambas as linhas estiverem presentes, a opção keep state não se faz necessária; todos pacotes passarão pela interface interna, isso porquê existem regras para passar os pacotes em ambas as direções. Contudo caso a linha pass out não exista a linha pass in deve incluir keep state. Existe além disso um ganho de performance mantendo-se o estado da conexão: as tabelas de estado (State tables) são verificadas antes das regras serem avaliadas, e caso um pacote combine com alguma entrada na tabela, o mesmo passa pelo firewall sem ser avalidado pelas regras. Isso oferece ganho de performance num firewall muito carregado, mas num sistema simples como este não trará benefícios visíveis.

Finalmente, permitimos tráfego na interface externa:

pass out on $ext_if proto tcp all modulate state flags S/SA
pass out on $ext_if proto { udp, icmp } all keep state

Tráfego TCP, UDP e ICMP é permitido sair do firewall em direção à Internet. Informação de estado das conexões é mantido para que os pacotes de retorno passem direto pelo firewall.

O Conjunto Completo de Regras

# macros
int_if = "fxp0"
ext_if = "ep0"

tcp_services = "{ 22, 113 }"
icmp_types = "echoreq"

priv_nets = "{ 127.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8 }"
	  
comp3 = "192.168.0.3"

# opções
set block-policy return
set loginterface $ext_if

# scrub
scrub in all

# nat/rdr
nat on $ext_if from $int_if:network to any -> ($ext_if)
rdr on $int_if proto tcp from any to any port 21 -> 127.0.0.1 \
   port 8021
rdr on $ext_if proto tcp from any to any port 80 -> $comp3

# regras de filtragem
block all

pass quick on lo0 all

block drop in  quick on $ext_if from $priv_nets to any
block drop out quick on $ext_if from any to $priv_nets

pass in on $ext_if inet proto tcp from any to ($ext_if) \
   port $tcp_services flags S/SA keep state

pass in on $ext_if proto tcp from any to $comp3 port 80 \
   flags S/SA synproxy state

pass in on $ext_if inet proto tcp from port 20 to ($ext_if) \
   user proxy flags S/SA keep state

pass in inet proto icmp all icmp-type $icmp_types keep state

pass in  on $int_if from $int_if:network to any keep state
pass out on $int_if from any to $int_if:network keep state

pass out on $ext_if proto tcp all modulate state flags S/SA
pass out on $ext_if proto { udp, icmp } all keep state

[Anterior: Redundância de Firewall com CARP e pfsync] [Conteúdo]


[voltar] www@openbsd.org
$OpenBSD: example1.html,v 1.3 2005/11/18 20:48:47 jufi Exp $