Mejorando la seguridad de nuestro servidor con iptables

  • #linux
  • #seguridad

Iptables puede parecer difícil o tedioso de configurar, pero si usamos unas reglas básicas y comunes, todo será mucho más fácil.

Iptables es una potente herramienta que todo administrador de sistemas debería conocer y utilizar. Pero como desarrollador web, a veces es difícil mantenerse al día con todas las funcionalidades que este enorme cortafuegos ofrece.

Iptables aporta seguridad a nuestras conexiones

A continuación veremos un ejemplo de configuración de iptables restrictivo y útil, en el que cerraremos todos los puertos e iremos abriendo los necesarios según las necesidades personales de cada uno.

Lo primero es especificar qué tipo de reglas vamos a añadir. Esto se hace marcando el inicio y el fin:

*filter
# Aquí nuestras reglas
COMMIT

Reglas básicas

Utilizaremos una política restrictiva donde cerraremos todos los puertos por defecto:

-P INPUT DROP
-P OUTPUT DROP
-P FORWARD DROP

Si una conexión ya obtuvo permiso para interactuar con nuestra máquina, dejamos que los siga teniendo:

-A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
-A OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

Permitimos las conexiones loopback de nuestra máquina:

-A INPUT -i lo -j ACCEPT
-A OUTPUT -o lo -j ACCEPT

Y por último configuramos el sistema de registro:

-A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7
-A OUTPUT -j LOG --log-prefix "[Output Log] "

Reglas comunes

Las reglas vienen a ser bastante sencillas: especificamos el protocolo, el puerto e incluímos INPUT si queremos conexiones entrantes y/o OUTPUT si queremos conexiones salientes.

Por ejemplo, si nuestro servidor corre un servicio HTTP (Apache, Nginx, etc), generalmente nos interesa que se pueda acceder desde el exterior a los puertos 80 (HTTP) y 443 (HTTPS):

-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 443 -j ACCEPT

Y a su vez, si queremos navegar desde nuestro servidor (p. ej. con lynx u otro navegador), necesitaremos crear la misma regla, pero esta vez cambiando INPUT por OUTPUT:

-A OUTPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A OUTPUT -p tcp -m tcp --dport 443 -j ACCEPT

Sencillo, ¿verdad? A continuación una lista de reglas comunes que nos podría interesar añadir.

SSH

Para poder conectar por SSH y a su vez que nuestro servidor pueda conectar por SSH a otros servidores, necesitaremos crear las reglas INPUT y OUTPUT para el puerto 22:

-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A OUTPUT -p tcp -m tcp --dport 22 -j ACCEPT

DNS

Si queremos que nuestro servidor pueda consultar nombres de dominio a otros servidores DNS, necesitaremos abrir el puerto 53:

-A OUTPUT -p udp -m udp --dport 53 -j ACCEPT

Y si nuestro servidor corre un servicio DNS (p. ej. BIND), utilizaremos INPUT:

-A INPUT -p udp -m udp --dport 53 -j ACCEPT

FTP

En el caso del protocolo FTP, normalmente nuestro servidor correrá el servicio FTP en el puerto 21. Pocas veces necesitaremos conectar desde nuestro servidor al exterior por FTP, así que solo INPUT:

-A INPUT -p tcp -m tcp --dport 21 -j ACCEPT

Rsync

Rsync se utiliza por defecto en emerge, el gestor de paquetes de Gentoo. También es muy común utilizar rsync para realizar backups, en nuestro caso nos sirve la regla OUTPUT para el puerto 873:

-A OUTPUT -p tcp -m tcp --dport 873 -j ACCEPT

Git

El puerto por defecto para Git es 9418. Como no corremos un servidor Git en nuestra máquina y solo necesitamos descargar software (GitHub), utilizaremos lo siguiente:

-A OUTPUT -p tcp -m tcp --dport 9418 -j ACCEPT

Ping

Si queremos que nuestro servidor pueda enviar y recibir pings, estas son las reglas:

-A INPUT -p icmp -j ACCEPT
-A OUTPUT -p icmp -j ACCEPT

Resumen

El resultado final sería el siguiente:

*filter

-P INPUT DROP
-P OUTPUT DROP
-P FORWARD DROP

-A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
-A OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

-A INPUT -i lo -j ACCEPT
-A OUTPUT -o lo -j ACCEPT

-A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7
-A OUTPUT -j LOG --log-prefix "[Output Log] "

# HTTP & HTTPS
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 443 -j ACCEPT
-A OUTPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A OUTPUT -p tcp -m tcp --dport 443 -j ACCEPT

# SSH
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A OUTPUT -p tcp -m tcp --dport 22 -j ACCEPT

# DNS
-A OUTPUT -p udp -m udp --dport 53 -j ACCEPT
-A INPUT -p udp -m udp --dport 53 -j ACCEPT # Sólo si utilizamos un servidor DNS

# FTP
-A INPUT -p tcp -m tcp --dport 21 -j ACCEPT

# RSYNC
-A OUTPUT -p tcp -m tcp --dport 873 -j ACCEPT

# GIT
-A OUTPUT -p tcp -m tcp --dport 9418 -j ACCEPT

# Ping
-A INPUT -p icmp -j ACCEPT
-A OUTPUT -p icmp -j ACCEPT

COMMIT

Si queréis abrir el puerto solamente para acceder desde una IP específica (por ejemplo, para conectar únicamente desde casa), solo hay que añadir: -s 12.34.56.78 a la regla en cuestión.

Para cargar las reglas en iptables basta con guardar estas reglas en un fichero y después ejecutar iptables-restore < fichero.

Una vez hayamos cargado las reglas en iptables, si queremos reemplazar las reglas por otras nuevas o si queremos eliminar las actuales, debemos ejecutar una serie de comandos:

iptables -F
iptables -X
iptables -P INPUT ACCEPT
iptables -P OUTPUT ACCEPT

Esto eliminará las reglas existentes y permitirá acceso de nuevo a todo. Si solo hacemos flush (iptables -F), eliminaremos las reglas pero nos quedaremos sin conexión, por lo que no es buena idea.

Esperamos que os haya sido de utilidad y no dudéis en dejar vuestros comentarios.

Compartir en