Rsync, ssh como transporte y autenticación mediante claves sin frase

Contenido

1. Introducción
2. Instalación
3. Utilización
4. Sincronización de directorios
5. Incluyendo y excluyendo archivos y/o directorios
6. Sincronización remota
7. Autenticación mediante certificado sin frase
8. Referencias

1. Introducción

Rsync es una aplicación para sistemas de tipo Unix que ofrece transmisión eficiente de datos incrementales comprimidos y cifrados. Mediante una técnica de delta encoding, permite sincronizar archivos y directorios entre dos máquinas de una red o entre dos ubicaciones en una misma máquina, minimizando el volumen de datos transferidos.

Rsync es tanto un protocolo como un algoritmo, para la comunicación entre hosts remotos pueden utilizarse tanto el protocolo de comunicación rsync, en su puerto estándar 873, o bien utilizando otro transporte como por ejemplo ssh, uno de los mas utilizados.

2. Instalación

Como todo en debian se reduce a ejecutar


# apt-get install rsync

Cabe aclarar que si se realizaran copias remotas rsync debe estar instalado en ambos hosts.

3. Utilización

En su forma básica rsync es muy similar a cp, su sintaxis básica es:


$ rsync [opciones] origen [| origen...] [destino]

Donde origen o destino pueden ser ubicaciones remotas pero al menos una de ellas debe ser local.
Esto implica que, si tenemos tres hosts, A, B y C, puede hacerse copias remotas desde el hosta A hacia el host B ejecutando rsync tanto en A como en B pero no puede hacerse desde A hacia B ejecutándose en C, al menos no directamente sino que debe hacerse el paso intermedio A --> C y C --> B.

Si queremos copiar en local el archivo archivo_1 a archivo_2, dentro del mismo directorio:

$ rsync -v archivo_1 archivo_2
archivo_1

sent 7626448 bytes  received 42 bytes  15252980.00 bytes/sec
total size is 7625431  speedup is 1.00

La opcion -v la he incluido para obtener mayor información en pantalla.
El comportamiento es el mismo que cp, no se conserva el usuario dueño del archivo, si los permisos.

Y al igual que cp no es capaz de copiar directorios sin agregar un modificador:

$ rsync dir1 dir2
skipping directory dir1

4. Sincronización de directorios

Para copiar directorios se utiliza la opción -a o su equivalente en formato largo --archive, esta es una combinación de las siguientes opciones:

  • -r : Recorrer la estructura de directorios recursivamente
  • -l : Copiar enlaces simbólicos
  • -p : Conservar los permisos
  • -t : Conservar la hora
  • -g : Conservar el grupo
  • -o : Conservar el propietario
  • -D : Mantener archivos de dispositivo (solo para root)

En definitiva, con la opción -a obtenemos una copia exacta de una jerarquía de archivos y directorios.

Para copiar un directorio Dir1 en otro Dir2 que contiene varios archivos y directorios

$ rsync -av dir1/ dir2/
building file list ... done
created directory dir2
dir1/
dir1/archivo_1
dir1/archivo_2
dir1/dir11/
dir1/dir11/archivo_3
dir1/dir12/
dir1/dir12/archivo_4

sent 6540542 bytes  received 126 bytes  13081336.00 bytes/sec
total size is 6539349  speedup is 1.00

En este punto debe hacerse algunas aclaraciones, si se modificara algún archivo, por ejemplo a archivo_3 se le agregara un carácter al final, al volver a ejecutar el comando anterior solo se copiará el archivo modificado, como es de esperarse, pero se copiara todo el archivo y no solo la parte modificada, esto es debido a que se está ejecutando en local y por tanto se utiliza por defecto la opción -W ya que se considera que es mas trabajoso calcular que parte se ha modificado que copiar el archivo completamente, si la ejecución fuera a remoto solo se transfieren los datos necesarios.

También debe saberse que, por defecto, rsync determina si un archivo ha sido modificado basándose en la fecha de última modificación y el tamaño del mismo. Se puede forzar que la modificación se determine mediante el calculo de un hash, md4 en este caso, con la opción -c pero debe tenerse en cuenta la carga de trabajo extra que esto significa.

Para el caso de sincronización de directorios cabe destacar la diferencia entre ejecutar


$ rsync -av dir1/ dir2/

y ejecutar


$ rsync -av dir1 dir2/

En el primer caso los directorios dir1 y dir2 quedaran exactamente iguales, en el segundo el directorio dir1 será copiado dentro del directorio dir2, la barra al final del directorio destino puede omitirse, no hay diferencia.

