Proyecto: Gestor de copias de seguridad versión 0.1b
En vistas de que me ha hecho falta tener que implementar un sistema de copias de respaldo para varias máquinas y que ninguna de las opciones que he estado leyendo satisfacía por completo mis necesidades, me he decidido por echar el sábado picando algo de código y este ha sido el resultado.
Enlace a GitHub: https://github.com/manuel-alcocer/Gestor-respaldos.git
1. Script de copias
El script que he desarrollado, en su primera versión, para la gestión de copias de respaldo cubre los siguientes puntos:
Copias completas
Copias incrementales
Copias remotas
Copias locales
Almacenamiento primario local (obligatorio)
Almacenamientos secundarios remotos (opcionales)
Cifrado mediante par de claves (cifrado asimétrico)
Comprobación de algunos puntos del script (no todos)
Queda pendiente para ir haciendo poco a poco:
Urgente:
Restauración automática de las copias
Gestión de políticas de borrado de copias
- Generación de ficheros con listas de paquetes del sistema
Cuando se pueda:
Almacenamiento primario local y remoto
Almacenamientos secundarios locales y remotos
Comprobar sintaxis en ficheros de configuración
Ayuda (‘–help’)
El script se maneja mediante creación tareas ‘cron’ o temporizadores ‘systemd’.
Es necesario que exista ‘rsync’ en los clientes y en los servidores, primario y secundarios.
‘OpenSSL’ es un requisito del script.
Es necesario tener claves ‘ssh‘ en los pcs remotos para los usuarios que se configuren en las deficiones de máquinas.
2. Estructura de ficheros
2.1. Directorio base para el almacén de las copias de seguridad
Este es el directorio del que colgarán todas las copias de seguridad. Se puede cambiar estableciendo la variable del entorno BASE_STOR.
Por defecto: ‘/BackUps/’.
BASE_STOR=${BASE_STOR:-/BackUps}
2.2. Directorio de configuración de la aplicación
Este ruta será la base de donde colgarán todos los ficheros de configuración del script. Se puede cambiar estableciendo la variable del entorno BACKUPMGR_CONFIG_DIR.
Por defecto: ‘/etc/backupMgr/’.
BACKUPMGR_CONFIG_DIR=${BACKUPMGR_CONFIG_DIR:-/etc/backupMgr}
2.3. Definiciones de máquinas
Fichero con la definición de hosts remotos, con formato: ‘alias:usuario:IP
‘
Se puede cambiar este fichero estableciendo la variable del entorno REMOTE_HOSTS_FILE.
Por defecto: ‘/etc/backupMgr/hosts.list’.
REMOTE_HOSTS_FILE="${BACKUPMGR_CONFIG_DIR}${REMOTE_HOSTS_FILE:-/hosts.list}"
2.4. Definiciones de objetos para guardar
Cada host tiene asociado un fichero, de nombre el alias dado a la IP. En ese fichero se creará una lista con los objetos a guardar, excepciones, cifrado/no cifrado.
Por defecto: ‘/etc/backupMgr/hosts.list.d/’
Se puede cambiar este directorio estableciendo la variable del entorno REMOTE_HOSTS_DIR
en el directorio de la aplicación $REMOTE_HOSTS_DIR con formato por línea:
(tipo de archivo: F-> Fichero, D-> Directorio):(Almacen cifrado: C, No cifrado: NC):(Ruta completa al fichero o directorio)[:(Excluir: E:RUTA1:RUTA2:…RUTAN)],
quedando así: ‘<F|D>:<C|NC>:<Ruta>[:E:Ruta-o-fichero1:ruta-o-fichero-2:...]’
, por ejemplo:
F:NC:/etc/fstab D:C:/etc/ldap:E:/etc/ldap/schema D:NC:/var/cache/bind
NOTA:
Las exclusiones solo se aplican a objetos directorios, las exclusiones pueden ser ficheros o directorios
Se permite el uso de comentarios en las líneas siempre que estas empiecen por #
REMOTE_HOSTS_DIR="${BACKUPMGR_CONFIG_DIR}${REMOTE_HOSTS_DIR:-/hosts.list.d}"
2.5. Lista de hosts de almacenamiento secundarios
Se admiten varios destinos con el siguiente formato: ‘alias:usuario:ip:/ruta-absoluta’
Por ejemplo:
saturno:malcocer:172.22.111.11:/Backup-ASO/malcocer
La línea de configuración en el script es:
SECONDARY_HOSTS_FILE="${BACKUPMGR_CONFIG_DIR}${SECONDARY_HOSTS_FILE:-/secondary_hosts.list}"
2.6. Cifrado de objetos
El script requiere de una clave pública. La ruta al fichero por defecto es: ‘/etc/backupMgr/backupmgr.pubkey.pem’
.
Para generar una clave nueva:
openssl req -x509 -newkey rsa:2048 -sha256 -keyout private_key.pem -out backupmgr.pubkey.pem
CONTRASEÑA DE LA CLAVE SUMINISTRADA: Asd123
Para descifrar el fichero:
openssl smime -decrypt -in fichero.ENCRYPTED.tar.gz \ -binary -inform DEM -inkey private_key.pem \ -out fichero.DECRYPTED.tar.gz
La línea en el script que lo define es:
OPENSSL_PUBKEY="${BACKUPMGR_CONFIG_DIR}${OPENSSL_PUBKEY:-/backupmgr.pubkey.pem}"
3. Código del script
#!/usr/bin/env bash REMOTE_HOSTS=() BASE_STOR=${BASE_STOR:-/BackUps} BACKUPMGR_CONFIG_DIR=${BACKUPMGR_CONFIG_DIR:-/etc/backupMgr} REMOTE_HOSTS_FILE="${BACKUPMGR_CONFIG_DIR}${REMOTE_HOSTS_FILE:-/hosts.list}" REMOTE_HOSTS_DIR="${BACKUPMGR_CONFIG_DIR}${REMOTE_HOSTS_DIR:-/hosts.list.d}" SECONDARY_HOSTS_FILE="${BACKUPMGR_CONFIG_DIR}${SECONDARY_HOSTS_FILE:-/secondary_hosts.list}" OPENSSL_PUBKEY="${BACKUPMGR_CONFIG_DIR}${OPENSSL_PUBKEY:-/backupmgr.pubkey.pem}" COMMAND=$1 LASTOPT=${@: -1} OPTIONS=$2 EXCLUDE=() ALIASHOST='' HOSTFILENAME='' REMOTEUSERNAME='' HOSTIP='' BACKUPDIR='' TARGETDIR='' function exitWithErr(){ printf 'Hubieron errores...Saliendo\n' exit 1 } function getRemoteHost(){ while IFS= read -r linea; do REMOTE_HOSTS+=("${linea}") done < ${REMOTE_HOSTS_FILE} } function checkConfig(){ if [[ ! -f ${REMOTE_HOSTS_FILE} ]]; then printf "No existe el fichero de hosts remotos ${REMOTE_HOSTS_FILE}\n" exitWithErr fi if [[ ! -d ${BASE_STOR} ]]; then printf "No existe la ruta de almacenamiento local ${BASE_STOR}\n" exitWithErr fi if [[ ! -f ${SECONDARY_HOSTS_FILE} ]]; then printf "No existe el fichero de almacenamiento secundario ${SECONDARY_HOSTS_FILE}\n" exitWithErr fi } function genExcludes(){ EXCLUDE=() excludeVal=$(cut -d':' -f4 <<< $1) if [[ ${excludeVal^^} == 'E' ]]; then excludeVals=${1#*:E:} SAVEIFS=$IFS IFS=: for field in ${excludeVals}; do EXCLUDE+=("--exclude ${field}") done IFS=$SAVEIFS fi } function uploadBackupDir(){ temporaryTar=/tmp/${2##*/}-${1}-${3}.tar.gz tar czf ${temporaryTar} ${2} while IFS= read -r linea; do rsyncToSecondary ${linea} $1 $3 ${temporaryTar} done < ${SECONDARY_HOSTS_FILE} } function rsyncToSecondary(){ secRemUser=$(cut -d':' -f2 <<< $1) secRemHost=$(cut -d':' -f3 <<< $1) secRemDir="$(cut -d':' -f4 <<< $1)/${2}/${3}" rsync $4 ${secRemUser}@${secRemHost}:${secRemDir} } function lastFullRsync(){ baseDir="${BASE_STOR}/${1}/fullSync" lastDir="$(ls -t ${baseDir} | head -n1)" printf "${lastDir}\n" } function createVars(){ ALIASHOST=$(cut -d':' -f1 <<< $1) HOSTFILENAME="${REMOTE_HOSTS_DIR}/${ALIASHOST}" REMOTEUSERNAME=$(cut -d':' -f2 <<< $1) HOSTIP=$(cut -d':' -f3 <<< $1) if [[ $3 == 'full' ]]; then TARGETDIR="${BASE_STOR}/${ALIASHOST}/fullSync/${2}" BACKUPDIR="${TARGETDIR}" else TARGETDIR="${BASE_STOR}/${ALIASHOST}/fullSync/$(lastFullRsync ${ALIASHOST})" BACKUPDIR="${BASE_STOR}/${ALIASHOST}/incrSync/${2}" fi } function rsyncObjects(){ case $1 in incrF) rsyncOPTS="-ab --checksum --backup-dir=${BACKUPDIR} --relative" ;; fullF) rsyncOPTS="-a --relative" ;; incrD) genExcludes $2 rsyncOPTS="-ab --checksum ${EXCLUDE} --delete --backup-dir=${BACKUPDIR} --relative" ;; fullD) genExcludes $2 rsyncOPTS="-a ${EXCLUDE} --relative" ;; esac if [[ ! -d ${TARGETDIR} ]]; then mkdir -p ${TARGETDIR} fi BCKPOBJ=$(cut -d':' -f3 <<< $2) if [[ ${HOSTIP,,} != 'localhost' ]]; then BCKPOBJ="${REMOTEUSERNAME}@${HOSTIP}:${BCKPOBJ}" fi rsync ${rsyncOPTS} ${BCKPOBJ} ${TARGETDIR} } function encryptObject(){ targetObject=$(cut -d':' -f3 <<< $1) targetFullPath="${TARGETDIR}/${targetObject}" targetTar="${targetFullPath}.tar.gz" targetEncryptedTar="${TARGETDIR}/${targetObject//\//-}.ENCRYPTED.tar.gz" tar czf "${targetFullPath}.tar.gz" "${targetFullPath}" openssl smime -encrypt -binary -aes-256-cbc \ -in ${targetTar} -out ${targetEncryptedTar} \ -outform DER ${OPENSSL_PUBKEY} rm -rf ${targetFullPath} ${targetTar} } function mainRsync(){ while IFS= read -r linea; do if [[ ! ${linea} =~ ^[[:space:]]*#.* ]]; then objectType=$(cut -d':' -f1 <<< ${linea}) rsyncObjects ${1}${objectType^^} ${linea} unset storSecurity storSecurity=$(cut -d':' -f2 <<< ${linea}) if [[ ${storSecurity^^} == 'C' ]]; then encryptObject ${linea} fi fi done < $HOSTFILENAME if [[ ${OPTIONS} == '--secondary-stor' ]]; then uploadBackupDir ${ALIASHOST} ${BACKUPDIR} ${1} fi } function makeBackup(){ getRemoteHost currentDate=$(date +%y-%U-%m%d-%H%M) for remoteHost in "${REMOTE_HOSTS[@]}"; do createVars "${remoteHost}" "${currentDate}" $1 mainRsync $1 done } function main(){ checkConfig case ${COMMAND,,} in full) makeBackup full ;; incr) makeBackup incr ;; *) printf 'Error en el comando\n' ;; esac } [[ $LASTOPT == '-d' ]] && set -x main $OPTIONS [[ $LASTOPT == '-d' ]] && set +x
1 respuesta
viagra online
WALCOME