jueves, 14 de noviembre de 2013

GeoIP para Iptables con Xtables_addons en GNU\Linux Ubuntu 13+

Después de un largo tiempo os traigo un nuevo articulo relacionado con la seguridad de vuestros sistemas para que podáis estar un poco más seguros evitando o permitiendo a países enteros de forma específica en vuestros firewalls o cortafuegos con iptables.

Xtables-addons

Xtables_addons es un software con licencia libre que sustituye la forma de parchear el kernel para agregar modificaciones a netfilter (iptables).

Antes se usaba patch-o-matic para agregar características pero se necesitaba recompilar el kernel y reiniciar el sistema para que funcionara. Además se debían repetir los pasos cada vez que se instalaba un nuevo kernel.

Con xtables-addons se consigue crear módulos dinámicos del kernel (dkms) que evita el reinicio del servidor ya que se cargan de forma dinámica. Podemos ver más información en

http://xtables-addons.sourceforge.net

En algunas distribuciones GNU\Linux como Ubuntu disponemos de los paquetes en los repositorios. En otras distribuciones como CentOS no. Nosotros vamos a instalarlo en GNU\Linux Ubuntu 13.10 64 bits pero he comprobado que también funciona en GNU\Linux CentOS 6.4 64 bits aunque hay que compilarlo a partir de los fuente e instalar la última versión 1.X. En Ubuntu instalaremos la versión más actual la 2.X (2.3).

Instalación

Instalamos los paquetes necesarios mediante apt-get
sudo apt-get install libtext-csv-xs-perl xtables-addons-common xtables-addons-dkms
Esto reconfigurará los módulos apropiados del kernel que tengamos instalado, entre ellos el módulo de GeoIP. Cuando se actualice el kernel se actualizaran los módulos gracias a dkms.

Una vez instalado, para usar las características de GeoIP deberemos de configurar las bases de datos de los países y los rangos de IPs para poder filtrar. Esto lo haremos usando los scripts que incluye xtables_addons al instalarse. Estos scripts se encuentran en /usr/lib/xtables_addons
cd /usr/lib/xtables-addons/
Actualizamos las bases de datos, para ello usamos el script de descarga
sudo ./xt_geoip_dl
--2013-11-14 18:50:19--  http://geolite.maxmind.com/download/geoip/database/GeoIPv6.csv.gz
Resolviendo geolite.maxmind.com (geolite.maxmind.com)... 108.168.255.243, 2607:f0d0:3:8::4
Conectando con geolite.maxmind.com (geolite.maxmind.com)[108.168.255.243]:80... conectado.
Petición HTTP enviada, esperando respuesta... 200 OK
Longitud: 729907 (713K) [application/octet-stream]
Grabando a: “GeoIPv6.csv.gz”

100%[======================================================>] 729.907      447KB/s   en 1,6s   

2013-11-14 18:50:21 (447 KB/s) - “GeoIPv6.csv.gz” guardado [729907/729907]

--2013-11-14 18:50:21--  http://geolite.maxmind.com/download/geoip/database/GeoIPCountryCSV.zip
Reutilizando la conexión con geolite.maxmind.com:80.
Petición HTTP enviada, esperando respuesta... 200 OK
Longitud: 1260849 (1,2M) [application/zip]
Grabando a: “GeoIPCountryCSV.zip”

100%[======================================================>] 1.260.849    917KB/s   en 1,3s   

2013-11-14 18:50:22 (917 KB/s) - “GeoIPCountryCSV.zip” guardado [1260849/1260849]

COMPLETADO --2013-11-14 18:50:22--
Tiempo total: 3,4s
Descargados: 2 files, 1,9M in 2,9s (662 KB/s)
Archive:  GeoIPCountryCSV.zip
  inflating: GeoIPCountryWhois.csv   