Otro aspecto a tener en cuenta es que por defecto se conservan en el destino los archivos borrados en el origen, si queremos que esto último no ocurra debemos agregar la opción --delete, también podemos querer agregar la opción --prune-empty-dirs para no copiar directorios vacíos

5. Incluyendo y excluyendo archivos y/o directorios

Una forma de sincronizar mas de un archivo y/o directorios es simplemente mencionarlos en el comando, recordar que la sintaxis básica es rsync [opciones] origen [| origen...] [destino] por lo que siempre que se mencione mas de una ubicación se supondrá que lo que se quiere hacer es sincronizar las primeras ubicaciones dentro de la última. Si se menciona solo una se operara con el directorio actual como directorio destino.

Si se quieren copiar muchos archivos y/o excluir algunos se pueden utilizar las siguientes opciones:

  • --exclude=PATTERN Excluir archivos que coinciden con la expresión PATTERN
  • --exclude-from=FILE Obtener el conjunto de expresiones del archivo especificado por FILE
  • --include=PATTERN No excluir los archivos que coinciden con la expresión PATTERN
  • --include-from=FILE Obtener el conjunto de expresiones del archivo especificado por FILE
  • --files-from=FILE Incluir los archivos especificados en el archivo FILE

En todos los casos debe indicarse un directorio origen el cual se tomará como base, esto es, la busqueda se inicia a partir de esa ubicación y las rutas especificadas se consideran relativas al origen indicado, por ejemplo


rsync -av --files-from=foo /usr /media/back

con la opción --files-from=foo se indica que el archivo foo contiene la lista de archivos a incluir, si se indicó como origen /usr y en foo existe la linea /sbin lo que se sincronizará es /usr/sbin y no /sbin.

Las opciones --include y --exclude son simple, algo como:


rsync -av --include=* --exclude=*.so /lib /media/back

Sincronizaría todos los archivos bajo /lib que no terminen en .so

Para las otras opciones se deben especificar expresiones regulares en las que se buscará coincidencias, la forma de operar puede ser un tanto compleja para las opciones --exclude-from=FILE y --include-from=FILE ya que rsync cuenta con su propia forma de expresiones regulares, léase la sección FILTER RULES del man page de rsync para mas detalles, igualmente se dará una breve introducción mediante un ejemplo:

Supongasé que se desea sincronizar los archivos en /etc/ssh y /var/log en /media/back y hace con lo siguiente:


rsync -av --include-from=foo / /media/back

y sabiendo que:

  • el caracter + indica incluir
  • el caracter - indica excluir
  • / matchea con el directorio /
  • /* matchea con todos los archivos en /
  • /** matchea con todos los archivos y directorios en /
  • /*** matchea con todos los archivos y directorios en / e incluso también con /
  • el - * al final indica que lo que no ha sido aceptado hasta entonces se excluya

podría pensarse lógico que el contenido de foo sea el siguiente:


+ /etc/ssh/*
+ /var/log/*
- *

Pero esto no obtendrá los resultados esperados, observe lo siguiente, el directorio base de origen es /, si estamos buscando coincidencias note que cuando comience a buscar a partir de / y se encuentre con /etc éste no coincide con ninguna de las expresiones indicadas en foo, la expresión /etc no coincide con la expresion regular /etc/ssh/*, y por o tanto no ingresará al directorio para continuar la busqueda. Por lo tanto la forma correcta es:

+ /etc/
+ /etc/ssh/
+ /etc/ssh/*
+ /var/
+ /var/log/
+ /var/log/*
- *


Esto es evidentemente engorroso pero es el método mas eficiente, puede también hacerse del siguiente modo, valiendonos de los * múltiples

+ /etc/
+ /etc/ssh/***
+ /var/
+ /var/log/***
- *


Una forma mas fácil será:

+ */
+ /etc/ssh/*
+ /var/log/*
- *

pero esto ultimo tiene el inconveniente de recorrer toda la estructura de directorios por debajo de lo indicado como origen, además copiará, aunque vacíos, todos los directorios ya que todos coinciden con + */, por lo que debe utilizarse con la opción --prune-empty-dirs

Las opción --exclude-from es análoga a lo anterior.

6. Sincronización remota

