Copias de seguridad en AWS S3 con duply

27 de diciembre 2018ComentarioslinuxDavid Poza SuárezComentarios

Duply es una interfaz de línea de comandos que simplifica el uso de otro comando llamado duplicity, escrito en python, que usa librsync , y que sirve para realizar copias de seguridad incrementales y encriptadas en un repositorio externo. Entre las muchas opciones soportadas como almacenamiento podemos destacar algunas, como son un servidor ftp o servicios como azure, dropbox, mega, onedrive, o aws s3, siendo este último el que nos ocupa en esta ocasión.

¿Por qué es tan interesante AWS S3?

Cuando hablamos de AWS S3 hablamos de un servicio de almacenamiento de objetos, como pueden ser Azure Blob Storage , Google Cloud Storage o Spaces en Digital Ocean.

El object based storage llega para ofrecer mayor escalabilidad, a cambio de dejar de trabajar con datos estructurados e incluir mayores latencias que las opciones basadas en bloques o ficheros. Sus diferencias principales son:

  • Se basa en una API http, lo que significa que puede integrarse fácilmente con otras aplicaciones, como es el caso de duplicity. Además es independiente del sistema operativo.
  • Se desprende de las restricciones que supone un sistema de ficheros, como son la jerarquía de directorios y subdirectorios. Y esto se sustituye por un contenedores de objetos con un identificador único, unos metadatos asociados y el fichero propiamente dicho.
  • Permite que cada objeto se encuentre almacenado en ubicaciones diferentes y no necesita conocerse por el cliente. Lo que permite reducir costes y permite una escalabilidad casi ilimitada.
  • El propio sistema garantiza la redundancia de los datos, de modo que nosotros no tenemos montar un RAID ni nada parecido.
  • Contratar un sistema de bloques implica pagar también el que espacio sin usar, mientras que con aws s3 únicamente pagaremos lo que usemos.
  • Funciona muy bien con datos no estructurados. Por el contrario, montar un sistema de objetos como sistema de ficheros (como hace s3fs, goofys o riofs entre otros) tiene un gran impacto negativo en el rendimiento.
  • En un sistema de ficheros podemos modificar una porción de un archivo pero en los sistemas de objetos no es recomendable, ya que si hacemos un cambio en un objeto deberemos borrar el existente y subir un objeto nuevo con la modificación. Aumentando por tanto el tráfico de datos ante pequeñas modificaciones.

tipos almacenamiento 1024x566

En resumen, tenemos un almacenamiento más lento pero muchísimo más barato. Por ello es interesante para guardar gran cantidad de datos que no requieren rápido acceso, perfecto para hacer backups.

Configuración AWS S3

Supondremos que ya estás dado de alta en AWS, datos de pago, has configurado la doble autenticación, etc.

El primer paso es crear una clave de acceso para usar la API de S3, que será la que indicaremos en el fichero de configuración de duply. Para ello vamos a IAM Management Console > Usuarios > Claves de acceso > Crear una clave de acceso.

Paso 1

Paso 1

Paso 2

Paso 2

El siguiente paso será crear una política para dar permisos de acceso a S3 para nuestro usuario en AWS. Para no complicarnos la vida creando una política personalizada, seleccionaremos una ya existente: AmazonS3FullAccess. Vamos a la sección Usuarios > pestaña Permisos > botón Añadir permisos.

politica aws s3

Un bucket es una forma de organización de objetos. Podríamos por ejemplo tener un bucket para clientes y otro para uso privado, o un bucket por cliente. Aunque sin duda yo prefiero tener un solo bucket y crear una política personalizada para gestionar el acceso de los diferentes usuarios a determinadas carpetas.

Lo importante que debemos saber de un bucket es que tiene ciertas limitaciones, como que no se puede cambiar de nombre, que este debe ser único de forma global (entre todos los usuarios de Aws) o que existe un límite de 100 buckets por cuenta aws.

El último paso es crear el bucket, en este ejemplo un solo bucket con acceso total para nuestro usuario. Para ello accedemos a la consola de administración de S3: https://s3.console.aws.amazon.com/s3/home y pulsamos el botón Crear bucket. Simplemente le damos un nombre único y la región donde vamos a alojar los datos (a mí me gusta que sea Europa por latencia y porque nos beneficia la ley de protección de datos).