Esto nos habrá descargado y descomprimido la base de datos csv. Ahora hay que convertir los ficheros de países en ficheros apropiados para el firewall y xtables_addons. Por defecto se usa una ubicación determinada para almacenarlos, por tanto, antes de ejecutar el script de construcción tenemos que crear el directorio de almacén en dicha ubicación y después ejecutamos el script dándole dicha ruta como parámetro (sin el directorio LE). Si no se hace esto fallará.
sudo mkdir -p /usr/share/xt_geoip/LE
sudo /usr/lib/xtables-addons/xt_geoip_build -D /usr/share/xt_geoip/ GeoIPCountryWhois.csv
82078 entries total
    0 IPv6 ranges for A1 Anonymous Proxy
  102 IPv4 ranges for A1 Anonymous Proxy
    0 IPv6 ranges for A2 Satellite Provider
  372 IPv4 ranges for A2 Satellite Provider
    0 IPv6 ranges for AD Andorra
    9 IPv4 ranges for AD Andorra
    0 IPv6 ranges for AE United Arab Emirates
  104 IPv4 ranges for AE United Arab Emirates
    0 IPv6 ranges for AF Afghanistan
   65 IPv4 ranges for AF Afghanistan
    0 IPv6 ranges for AG Antigua and Barbuda
   39 IPv4 ranges for AG Antigua and Barbuda
...
    0 IPv6 ranges for WS Samoa
   13 IPv4 ranges for WS Samoa
    0 IPv6 ranges for YE Yemen
   12 IPv4 ranges for YE Yemen
    0 IPv6 ranges for YT Mayotte
   13 IPv4 ranges for YT Mayotte
    0 IPv6 ranges for ZA South Africa
  461 IPv4 ranges for ZA South Africa
    0 IPv6 ranges for ZM Zambia
   41 IPv4 ranges for ZM Zambia
    0 IPv6 ranges for ZW Zimbabwe
   45 IPv4 ranges for ZW Zimbabwe
He dejado solo un extracto de la salida para no alargar el documento, pero se han configurado todos los países. Además hay algunos rangos especiales como podemos ver en el inicio, por ejemplo, A1 que es el rango de proxies anónimos. Esto puede ser interesante para denegar ataques desde dichos proxies que suelen ser usados como inicios de ataques.

Para comprobar que está todo correcto podemos ejecutar la regla que deniega a China a través del sistema de GeoIP de xtables_addons e iptables. Además crearemos una regla que deniegue los proxies anónimos al puerto 80 y 443. Suponemos que las políticas por defecto de iptables en el INPUT es ACCEPT.
sudo iptables -A INPUT -m geoip --src-cc CN -j DROP
sudo iptables -A INPUT -p tcp -m tcp -m multiport --dports 80,443 -m geoip --src-cc A1 -j DROP
Como vemos se usa el modulo "geoip" y el source es CN. CN se corresponde con el código de China de la base de datos geoip que contendrá los rangos de IP que se denegarán (drop). En caso de la segunda regla, sería lo mismo pero añadiríamos el protocolo tcp, los puertos 80 (http) y 443 (https) y el rango A1 (proxies anónimos)

En caso de tener política por defecto de denegación (DROP) solo habría que ejecutar las reglas correspondientes a los países que quisiéramos permitir, por ejemplo, España. Para nuestro servidor web, denegamos por defecto y permitimos solo a usuarios de España el acceso a nuestra web.
sudo iptables -A INPUT -p tcp -m tcp -m multiport --dports 80,443 -m geoip --src-cc ES -j ACCEPT
Podemos ver que se han creado las reglas de forma correcta. Se deniega China y Proxies y se permite a España de forma explícita.
 sudo iptables -L -n --line-numbers
Chain INPUT (policy ACCEPT)
num  target     prot opt source               destination         
1    DROP       all  --  0.0.0.0/0            0.0.0.0/0            -m geoip --source-country CN 
2    DROP       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp multiport dports 80,443 -m geoip --source-country A1 
3    ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp multiport dports 80,443 -m geoip --source-country ES 

Chain FORWARD (policy ACCEPT)
num  target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
num  target     prot opt source               destination
Conclusión

Espero que estos pasos os ayuden a asegurar vuestros servidores y ordenadores de trabajo y a clarificar este tema que está un poco farragoso en internet.

