[OpenBSD]

[Anterior: Redundancia de cortafuegos con CARP y pfsync] [Contenido]

PF: Ejemplo: Cortafuegos para una red doméstica o una oficina


Índice de contenidos


El escenario

En este ejemplo, PF funciona en una máquina OpenBSD que actúa como cortafuegos y pasarela de NAT para una pequeña red en casa o en la oficina. El objetivo final es el de dar acceso a Internet desde la red, permitir un acceso limitado a la máquina cortafuegos desde Internet y exponer un servidor web interno a Internet. En este documento se repasa un grupo de reglas completo con este fin.

La red

La configuración de la red es como sigue:

    
  [ COMP1 ]    [ COMP3 ]
      |            |                               
   ---+------+-----+------- xl0 [ OpenBSD ] fxp0 -------- ( Internet )
             |
         [ COMP2 ]

En la red interna hay varios ordenadores; el diagrama muestra sólo tres, aunque el número real es irrelevante. Estos ordenadores son estaciones de trabajo normales que se usan para navegar por la web, correo electrónico, charlas en línea (chats), etc., excepto COMP3 que además corre un pequeño servidor web. La red interna usa el bloque de red 192.168.0.0 / 255.255.255.0.

El cortafuegos OpenBSD es un Celeron 300 con dos tarjetas de red: una 3Com 3c905B (xl0) y una Intel EtherExpress Pro/100 (fxp0). El cortafuegos tiene una conexión de cable a Internet y está usando NAT para compartir esta conexión con la red interna. La dirección IP en la interfaz externa la asigna de forma dinámica el proveedor de Internet (ISP).

El objetivo

Los objetivos son:

Preparación

En este documento se asume que se ha configurado correctamente el anfitrión con OpenBSD para que funcione como un enrutador, incluida la verificación de la configuración de redes IP, la conexión a Internet y haber configurado las variables sysctl(3) net.inet.ip.forwarding y/o net.inet6.ip6.forwarding con el valor "1".

El grupo de reglas

A continuación construiremos un grupo de reglas que lograrán los objetivos anteriores.

Macros

Las siguientes macros se han definido para facilitar el mantenimiento y la lectura del grupo de reglas:

int_if="xl0"

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

comp3="192.168.0.3"

La primera línea define la interfaz de red interna en la que tendrá lugar el filtrado. Al definirlas aquí, si tenemos que mover este sistema a otra máquina con diferente hardware, podemos cambiar solo estas dos líneas, y el resto de reglas seguirán siendo válidas. (Para este ejemplo, la interfaz externa será manejada usando la interfaz de grupo egress. Esto es automáticamente configurado en cualquier interfaz que contenga una ruta por defecto, en este caso fxp0). La segunda y tercera líneas son una lista de los números de puertos TCP de los servicios que se abrirán a Internet (SSH e ident/auth) y de los tipos de paquetes ICMP a los se que les permitirá llegar a la máquina cortafuegos. Finalmente, la última línea define la dirección IP de COMP3.

Nota: Si la conexión de Internet requiere PPPoE, entonces el filtrado y el NAT tendrían que realizarse en la interfaz pppoe0y no en fxp0.

Opciones

Con las siguientes dos opciones se configura la respuesta predeterminada para las reglas de filtrado block, y se activa el registro de estadísticas para la interfaz externa:

set block-policy return
set loginterface fxp0

Todo sistema Unix tiene una interfaz de retrobucle (loopback). Se trata de una interfaz virtual de red que usan las aplicaciones para comunicarse entre sí mismas dentro del sistema. En OpenBSD, la interfaz de loopback es lo(4). Se considera una buena práctica desactivar todo filtrado en las interfaces loopback. Por medio de set skip lograremos esto:

set skip on lo
Tenga en cuenta que nos estamos saltando el filtrado para todos los interfaces lo. De esta manera, si más tarde debemos añadir interfaces loopback suplementarios, no tendríamos que preocuparnos por la modificación de esta parte de nuestro actual fichero de reglas.

Reglas del cortafuegos

Comenzaremos con las reglas para soportar el uso de ftp-proxy(8), de modo que los clientes FTP en la red local puede conectarse a servidores FTP en Internet. Esto funciona mediante la inserción dinámica de las reglas cuando se realiza una conexión ftp. Se hace por medio de un anclaje:
anchor "ftp-proxy/*"

Ahora añadiremos la regla que permita la redirección de las conexiones FTP para que puedan ser vistas por ftp-proxy(8):

pass in quick on $int_if inet proto tcp to any port ftp \
    rdr-to 127.0.0.1 port 8021

Esta regla interceptará las conexiones FTP en el puerto 21 y las redirigirá a una instancia ftp-proxy(8) que se ejecuta en el puerto 8021 y, a través del uso de la palabra clave quick, los paquetes válidos no serán verificados por el resto del conjunto de reglas. Si los usuarios se conectan regularmente a los servidores FTP en otros puertos, entonces se debe utilizar una lista para especificar el puerto de destino, por ejemplo: to any port { 21, 2121 }.

Hay que subrayar que tanto el anclaje como la regla de redirección ftp-proxy(8) necesitan ser situados antes de cualquier regla match para el NAT o el ftp-proxy(8) no funcionará como se espera.