AWS S3 posee infinidad de opciones, como el sistema de versiones o el cifrado, pero para este ejemplo lo mantendremos todo sencillo, el resto de opciones no es necesario rellenarlas.

crear bucket 1024x747

Instalación de duply

add-apt-repository ppa:duplicity-team/ppa
apt-get update
apt-get install duplicity duply python-boto
pip install boto

Configuración de duply

Para este artículo voy a estar usando Duply 2.1 y duplicity 0.7.18.2 en un Ubuntu 16.04.

Duply permite tener varios perfiles de backup, asi que lo primero es crear uno nuevo. Simplemente tecleamos duply nombre_perfil create y se nos creará un fichero en ~/.duply/nombre_perfil/conf.

Es muy recomendable tener una copia del directorio de perfil fuera de la propia copia de duply.

Fichero conf

# no vamos a encriptar las copias
GPG_KEY='disabled'
#GPG_PW='_GPG_PASSWORD_'

TARGET='s3://s3-eu-west-1.amazonaws.com/BUCKET/CARPETABUCKET'
export AWS_ACCESS_KEY_ID='AKIAJNJUCXBGW63USBAQ'
export AWS_SECRET_ACCESS_KEY='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'
# signature v4 es requerido para algunas zonas como paris o frankfurt
export S3_USE_SIGV4="True"

# la carpeta base de donde vamos a realizar nuestras copias
SOURCE='/'

# Mantendremos nuestras copias antiguas un máximo de tres meses
# Esta variable se usa cuando se hace un purge
MAX_AGE=3M

# Mantendremos dos copias completas en todo momentos, por si una se corrompiese. Esta variable se usa cuando se hace un purgeFull
MAX_FULL_BACKUPS=2

# Tiempo máximo en generar un nuevo backup full
# MAX_FULLBKP_AGE no es un parámetro de duply.
# Para ello llamaremos a duplicity con el parámetro --full-if-older-than
MAX_FULLBKP_AGE=1M

# VOLSIZE no es un parámetro de duply.
# Para evitar tener demasiados ficheros de volumen por backup.
# Para ello llamamos a duplicity con el parámetro --volsize
VOLSIZE=1024

# Podemos personalizar la llamada a duplicity
# verbosity info para incluir el listado de ficheros copiados en el log.
DUPL_PARAMS="$DUPL_PARAMS --volsize $VOLSIZE --full-if-older-than $MAX_FULLBKP_AGE --verbosity info --s3-use-new-style --s3-european-buckets"

Podemos encontrar el listado de urls de los endpoints de aws s3 aquí

El fichero conf del ejemplo plantea la siguiente planificación:

planificacion duply 1024x779

Cifrado de la copia

Puede ser muy interesante cifrar la copia, para lo cual usaremos GnuPG, del que ya he hablado aquí.

Para ello simplemente tendremos que establecer las siguientes opciones en el fichero conf.

GPG_KEY='XXXXXXXX'        # el id de tu clave pública gpg
GPG_PW='Passphrase'   # Passphrase de tu clave, para poder firmar

Como resultado del cifrado si acudimos a ver los ficheros de volúmenes, manifest y signatures, ahora tendrán extensión gpg para indicar que están encriptados.

Necesitaremos el passphrase para hacer restauración y también para los comandos list y status.

-rw------- 1 root      root           797 Dec 28 10:57 duplicity-full.20181228T095724Z.manifest.gpg
-rw------- 1 root      root      12009790 Dec 28 10:57 duplicity-full.20181228T095724Z.vol1.difftar.gpg
-rw------- 1 root      root        761868 Dec 28 10:57 duplicity-full-signatures.20181228T095724Z.sigtar.gpg

Fichero exclude

Para configurar los directorios que queremos incluir o excluir tendremos que editar el fichero ~/.duply/nombre_perfil/exclude. Usando el símbolo + incluimos y con el símbolo - excluimos. Por ejemplo para realizar un backup completo de la máquina hemos usado SOURCE="/" en el conf y la siguiente lista de exclusiones:

  • /proc
  • /sys
  • /run
  • /dev
  • /tmp
  • /boot
  • /media
  • /mnt
  • /lost+found
  • /var/lib/lxcfs