Además con un poco de imaginación y un script bash sencillo podréis añadir conjuntos de reglas con el comando iptables para automatizar algo el proceso, pero eso ya os lo dejo a vosotros ;-).

Como añadido os dejo el link para consultar el cádigo de países en wikipedia.

http://es.wikipedia.org/wiki/ISO_3166-1

martes, 18 de diciembre de 2012

Instalar los comandos de Azure para trabaja con la shell en GNU\Linux Ubuntu 12/13

ACTUALIZACION 28-11-2013:Se han rectificado los métodos de instalación. No es necesario instalar npm ya que se incluye en el paquete node.js y no se debe instalar azure y azure-cli. Solo azure-cli ya que puede dar errores de dependencias. Sigue siendo válido para GNU\Linux Ubuntu 13.10 64 bits y versión 0.7.4 de azure, la más actual. Tened en cuenta que Azure va cambiando su infraestructura y que el cliente cambia con ella así que debemos tener actualizado el cliente siempre que podamos.
ACTUALIZACION 09-01-2013: Al contrario que azure 0.6.9 que no funcionaba, la version 0.6.10 funciona correctamente al instalarla. Podéis actualizar con el siguiente comando:
sudo npm install azure -g && sudo npm install azure-cli -g

Hola a todos de nuevo. Aquí os dejo un how-to de como instalar Azure y ejecutar comandos del Cloud de Microsoft desde un GNU\Linux.

Ya sabéis que desde hace poco Microsoft da la posibilidad de instalar máquinas virtuales de GNU\Linux en su Cloud. Creo que todavía le falta un poco de tiempo y no obstante está en Preview pero para ver como va es interesante. Yo lo uso para el trabajo pero puede que os sea útil esta información.

Previamente deberemos tener una cuenta de azure. https://www.windowsazure.com/es-es/pricing/free-trial/?WT.mc_id=AzureBG_Spain_SEM

Podéis usar el interfaz gráfico (tiene algunas limitaciones) o instalar la linea de comandos. Para ello, en nuestro GNU\Linux necesitamos tener instalado node.js.

En Ubuntu 12.04 ejecutamos lo siguiente
sudo apt-get install python-software-properties
sudo add-apt-repository ppa:chris-lea/node.js
sudo apt-get update
sudo apt-get install nodejs
En Ubuntu 12.10, además hay que tener instalado
sudo apt-get install software-properties-common
Comprobamos las versiones
$ node -v && npm -v
v0.8.16
1.1.69
Una vez hecho debemos instalar el cliente de azure con el sistema de paquetería de node.js. El propio cliente instalará la versión de azure requerida.
sudo npm install azure-cli -g
Esto nos instalará la última versión de azure. Si nos fallara, podemos instalar la versión que queramos anterior. Para instalar una versión específica
sudo npm install azure-cli@0.6.8 -g
Con estos comandos dispondremos de Azure 0.6.8 (en este caso. 0.6.9 tiene un bug y no funciona correctamente) Comprobamos
$ azure

info:             _    _____   _ ___ ___
info:            /_\  |_  / | | | _ \ __|
info:      _ ___/ _ \__/ /| |_| |   / _|___ _ _
info:    (___  /_/ \_\/___|\___/|_|_\___| _____)
info:       (_______ _ _)         _ ______ _)_ _ 
info:              (______________ _ )   (___ _ _)
info:    
info:    Windows Azure: Microsoft's Cloud Platform
info:    
info:    Tool version 0.6.8
help:    
help:    Display help for a given command
help:      help [options] [command]
help:    
help:    Commands:
help:      account                Manage your account information and publish settings
help:      account storage        Commands to manage your Azure storage account
help:      account storage keys   Commands to manage your Azure storage account keys
help:      account affinity-group Commands to manage your Azure affinity groups
help:      config                 Manage tool local settings
help:      vm                     Commands to manage your Azure virtual machines
help:      vm location            Commands to manage your Azure locations
help:      vm endpoint            Commands to manage your Azure virtual machine endpoints
help:      vm image               Commands to manage your Azure VM images
help:      vm disk                Commands to manage your Azure virtual machine data disks
help:      site                   Commands to manage your web sites
help:      site location          Commands to manage your Azure locations
help:      site deployment        Commands to manage your git deployments
help:      site log               Commands to download diagnostic log
help:      site repository        Commands to manage your git repository
help:      site config            Commands to manage your site configurations
help:      service                Commands to manage your Azure cloud services
help:      service cert           Commands to manage your Azure certificates
help:    
help:    Options:
help:      -h, --help     output usage information
help:      -v, --verbose  use verbose output
help:      --json         use json output
Para usar la linea de comandos debemos descargar el certificado de nuestra suscripción (cuenta de azure) La suscripción gratuita de 3 meses no descarga correctamente el fichero de credenciales. Hay que tener una versión de prueba especial de Microsoft (la mía lo es por el trabajo). Es posible que con la versión de pago funcione correctamente aunque no lo puedo asegurar.
azure account download