Ahora vamos a ver las reglas match. Por sí misma, una regla match no determina si a un paquete se le permite o no pasar. En cambio, se almacenarán los parámetros de los paquetes que coincidan con esta regla y se utilizarán en cualquier regla pass que luego valide estos paquetes.

Esto es potente: parámetros tales como NAT o formación de colas (queueing) pueden aplicarse a ciertas clases de paquetes y los permisos de acceso definirse después por separado.

Para disponer de NAT en toda la red interna se utiliza la siguiente regla match:

match out on egress inet from !(egress:network) to any nat-to (egress:0)

En este caso, el "!(egress:network)" podría ser fácilmente reemplazado por un "$int_if:network", pero si usted ha agregado múltiples interfaces internas, habría que añadir reglas NAT adicionales, mientras que con esta estructura NAT será manejado en todas las interfaces protegidas.

Dado que la dirección IP de la interfaz externa se asigna dinámicamente, los paréntesis se colocan en torno a la interfaz de traducción para que PF sea avisado cuando la dirección cambia. El sufijo :0 se utiliza para que si la interfaz externa tiene múltiples direcciones, sólo la primera dirección se utilice para la traducción.

Para acabar, se especifica la familia de protocolos inet (IPv4) Esto suprime la traducción de todos los paquetes inet6 (IPv6) que puedan ser recibidos.

Ahora las reglas para controlar los permisos de acceso. Se empieza con una denegación de forma predeterminada:

block in log

En este punto todo el tráfico que intenta entrar en la interfaz será bloqueado, incluso el que proviene de la red interna. Estos paquetes también son logueados. Las reglas siguientes abrirán el cortafuegos de acuerdo con los objetivos descritos anteriormente, y abrirán también todos los interfaces virtuales necesarios.

Tenga en cuenta que pf puede bloquear el tráfico entrante o saliente de un interfaz. Puede simplificar su vida si usted elige filtrar el tráfico en una dirección, en lugar de tratar de bloquear entrada y salida. En nuestro caso, optaremos por filtrar únicamente el tráfico de entrada, pero una vez permitida la entrada en una interfaz, no vamos a tratar de obstruir la salida, por lo que haremos lo siguiente:

pass out quick
Utilizando quick puede evitarse que los paquetes salientes sean verificados contra las reglas siguientes, mejorando así el rendimiento.

Es útil usar también la protección contra la falsificación de direcciones (antispoofing):

antispoof quick for { lo $int_if }

Ahora abrimos los puertos usados por los servicios de red que estarán disponibles desde Internet. Primero, el tráfico que se destina al cortafuegos mismo:

pass in on egress inet proto tcp from any to (egress) \
    port $tcp_services

Especificar los puertos de red en la macro $tcp_services simplifica la apertura de servicios adicionales a Internet, simplemente mediante la edición de la macro y la recarga del conjunto de reglas. Los servicios UDP también pueden abrirse mediante la creación de una macro $udp_services y la adición de una regla de filtrado, similar a la indicada anteriormente, que especifique proto udp.

La siguiente regla captura cualquier intento de conexión desde Internet por medio del puerto TCP 80 del cortafuegos. Los intentos legítimos para acceder a este puerto procederán de usuarios que tratan de acceder al servidor web de la red. Estos intentos de conexión deben ser redirigidos a COMP3:

pass in on egress inet proto tcp to (egress) port 80 \
    rdr-to $comp3 synproxy state

Para incrementar un poco la seguridad, usaremos el proxy de paquetes TCP SYN con el fin de proteger el servidor web.

Debe permitirse el tráfico ICMP:

pass in inet proto icmp all icmp-type $icmp_types

Similar a la macro $tcp_services, la macro $icmp_types puede fácilmente ser modificada para alterar los tipos de paquetes ICMP que serán autorizados a alcanzar el cortafuegos. Téngase en cuenta que esta regla se aplica a todas las interfaces de red.

Ahora el tráfico de la red interna debe ser permitido. Asumimos que los usuarios de la red interna saben lo que hacen y no causarán problemas. Esto no es necesariamente una asunción válida para muchos entornos; para muchos otros contextos pueden ser más apropiado un conjunto de reglas más restrictivo.

pass in on $int_if

Se permite que el tráfico TCP, UDP y ICMP salga del cortafuegos hacia Internet gracias a la regla precedente "pass out". La información sobre el estado se guarda para que los paquetes de vuelta pasen a través del cortafuegos.

El grupo de reglas completo

# macros

int_if="xl0"

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

comp3="192.168.0.3"

# opciones

set block-policy return
set loginterface fxp0
set skip on lo

# reglas proxy FTP

anchor "ftp-proxy/*"

pass in quick on $int_if inet proto tcp to any port ftp \
    rdr-to 127.0.0.1 port 8021

# reglas match

match out on egress inet from !(egress) to any nat-to (egress:0)

# reglas de filtrado

block in log
pass out quick

antispoof quick for { lo $int_if }

pass in on egress inet proto tcp from any to (egress) \
    port $tcp_services

pass in on egress inet proto tcp to (egress) port 80 \
    rdr-to $comp3 synproxy state

pass in inet proto icmp all icmp-type $icmp_types

pass in on $int_if

[Anterior: Redundancia de cortafuegos con CARP y pfsync] [Contenido]


[back] www@openbsd.org
$OpenBSD: example1.html,v 1.10 2011/02/20 10:08:24 ajacoutot Exp $