UFW: Permitir tráfico solo desde un dominio con dirección IP dinámica

32

Ejecuto un VPS que me gustaría asegurar usando UFW, permitiendo conexiones solo al puerto 80. Sin embargo, para poder administrarlo de forma remota, necesito mantener el puerto 22 abierto y hacerlo accesible desde casa.

Sé que UFW se puede configurar para permitir conexiones a un puerto solo desde una dirección IP específica:

ufw allow proto tcp from 123.123.123.123 to any port 22

Pero mi dirección IP es dinámica, por lo que aún no es la solución.

La pregunta es: tengo una resolución DNS dinámica con DynDNS, entonces, ¿es posible crear una Regla usando el dominio en lugar de la IP?

Ya probé esto:

ufw allow proto tcp from mydomain.dyndns.org to any port 22

pero tengo ERROR: Bad source address

Carles Sala
fuente

Respuestas:

47

No creo que esto sea posible con ufw. ufwes solo una interfaz a la iptablesque también le falta esta característica, por lo que un enfoque sería crear una entrada crontab que se ejecute periódicamente y verifique si la dirección IP ha cambiado. Si es así, lo actualizará.

Puede sentirse tentado a hacer esto:

$ iptables -A INPUT -p tcp --src mydomain.dyndns.org --dport 22 -j ACCEPT

Pero esto resolverá el nombre de host en una IP y lo usará para la regla, por lo que si la IP cambia más adelante, esta regla dejará de ser válida.

Idea alternativa

Podrías crear un script así, llamado iptables_update.bash,.

#!/bin/bash
#allow a dyndns name

HOSTNAME=HOST_NAME_HERE
LOGFILE=LOGFILE_NAME_HERE

Current_IP=$(host $HOSTNAME | cut -f4 -d' ')

if [ $LOGFILE = "" ] ; then
  iptables -I INPUT -i eth1 -s $Current_IP -j ACCEPT
  echo $Current_IP > $LOGFILE
else

  Old_IP=$(cat $LOGFILE)

  if [ "$Current_IP" = "$Old_IP" ] ; then
    echo IP address has not changed
  else
    iptables -D INPUT -i eth1 -s $Old_IP -j ACCEPT
    iptables -I INPUT -i eth1 -s $Current_IP -j ACCEPT
    /etc/init.d/iptables save
    echo $Current_IP > $LOGFILE
    echo iptables have been updated
  fi
fi

fuente: Uso de IPTables con nombres de host de IP dinámica como dyndns.org

Con este script guardado, podría crear una entrada crontab como esta en el archivo /etc/crontab:

*/5 * * * * root /etc/iptables_update.bash > /dev/null 2>&1

Esta entrada ejecutaría el script cada 5 minutos, verificando si la dirección IP asignada al nombre de host ha cambiado. Si es así, creará una nueva regla que lo permita, mientras elimina la regla anterior para la antigua dirección IP.

slm
fuente
2
Qué tonto que no pensara en resolver el nombre de host periódicamente. Modifiqué tu script (agregué registros, etc.) y funciona de maravilla. ¡Gracias!
Carles Sala
@CarlesSala: me alegra que haya resuelto tu problema. Además de aceptar, también puedes votar 8-).
slm
1
nota: en Debian 7 tuve que cambiar la línea Current_IP=$(host $HOSTNAME | cut -f4 -d' ')aCurrent_IP=$(host $HOSTNAME | head -n1 | cut -f4 -d ' ')
Krystian
¿Podré ver esto cuando use ufw status verbose? Quiero decir, las reglas?
Freedo
@Freedo no estoy seguro, pruébalo y mira qué sucede.
slm
8

Sé que esto es antiguo, pero lo encontré y terminé con esta solución al final, lo que parece aún mejor porque no se necesita ningún archivo de registro y es muy fácil agregar hosts adicionales según sea necesario. ¡Funciona de maravilla!

Fuente: http://rdstash.blogspot.ch/2013/09/allow-host-with-dynamic-ip-through.html

#!/bin/bash

DYNHOST=$1
DYNHOST=${DYNHOST:0:28}
DYNIP=$(host $DYNHOST | grep -iE "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" |cut -f4 -d' '|head -n 1)