info:    Executing command account download
info:    Launching browser to http://go.microsoft.com/fwlink/?LinkId=254432
help:    Save the downloaded file, then execute the command
help:      account import 
info:    account download command OK
Vamos al link en un navegador http://go.microsoft.com/fwlink/?LinkId=254432 y nos descargará un archivo nombre.publishsettings que deberemos importar. En nuestro caso descarga un fichero del tipo (está cambiado) Nombre140C14790L-12-5-2012-credentials.publishsettings Para importarlo
azure account import Nombre140C14790L-12-5-2012-credentials.publishsettings

info:    Executing command account import
info:    Found subscription: Nombre140C14790L
info:    Setting service endpoint to: https://management.core.windows.net/
info:    Setting default subscription to: Nombre140C14790L
info:    Use "azure account set" to change to a different one.
warn:    The 'Nombre140C14790L-12-5-2012-credentials.publishsettings' file contains sensitive information.
warn:    Remember to delete it now that it has been imported.
info:    Account publish settings imported successfully
+ Enumerating locations                                                        
info:    account import command OK
Una vez importado podemos ver la lista de cuentas con
azure account list

info:    Executing command account list
data:    Name             Id                                  
data:    ----------------  ------------------------------------
data:    Nombre140C14790L  d4be462c-87c4-4dda-b612-76525fd2e05e
Por último seleccionamos la suscripción en la que queremos usar nuestros comandos
azure account set Nombre140C14790L
Con esto, los comandos que ejecutemos de azure se ejecutarán en la cuenta Nombre140C14790L. Podemos tener varias cuentas y ejecutar comandos para cada una siempre que seleccionemos con set la cuenta o suscripción correspondiente primero. Mediante estos comandos y desde GNU\Linux Ubuntu podremos crear maquinas virtuales, borrarlas, arrancarlas, crear sites, etc. Saludos y espero que os sea útil.

miércoles, 24 de agosto de 2011

Rsync y optimización del espacio con enlaces duros o hard links

ACTUALIZACION 24-Agosto-2011 16:41: He añadido una nota al final sobre los links duros.

Hola a todos. Hace bastante tiempo que no incluyo una entrada nueva en el blog y creo que esta le va a gustar a muchos administradores de sistemas que necesitan optimizar el espacio porque los datos que necesitan guardar son muy pesados.

Hace poco me encontré con un problema de espacio que tenia en un servidor web. El caso es que, por contrato, la empresa donde trabajo necesitaba guardar un cierto número de rotaciones que no podíamos mantener ni por asomo. Cada copia eran 154GB, para que os hagáis una idea. La única forma de mantener un sistema de copias de seguridad así es haciendo copias incrementales, por supuesto, pero ¿como podríamos hacer que gastando un mínimo espacio pudiésemos tener copias de seguridad completas en cada copia y tener rotaciones cada dos horas?

La respuesta la tenemos en el uso de los links duros o hard links y en rsync.