Podemos excluir todo usando comodínes: - **

Ejecutar un backup

Para ejecutar una copia solo tenemos que lanzar el siguiente comando:

duply nombre_perfil backup

Si estamos probando un nuevo perfil y queremos realizar solo una prueba sin copiar realmente los ficheros, tenemos el flag preview

duply nombre_perfil backup --preview

Habitualmente se incluye en el cron la llamada para realizar el backup:

0 2 * * * env HOME=/root /usr/bin/duply nombre_perfil backup

Ejecutar secuencias personalizadas

Lanzar un backup con el comando backup equivale a:

  1. Ejecutar el script pre (si existe)
  2. Ejecutar el backup
  3. Ejecutar el script post (si existe)

Pero podemos componer nuestras propias secuencias con las siguientes acciones:

  • pre (ejecuta el script ~/.duply/nombre_perfil/pre)
  • post (ejecuta el script ~/.duply/nombre_perfil/post)
  • bkp (ejecuta full si no existe y en caso de tener uno ejecutará un incremental)
  • full (fuerza un backup completo)
  • inc (fuerza un backup incremental)
  • purge (realiza un limpiado de backups con antigüedad mayor que MAX_AGE en el conf).
  • verify (comprueba los archivos que han cambiado, útil si el backup devuelve errores porque hay ficheros que han cambiado durante su ejecución.)

Para crear una secuencia simplemente usamos el carácter "" para separar acciones, y estas se ejecutarán en orden de izquierda a derecha. Por ejemplo: `duply nombreperfil prebkppurge`.

Incluso tenemos la opción de usar otros separadores:

    • Sólo se ejecutará si la acción anterior ha tenido éxito.
    • Sólo se ejecutará si la acción anterior ha fallado.

Borrar los backups antiguos si el backup ha tenido éxito

duply nombre_perfil bkp+purge

Estadísticas

Al finalizar la copia obtendremos un conjunto de estadísticas:

--------------[ Backup Statistics ]--------------
StartTime 1545991044.99 (Fri Dec 28 10:57:24 2018)
EndTime 1545991049.75 (Fri Dec 28 10:57:29 2018)
ElapsedTime 4.76 (4.76 seconds)
SourceFiles 5038
SourceFileSize 34095125 (32.5 MB)
NewFiles 5038
NewFileSize 34095125 (32.5 MB)
DeletedFiles 0
ChangedFiles 0
ChangedFileSize 0 (0 bytes)
ChangedDeltaSize 0 (0 bytes)
DeltaEntries 5038
RawDeltaSize 32030591 (30.5 MB)
TotalDestinationSizeChange 12009790 (11.5 MB)
Errors 0
-------------------------------------------------

Forzar un backup completo

Cada cuánto hacemos un backup full se controla con el flag --full-if-older-than de duplicity, sin embargo si por algún motivo queremos lanzar de inmediato un backup completo simplemente tecleamos:

duply nombre_perfil full

Lanzar script antes del backup

Es muy habitual querer lanzar un script antes o después de hacer un backup, por ejemplo si queremos incluir un volcado de la base de datos en el mismo.

Para ello podemos crear el script que queramos en las rutas indicadas:

~/.duply/nombre_perfil/pre
~/.duply/nombre_perfil/post

Script para backup

Otra opción es crear un pequeño script que controle todo el flujo de la copia invocando él mismo a duply. En mi github dejo un ejemplo de script en python que he preparado. Hace un volcado de mysql y además envía por correo el log de duply: https://github.com/davidpoza/dps-backups-duply

Contenido del backup

Historial

Es muy interesante disponer de un listado de las fechas y los tipos de backup que se han ido realizando a lo largo del tiempo así como los volúmenes que ocupan cada uno.

Con el comando status podemos ver las diferentes cadenas (chain) que se han ido realizando, siendo una cadena cada grupo de full backup + sus incrementales.

duply nombre_perfil status