# Exit if invalid IP address is returned
case $DYNIP in
0.0.0.0 )
exit 1 ;;
255.255.255.255 )
exit 1 ;;
esac

# Exit if IP address not in proper format
if ! [[ $DYNIP =~ (([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]) ]]; then
exit 1
fi

# If chain for remote doesn't exist, create it
if ! /sbin/iptables -L $DYNHOST -n >/dev/null 2>&1 ; then
/sbin/iptables -N $DYNHOST >/dev/null 2>&1
fi

# Check IP address to see if the chain matches first; skip rest of script if update is not needed
if ! /sbin/iptables -n -L $DYNHOST | grep -iE " $DYNIP " >/dev/null 2>&1 ; then


# Flush old rules, and add new
/sbin/iptables -F $DYNHOST >/dev/null 2>&1
/sbin/iptables -I $DYNHOST -s $DYNIP -j ACCEPT

# Add chain to INPUT filter if it doesn't exist
if ! /sbin/iptables -C INPUT -t filter -j $DYNHOST >/dev/null 2>&1 ; then
/sbin/iptables -t filter -I INPUT -j $DYNHOST
fi

fi
Dom
fuente
lo siento, soy un poco novato. ¿Dónde necesito almacenar este script y dónde cambio las cosas para reflejar mi caso específico?
Freedo
5

Basado en respuestas anteriores, actualicé lo siguiente como script bash que funciona en Debian Jessie

#!/bin/bash
HOSTNAME=dynamichost.domain.com
LOGFILE=$HOME/ufw.log
Current_IP=$(host $HOSTNAME | head -n1 | cut -f4 -d ' ')

if [ ! -f $LOGFILE ]; then
    /usr/sbin/ufw allow from $Current_IP to any port 22 proto tcp
    echo $Current_IP > $LOGFILE
else

    Old_IP=$(cat $LOGFILE)
    if [ "$Current_IP" = "$Old_IP" ] ; then
        echo IP address has not changed
    else
        /usr/sbin/ufw delete allow from $Old_IP to any port 22 proto tcp
        /usr/sbin/ufw allow from $Current_IP to any port 22 proto tcp
        echo $Current_IP > $LOGFILE
        echo iptables have been updated
    fi
fi
Mattias Pettersson
fuente
Incluso podría agregarse para cronque se ejecute periódicamente solo.
Tim Kennedy
Eso es lo que hice;)
Mattias Pettersson
Este script tiene un pequeño problema: en el primer uso, si olvidó ejecutarlo como root, creará el archivo de registro pero no agregará las reglas. Luego, si ejecuta nuevamente como root, solo dirá 'la dirección IP no cambió'. ¡Tiene que ejecutarse como root la primera vez! Además, sería bueno cambiar LOGFILE=$HOME/ufw.logpara LOGFILE=$HOME/ufw.$HOSTNAME.logpermitir que se ejecute más de un script al mismo tiempo
Guerlando OCs
@GuerlandoOCs, ¿cómo se restablece si se encuentra con este problema?
Mateo
0

Basado en todas las respuestas antes de combinarlas. No se necesita un archivo de registro. Probado en Ubuntu 18.04

#!/bin/bash
HOSTNAME=YOUR.DNS.NAME.HERE

if [[ $EUID -ne 0 ]]; then
   echo "This script must be run as root"
   exit 1
fi

new_ip=$(host $HOSTNAME | head -n1 | cut -f4 -d ' ')
old_ip=$(/usr/sbin/ufw status | grep $HOSTNAME | head -n1 | tr -s ' ' | cut -f3 -d ' ')

if [ "$new_ip" = "$old_ip" ] ; then
    echo IP address has not changed
else
    if [ -n "$old_ip" ] ; then
        /usr/sbin/ufw delete allow from $old_ip to any
    fi
    /usr/sbin/ufw allow from $new_ip to any comment $HOSTNAME
    echo iptables have been updated
fi

Puede agregar un puerto a las reglas con el parámetro "puerto". p.ej:

if [ -n "$old_ip" ] ; then
    /usr/sbin/ufw delete allow from $old_ip to any port 22
fi
/usr/sbin/ufw allow from $new_ip to any port 22 comment $HOSTNAME
Sebastian
fuente