Cuando tenemos un fichero en el disco, sus datos ocupan un espacio de bits en el. A grandes rasgos, el nombre, inodo, comienzo del bloque de datos en el disco y final, etc. vamos los metadatos del fichero, apuntan a ese espacio de disco. Si los datos del disco del fichero no cambian, podríamos crear un link duro que apuntara a esos datos e incluirlo en la copia de seguridad en vez de copiar el fichero con la duplicidad de los mismos datos en disco que eso conlleva. Un link duro es, a todos los efectos, el mismo fichero que el fichero original y comparte el mismo inodo que el fichero original. Podemos ver el inodo de un fichero con el comando ls y la opción -i.

Imaginaros que, de los 154 GB de los que tengo que hacer la copia de seguridad, solo cambian, realmente, 2 o 3 MB cada 2 horas, o incluso menos (imágenes no cambian, vídeos no cambian,etc.)... ¿Os vais dando cuenta del espacio que podemos ahorrar creando links duros en vez de copias, no? :-D y, por tanto, también os dais cuenta de la frecuencia que podemos tener de copias de seguridad en comparación con otros sistemas de copia. Pues bien, para poder conseguir esto he creado un script que realiza una copia de seguridad usando rsync y links duros y generando un directorio nuevo "incremental" con la frecuencia que pongáis ejecutándolo con cron. ¿Por que pongo incremental con comillas? por que en realidad, cada directorio con la nueva copia donde solo se crearán copias reales de los ficheros que cambien o sean nuevos, serán copias de seguridad completas del directorio de origen. No hará falta copiar varias copias incrementales en orden para tener la copia completa que queremos recuperar, podemos copiar el contenido del directorio del día/hora que queramos directamente y listo (otra ventaja, sin duda)

#!/bin/bash

# Nombre: rsync_hard_link.sh
# Localización del script: HOST /root/bin 
# Versión: 1.0.0
# Permisos: 770 usuario: root grupo: root
# Autor: Francisco J. Bejarano
# Descripción:
# Script que genera copias de seguridad completas "incrementales"
# de un directorio.
#
# Log: DIR_LOG
#
# Comentarios: usar una version de rsync que permita la opcion
# --link-dest=DIR. En GNU\Linux CentOS 5.6 tenemos:
# rsync  version 2.6.8  protocol version 29
# Con la que funciona sin problemas. Si usáis Fedora, Ubuntu, etc. (más nuevos) no deberíais de
# preocuparos.
#
# Frecuencia: crontab -u root -l
# # Ejecución del script cada dos horas en punto.
# 00 */2 * * * /root/bin/rsync_hard_link.sh


################################ Parámetros de configuración

# Inicializamos las variables que vayamos a usar y los directorios.
FECHA=`date +%Y%m%d%-H%M%S`
DIR_BACKUP=/var/backup/
DIR_BASE_PREVIOUS=${DIR_BACKUP}web/
ORIGEN=${DIR_BACKUP}www/
DESTINO=${DIR_BASE_PREVIOUS}${FECHA}/
DIR_LOG=${DIR_BACKUP}web/log/
LOG_FILE=${DIR_LOG}incremental_www-${FECHA}.log

# Los directorios y logs de copias con más antigüedad que los días que pongamos aquí serán
# eliminados. Por defecto 180 días o 6 meses. Ajustar a lo deseado.
DIAS=180

################################ Aplicaciones

# Detectamos la ubicación de la aplicación rsync por si lo ejecutamos en diferentes sistemas.
APP_RSYNC=`whereis rsync | cut -d" " -f2`

################################ Funciones

# Crea el nuevo directorio con la copia de seguridad nueva usando los hard links y copias 
# de ficheros nuevos o modificados.