Chain start time: Sun Sep 23 17:57:43 2018
Chain end time: Thu Dec 27 02:00:05 2018
Number of contained backup sets: 96
Total number of contained volumes: 106
 Type of backup set:                            Time:      Num volumes:
                Full         Sun Sep 23 17:57:43 2018                 7
         Incremental         Mon Sep 24 02:00:03 2018                 1
         Incremental         Tue Sep 25 02:00:03 2018                 2
         Incremental         Wed Sep 26 02:00:03 2018                 1
         Incremental         Thu Sep 27 02:00:04 2018                 1
         Incremental         Fri Sep 28 02:00:04 2018                 2
         Incremental         Sat Sep 29 02:00:04 2018                 1
         Incremental         Sun Sep 30 02:00:04 2018                 1
         Incremental         Mon Oct  1 02:00:04 2018                 1
         Incremental         Tue Oct  2 02:00:04 2018                 1
         Incremental         Wed Oct  3 02:00:04 2018                 1
         Incremental         Thu Oct  4 02:00:04 2018                 1
         Incremental         Fri Oct  5 02:00:05 2018                 1
         Incremental         Sat Oct  6 02:00:06 2018                 1
.....

Si vamos a S3 podremos observar los diferentes volúmenes(contienen los ficheros respaldados) que va creando duply en función del --volsize especificado. También vemos archivos manifest, que son los que determinan todos los volúmenes que componen un backup y qué rango de ficheros se guardan en cada uno. Y por último veremos los archivos de signatures, que son listados de ficheros con su hash SHA1, usados para poder identificar cuáles han cambiado desde la última copia y así poder realizar un incremental o para crear el listado de ficheros que veremos a continuación.

Así cuando queremos restaurar un fichero, se leen los manifest y signatures y de este modo duply sabe exactamente qué volúmenes debe descargar de aws s3.

aws s3 duply 1024x460

Listado de ficheros

Puede ser que queramos saber si nuestro backup contiene un fichero o concreto. Esta opción es útil pero requiere descargar todo el listado de ficheros del backup, y puede tardar. Por supuesto es útil filtrar con grep.

duply nombre_perfil list
duply nombre_perfil list | grep /var/www

Borrar copias con antigüedad mayor que

Podemos limpiar las copias que tengan una antigüedad mayor a la indicada. Si no indicamos antigüedad entonces usará la variable MAX_AGE del conf. Por defecto no realiza los cambios, para hacerlos efectivamente hay que incluir el flag --force.

duply nombre_perfil purge [max_age] [--force]

En realidad no tiene mucho sentido hacer el purgado manualmente, se puede automatizar, para ello ver apartado Ejecutar secuencias personalizadas.

Borrar copias dejando N backups full

Si lo que deseamos es dejar N copias full (más sus incrementales asociados), debemos usar el comando purgeFull. Si no se indica el parámetro se usa la variable MAXFULLBACKUPS del conf.

duply nombre_perfil purgeFull [max_full_backups] [--force]

Realizar una restauración

Restaurar copia completa

Podemos restaurar toda la copia en el directorio que deseemos. Además tenemos un segundo parámetro age para indicar el momento exacto que queremos. Por defecto si no se indica, se recupera la última versión.

Age acepta los siguientes formatos:

  • 2002-01-25T07:00:00+02:00
  • 2002/3/5 (fecha AAAA/MM/DD)
  • 12D (hace 12 días)
  • 1h78m (hace 1 hora y 78 minutos)

duply nombre_perfil restore /destino [age]

Restaurar un fichero o directorio concreto

Salvo catástrofe, lo normal es querer restaurar solo un fichero o directorio, no toda la copia completa.

duply nombre_perfil fetch dir/subdir /restore [age]

Una restauración puede llevar bastante tiempo (dependiendo del tamaño total del backup) aunque solo queramos unos pocos ficheros, ya que tendremos que recuperar de AWS S3 un backup full más cierto número de incrementales. Toda esta operación se realiza en un directorio temporal del tipo /tmp/duplicity-jUXZc-tempdir_. Al finalizar la restauración podremos ver el tiempo que ha durado la operación:

--- Finished state OK at 17:33:50.030 - Runtime 00:14:08.329 ---

Resturar backup cifrado

Si el backup lo hemos cifrado, y tenemos el GPG_PW definida en el fichero conf, entonces la restauración realiza automáticamente el descifrado sin intervención del usuario. En caso contrario nos preguntará por el passphrase.

Documentación

Como siempre, me gusta apuntar a la documentación oficial, para poder profundizar en el funcionamiento de duply o de duplicity.