Anotaciones sobre iptables
Cadenas de reglas personalizadas
El escenario consiste en una red con un sistema de copias de seguridad bacula funcionando sobre él y que necesita que máquinas situadas en el exterior accedan a su almacenamiento a través de Internet; la dificultad estriba en que esas máquinas remotas tienen en su mayor parte direcciones IP dinámicas.
Vamos pues a crear una cadena de reglas que nos permita abrir el cortafuegos para que servidores de archivos remotos accedan a nuestro servidor de almacenamiento. Este último servidor está en la misma máquina que encara el acceso exterior, aunque también tengo el caso de un servidor de almacenamiento en el interior de la red y lo comentaré más abajo.
Para crear la cadena de reglas se emplea:
# iptables -t filter -N bacula-storage
y para comprobar que ha funcionado se usa:
# iptables -t filter -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Chain bacula-storage (0 references)
target prot opt source destination
#
donde podemos comprobar que no está asignada a ninguna de las cadenas predefinidas de la tabla de filtrado, así que para asignarla a alguna usaremos:
# iptables -t filter -A INPUT -j bacula-storage
# iptables -t filter -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
bacula-storage all -- anywhere anywhere
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Chain bacula-storage (1 references)
target prot opt source destination
#
Ahora llega el momento de añadirle las reglas que necesitemos:
# iptables -t filter -A bacula-storage -s NN.NN.NN.NN/32 -p tcp -m tcp --dport 9103 -j ACCEPT
# iptables -t filter -A bacula-storage -s XX.XX.XX.XX/24 -p tcp -m tcp --dport 9103 -j ACCEPT
e inspeccionar los resultados
# iptables -t filter -L bacula-storage
Chain bacula-storage (1 references)
target prot opt source destination
ACCEPT tcp -- remote1.mynet.com anywhere tcp dpt:bacula-sd
ACCEPT tcp -- remote2.mynet.com anywhere tcp dpt:bacula-sd
#
Cadenas de quita y pon
Ahora bien, ¿ qué ocurre si las direcciones IP son dinámicas y pueden ser distintas de tiempo en tiempo ? Lo peligroso desde mi punto de vista es dejar el puerto de acceso al servidor de almacenamiento (ya sea el estándar ó uno en particular) abierto a todo el mundo contínuamente, y puesto que una manera de rebajar el riesgo es abrirlo sólo durante el tiempo que dura la copia, se puede construir un mecanismo de apertura y cierre definiendo la cadena de reglas si no lo está, y conectándola y desconectándola del cortafuegos según se emplee.
Un programa como el siguiente puede emplearse para controlar el acceso al servidor de almacenamiento; obviamente es mejorable y lo pongo aquí a modo de ejemplo.
1 #!/bin/bash 2 3 # comprobamos si ya existe la cadena 4 iptables -t filter -L bacula-storage 2>&1 >/dev/null 5 6 if [ $? -ne 0 ]; then 7 # No existe, pasamos a crearla 8 iptables -t filter -N bacula-storage 9 iptables -t filter -A bacula-storage -p tcp -m tcp --dport 9103 -j ACCEPT 10 fi 11 12 # según lo que se nos pida 13 case $1 in 14 start) 15 # añadimos nuestra cadena a la cadena de entrada de la tabla de filtrado 16 iptables -t filter -A INPUT -j bacula-storage 17 ;; 18 stop) 19 # retiramos nuestra cadena pero NO la borramos 20 iptables -t filter -D INPUT -j bacula-storage 21 ;; 22 *) 23 echo "uso: bacula-sd-iptables.sh {start|stop}" >&2 24 exit 1 25 ;; 26 esac 27 28 exit $?
Nota: el lugar adecuado para ejecutar el programa anterior sería justo antes de iniciar el trabajo de copia e inmediatamente tras finalizarlo. Para ello se emplean las claúsulas
Run before job
yRun after job
en la definición de la copia de seguridad.
Bien pensado esta solución es un tanto burda, dado que en el fondo no consiste en otra cosa más que en abrir un puerto a todo el mundo durante un tiempo, las más de las veces medido en horas (dado el atraso tecnológico que suponen las líneas ADSL que nos vemos obligados a emplear). Eso significa que sigue siendo posible a terceros intentar conexiones al servidor en momentos concretos del día.
Otra solución más acertada sería abrir el acceso únicamente a los servidores de archivos de las máquinas a respaldar. Si cualquiera de esas máquinas sólo dispone de direcciones IP dinámicas será necesario instalar en ellas algún servicio de DNS dinámico como no-ip ó dhis y esperar que no se presenten cambios durante la transferencia de archivos.
Podría quedar como el siguiente programa:
1 #!/bin/bash 2 3 function usage () { 4 echo "uso: bacula-sd-iptables.sh {start|stop} host" >&2 5 exit 1 6 } 7 8 # salvamos parámetros 9 operation=$1 10 target=$2 11 12 # y verificamos que existan 13 if [ -z $operation -a -z $target ]; then 14 usage 15 fi 16 17 # comprobamos si ya existe la cadena 18 iptables -t filter -L bacula-storage 2>&1 >/dev/null 19 20 # Si no existe ... 21 if [ $? -ne 0 ]; then 22 # Creamos la cadena 23 iptables -t filter -N bacula-storage 24 25 # le añadimos como regla inicial la denegación de acceso al puerto para 26 # todas las conexiones nuevas (quizás habría que definir también el 27 # interfaz de red o algo similar para no dispararnos en el pié). 28 iptables -t filter -A bacula-storage -p tcp --syn --dport 9103 -j REJECT 29 30 # y la añadimos al filtrado de paquetes entrantes 31 iptables -t filter -A INPUT -j bacula-storage 32 fi 33 34 # según lo que se nos pida 35 case $operation in 36 start) 37 # Insertamos la regla para que encaje antes de la denegación global que 38 # establecimos al principio 39 iptables -t filter -I bacula-storage 1 -s $target -p tcp -m tcp --dport 9103 -j ACCEPT 40 ;; 41 stop) 42 # Borramos la regla buscando por coincidencia en lugar de por número 43 iptables -t filter -D bacula-storage -s $target -p tcp -m tcp --dport 9103 -j ACCEPT 44 ;; 45 *) 46 usage 47 ;; 48 esac 49 50 exit $?
Cambiando reglas en la cadena
Las reglas están numeradas por orden de aparición, que también es el orden de proceso de paquetes, por lo que si necesitamos borrar una de ellas tenemos:
# iptables -t filter -D bacula-storage 2
# iptables -t filter -L bacula-storage
Chain bacula-storage (1 references)
target prot opt source destination
ACCEPT tcp -- remote1.mynet.com anywhere tcp dpt:bacula-sd
#
aunque también podemos reemplazarla de esta manera:
# iptables -t filter -R bacula-storage 2 -s XX.XX.XX.XX/32 -p tcp -m tcp --dport 9103 -j ACCEPT
#
Referencias y enlaces
- Linux server hacks.
- Páginas etiquetadas con iptables en Debian Administration.