function rsync_incremental {
   
   # Los directorios que tenemos aquí son lo que más puede confundir. El directorio que ponemos
   # en --link-dest debe ser el directorio de la última copia que realizamos previamente.
   # Vamos la anterior a la que vamos a hacer ahora. En este caso, crearemos un link blando
   # al directorio anterior cada vez que ejecutemos el script llamado previous.
   # El directorio de origen (acabado en /, importante) es el directorio del que queremos hacer
   # la copia de seguridad.
   # El directorio destino es al que vamos a hacer la copia de seguridad nueva con los hard
   # links que sean necesarios.
   # La opcion delete elimina los ficheros/directorios en el destino que se hayan eliminado
   # en el origen.

   $APP_RSYNC -avh --stats --delete --link-dest=${DIR_BASE_PREVIOUS}previous $ORIGEN $DESTINO &> $LOG_FILE

   # Borramos el anterior link blando que apuntaba a la copia previa
   rm -f ${DIR_BASE_PREVIOUS}previous
   
   # Creamos el link blando nuevo que ahora apunta a la copia de seguridad que acabamos de hacer
   # y que será la previa para la siguiente.
   ln -s $DESTINO ${DIR_BASE_PREVIOUS}previous
   
   # Comprimimos el log con bzip2. Con bzcat podemos ver el contenido sin descomprimir.
   # Así optimizamos más a un el espacio.
   bzip2 $LOG_FILE
}

# Eliminamos los ficheros necesarios para controlar el crecimiento sin control.

function eliminar_ficheros {

   # Eliminamos los directorios con antigüedad mayor a los días que pongamos en los parámetros
   # Además solo borramos los directorios que empiecen por 2 (no creo que este script siga
   # funcionando en el año 3000 :D) y solo inspeccionamos el nivel 1 de directorios no queremos
   # que borre directorios dentro de los que hay en el 1 nivel que empiecen por 2 y que sean 
   # de una copia actual que debamos mantener, ¿no?

   find $DIR_BASE_PREVIOUS -maxdepth 1 -type d -iname "2*" -ctime +${DIAS} -exec rm -rf {} \; &> /dev/null

   # Eliminamos los ficheros de log comprimidos con antigüedad mayor a los días que pongamos.
   find $DIR_LOG -type f -iname "*.bz2" -ctime +${DIAS} -exec rm -rf {} \; &> /dev/null

}

################################ Programa Principal

# Si no existe una copia previa hacemos la primera copia completa
# Esto solo se hace la primera vez. Si existe hacemos la incremental.

if [ ! -h ${DIR_BASE_PREVIOUS}previous ] ; then
   $APP_RSYNC -azh --stats --delete $ORIGEN ${FECHA}_origen/ &> $LOG_FILE
   ln -s ${FECHA}_origen/ ${DIR_BASE_PREVIOUS}previous   
else
   rsync_incremental
   eliminar_ficheros
fi

################################ Fin de Script

Y listo. Cada vez que lo ejecutemos veremos como tenemos un nuevo directorio con una copia completa que solo ocupa el espacio de disco nuevo de los ficheros nuevos o modificados en el origen.

Podemos ejecutar el script, hacer un df, modificar el contenido de ORIGEN, ejecutar de nuevo el script y hacer otro df y veremos como el consumo es mínimo y tenemos copias completas en cada directorio. También usad ls -li para ver los inodos en diferentes directorios de destino y comprobar que son los mismos si el fichero no ha cambiado.

Imaginad un desastre, se ha ido al garete todo el directorio origen de la web. Tenemos copias cada 2 horas.

# rsync --azh --delete DIR_DESTINO_O_COPIA/ DIR_ORIGEN_O_DOCUMENTROOT/

Esperáis a que se sincronice y tendréis de nuevo la copia exacta realizada en el momento en que se creo DIR_DESTINO_O_COPIA.

Saludos y espero que os sea útil ;-) y recordad que las copias de seguridad de las bases de datos debéis realizarlas también a parte si las usáis en vuestra web jeje... eso os lo dejo a vosotros. Si solo son ficheros no hay problema.

NOTA: Los links duros solo se pueden usar en el mismo sistema de ficheros. Esta limitación debemos tenerla en cuenta. Primero deberíamos hacer una sincronización del servidor web al de backup con ssh (por ejemplo) y después realizar esta copia. Esta sincronización ssh habría que hacerla cada 2 horas si usáis un servidor remoto de producción antes de la copia para que refleje los cambios o cada frecuencia que queráis. Podéis añadirlo al script mediante otra función como ejercicio jeje. De hecho, asi funcionan mis servidores.
Related Posts with Thumbnails