Para las copias en remoto se puede utilizar el protocolo rsync. Esto se hace configurando el demonio rsync para que esté a la escucha como servidor en, al menos, uno de los hosts.
Esto último tiene varios inconvenientes, uno de ellos es, justamente, que esta configuración necesita hacerse, otra es que la información viajara en claro durante la comunicación. Un método muy utilizado es realizar el transporte sobre ssh, para lo cual rsync ya viene preparado y es muy sencillo de hacer.

Para esto todo lo que debe hacerse es decirle a rsync, mediante la opción -e, que shell remoto debe utilizar. También es importante saber la forma de indicar los archivos. Por ejemplo, la siguiente orden, que se ejecutará en el equipo 10.0.0.1, sincronizará el directorio /home/paco/docs local en /media/docs del equipo 10.0.0.2 utilizando como transporte ssh, para esto se tiene corriendo en 10.0.0.2 openssh-server y se utilizará para ello al usuario pepe, usuario de sistema de 10.0.0.2 con permisos para escribir en /media/docs


$ rsync -e ssh -av /home/paco/docs/ pepe@10.0.0.2:/media/docs/

Donde rsync nos solicitará la clave del usuario pepe en 10.0.0.2.

La siguiente orden, ejecutada en 10.0.0.1, sincroniza el directorio /home/pepe presente en 10.0.0.2 en el directorio local /media/pepe, se utiliza ssh como transporte pero esta vez el servicio está a la escucha en el puerto 1234, además se comprimirán los datos antes del transporte (opción -z) y se forzará que la sincronización se base en el cálculo de un hash (opción c) en lugar de tamaño/fecha última modificación.


$ rsync -e "ssh -p 1234" -avzc pepe@10.0.0.2:/home/pepe/ /media/pepe/

Esto último es lo que se conoce como modo pull, ya que se esta "trayendo" información desde un host remoto, el primer ejemplo se conoce como push por "empujar" datos.

7. Autenticación mediante certificado sin frase

Siempre que se utilice ssh como transporte será necesario autenticarnos en el servidor remoto mediante la clave del usuario que utilicemos para acceder al equipo. Si nuestra intención es hacer backups automáticos esto será un problema, la solución es la utilización de claves para la autenticación. Esto ya está más relacionado con openssh que con rsync por lo que solo se describirá brevemente como hacerlo.

Primero crear las claves publicas y privadas sin frase, esto ultimo significa que la clave privada se almacenará sin cifrar lo cual es un riesgo a la seguridad y por lo tanto "siempre" debe hacerse esto para la autenticación de un usuario de privilegios limitados, para nuestro caso supondremos que es el usuario paco del host 10.0.0.2.

Para autenticar un usuario mediante claves en openssh se hace lo siguiente:

Primero se crea el par de claves, suponiendo que nos encontramos en el host 10.0.0.1 e iniciamos sesión con el usuario pepe


$ ssh-keygen

Esto generará las claves, la clave privada por defeto se almacenará en /home/pepe/.ssh/id_rsa y la pública en /home/pepe/.ssh/id_rsa.pub. Es importante no ingresar nada, solo enter, cuando se nos solicite la passphrase (entiéndase esto como frase desafió o password), de lo contrario la passphrase será solicitada en cada conexión volviendo así al problema de tener que interactuar con el sistema cada vez que se intente autenticar.

Lo que debe hacerse ahora es copiar la clave pública en el host al cual se accederá, si lo que se desea hacer es acceder al host 10.0.0.2 mediante el usuario paco, existente en 10.0.0.2, se copiará la clave publica id_rsa.pub en el archivo /home/paco/.ssh/authorized_keys en 10.0.0.2.
La clave privada se mantendrá en el host cliente 10.0.0.1 y se le asignará permiso de solo lectura para el dueño del archivo de modo que solo él, en nuestro caso pepe, pueda ver la clave. Esto último es un requerimiento, si no se hiciera openssh-client emitiría un mensaje de error indicándonos que la clave no es segura y la conexión no tendrá lugar.

Ahora solo resta iniciar una conexión ssh para ver que funciona:


$ ssh paco@10.0.0.2

Lo anterior no requirió indicar la clave privada a utilizar ya que, por defecto openssh la buscará en el archivo id_rsa (como se indica en /etc/ssh/ssh_config), si se quisiera utilizar otra clave se le indica mediante la opción -i archivo.

Ahora ya debemos ser capaces de ejecutar rsync con autenticación mediante clave publica-privada sin necesidad de ingresar la password.

8. Referencias

man rsync
http://samba.anu.edu.au/rsync
http://es.wikipedia.org/wiki/Rsync