Recientemente he tenido que montar un chiringo de copias de seguridad para un par de servidores web tipicos (php+mysql) bajo CentOS y como estamos en crisis ha tenido que ser con software gratuito, de modo que despues de mirar las soluciones disponibles me decante por Rsnapshot, un script hecho en perl que por debajo usa las utilidades tipicas del sistema y rsync, reconocido programa para sincronizar directorios por red.
En principio el proceso es simple, pero como siempre sucede en el mundo Linux, lo que empieza simple acaba convirtiendose en un cipotillo de padre y muy señor mio, y esta vez no va a ser la excepcion aunque hay q reconocer que tampoco es para tanto. Lo importante es que una cosa simple te lleva horas por detalles estupidos, con lo que lo que te ahorras en licencias te lo gastas en mano de obra, pero esa es otra historia que merece ser comentada en otro momento.
La idea es hacer una copia de las paginas web, base de datos y ficheros de configuracion una vez al dia y dejarlos en un equipo remoto.
Para empezar la fiesta vamos a bautizar a los equipos: por un lado esta el servidor web y por el otro lado esta el servidor de copias. El caso es que el servidor de copias actua mas como cliente que como servidor ya que sera el servidor de copias el que se conecte al servidor web para recuperar los ficheros que hayan cambiado; con esto quiero decir que el servidor web no sera el que envie los datos a su gusto y antojo al servidor de copias sino sera el servidor de copias el que pida los datos al servidor web (push vs pull). Una ventaja de este esquema es que no es necesario instalar ningun agente ni nada en los servidores que vayamos a copiar (siempre y cuando tengan las herramientas basicas del sistema, servidor de ssh y una version de rsync modernilla).
- Primeramente descargamos rsnapshot de aqui.
- Lo vamos a instalar unicamente en el servidor de copias con:
gunzip rsnapshot.tar.gz
tar xvf rsnapshot.tar
./configure
make install
cp /usr/local/etc/rsnapshot.conf.default /usr/local/etc/rsnapshot.conf
- Para que la cosa rule de forma un poco segura lo vamos a lanzar con la cuenta rsnapshot (luego veremos el porque) que procedemos a crear en el servidor de copias:
adduser rsnapshot
- Vamos a realizar una copia todos los dias a las 2 de la mañana asi que creamos el fichero
touch /var/spool/cron/rnsapshot
le damos permisos de r,w,x para el usuario que lo va a lanzar
chmod 700 /var/spool/cron/rnsapshot
chown rsnapshot:rsnapshot /var/spool/cron/rnsapshot
A continuacion vamos a añadir una linea que le indique al cron cuando y qué debe de ejecutar
0 2 * * * /usr/local/bin/rsnapshot daily
y con esto y un bizcocho reiniciamos el cron a las 8 =:? para que lea los ficheros de config:
/etc/init.d/cron restart
Bien, ya tenemos lo mas facil, el script instalado y listo para ejecutarse todos los dias a las 2 AM.
- Ahora vamos a ver el fichero de configuracion del rsnapshot:
Primeramente hay que tener cuidado con la sintaxis, no se admiten espacios, hay que tabular siempre.
La mayor parte de los parametros estan bien como vienen y el fichero es bastante autoexplicativo.
Con snapshot_root indicamos la carpeta donde se dejaran los backups
snapshot_root /home/snapshots/
Los ficheros de log los dejamos en
logfile /home/snapshots/sys/rsnapshot
El fichero que contiene el pid en
lockfile /home/snapshots/sys/rsnapshot.pid
para el nivel de verbosity
verbose 2
loglevel 3
Se dejan los logs en el home del usuario ya que necesita permisos de escritura y que mejor lugar que su propio directorio. Lo mismo le pasa al fichero que contiene el pid del proceso.
Precisamente la parte que hay que cambiar por narices viene fatalmente explicada en la pagina web, y es la que nos permite indicar QUE hay que copiar y CUANTO tiempo hay q mantener las copias. Se trata de las siguientes lineas:
interval daily 7
backup /home/ localhost/
Hay que hacer notar CON MAYUSCULAS que la linea interval no tiene nada que ver con intervalos y la palabra daily, weekly etc NO INDICAN NADAN, ES SOLO UNA ETIQUETA que puede ser sustituida por cualquier otra.
Lo que se esta diciendo aqui es que nuestra copia se llamara daily y se rotara 7 veces, esto es: se mantendran las ultimas 7 copias. Como en el cron lo hemos puesto diario entonces vamos a mantener 7 dias de copias.
Por otro lado la linea backup /home/ localhost/ indica que hay que hacer un backup de /home/ y dejarlo en localhost, que es un path relativo que se añade al indicado en snapshot_root.
Lo que a mi no me cabia en la cabeza era que se le estuviera indicando un CUANDO hacer la copia en el fichero de configuracion si ya se lo estaba indicando yo en el cron (es aqui cuando empiezan las paranoias: tendra el script implementado su propio cron? como se conjuga el daily con la configuracion del cron? bueno, pues nada, el daily no significa nada, solo es el nombre de la carpeta que va a crear el rsnapshot cuando haga el backup).
- Generar y configurar los certificados
Finalmente la cosa viene con otra de esas tocadillas de pito cortesia del linux de rigor, y es que hay q bregar con los dichosos certificados digitales. Claro, uno se pensara que es lo guapo del software libre, todo se hace por piezas, lo que hizo pepe lo reutiliza juan y que bien que funcionan las cosas. Bueno, pues vale. El caso es que aqui la transferencia de ficheros se hace por ssh pero no se puede usar autenticacion por password, asi que toca empaparse un poco de certificados. Ya nos hemos tenido que empapar de como funciona el cron, el propio programa con el fichero de configuracion que va a su puta bola con los tabuladores y ahora toca ssh y certis; vamos que nos vamos:
Pues para no liar demasiado al personal vamos a resumir: se genera un par de claves asimetricas para la autenticacion del servidor de copias en el servidor web. El servidor web es el que corre el demonio ssh y el servidor de copias el que ejecutara el cliente de ssh.
Las claves asimetricas van emparejadas: lo que encripta una lo desencripta la otra y viceversa. Asi, una vez generadas tendre una clave publica y una clave privada, las dos relativas al equipo que se va a conectar, esto es, el servidore de copias. La clave privada es privada y solo la sabe el servidor de copias. La publica es publica y la sabe el servidor de copias y el servidor web. Es mas, las claves no se generan por equipo (ya podrian) sino por usuario, asi tenemos que el usuario rsnapshot del servidor de copias se quiere conectar al servidor web, de modo que para empezar tendremos que dar de alta esta cuenta en el servidor web:
adduser rsnapshot
Una vez hecho, en el servidor de copias generamos el par de claves:
su rsnapshot
ssh-keygen -t rsa
Es importante cambiar al usuario para el que vamos a generar el par de claves. Hemos elegido el algoritmo de cifrado asimetrico rsa aunque podriamos haber puesto dsa, que es el otro disponible (para mas info de esto mirar en la wikipedia aqui y aqui).
Despues de esto tendremos nuestras claves en /home/rsnapshot/.ssh. Una sera ids_rsa y la otra ids_rsa.pub. El pub es de publico asi que la primera es la que no tiene que salir del equipo ya que es la privada.
Ojo que al generar las claves nos pide passprase, no se puede poner nada ahi porque sino el rsnapshot no funciona. Esto de por si es una verdadera anchoa en cuanto a seguridad, mas de uno estara pensando “joder, tanta historia con cifrados, certificados y tal pero como me manguen la clave ya la hemos liado parda porque la van a poder usar sin mas complicacion”. Pues si, estas cosas son asi, ya se sabe. Es por eso que todo se resuelve con una cuenta como rsnapshot, muy capada. Se puede capar mas instalando cualquier alternativa a bash que restrinja los comandos a lanzar, pero ya es que me parece una sobrada hacer estas movidas para instalar un triste programa de backup. Yo no recomendaria generar certificados para root y usar este usuario para lanzar rsnapshot aunque sea algo muy tentador por temas de permisos como ya se vera. Tambien podemos añadir algo de seguridad restringiendo las IPs de origen permitidas para conectarse por ssh; estas cosas ya las dejo un poco en el aire porque sino va a quedar un post mas largo que un año sin pan.
El cliente y el servidor ssh van un poco de la mano: el cliente coge su clave privada del directorio /home/rsnapshot/.ssh para encriptar la comunicacion cuando quiere enviarle algo al servidor ssh y el servidor ssh coge la clave publica de /home/rsnapshot/.ssh cuando quiere descifrar lo que recibe cifrado del usuario rsnapshot. De esta guisa hay que copiar ids_rsa.pub desde la maquina del cliente (el servidor de copias) a la maquina servidora (el servidor web) y dejarlo en el mismo directorio pero renombrando el fichero como authorized_keys.
scp /home/rsnapshot/.ssh/id_rsa.pub rsnapshot@IP:/home/rsnaphost/.ssh/authorized_keys
Asi como cada cliente que se conecta al servidor va a tener su propia clave privada en su directorio home, el servidor puede tener un unico fichero authorized_keys con todas las claves publicas de todos los clientes que se vayan a conectar. Para ello solo hay que ir copiando el contenido de todos los .pub que los distintos clientes hayan generado.
Llegados a este punto se impone recapitular:
Cliente: tiene la clave privada (ids_rsa) en /home/rsnapshot/.ssh
Servidor: tiene la clave publica (ids_rsa.pub) en /home/rsnapshot/.ssh renombrada como authorized_keys.
OJO: Revisar los permisos!!, el owner de /home/rsnapshot/.ssh y de su contenido tanto en el cliente como en el servidor tiene que ser el user rsnapshot y los permisos 700!! (r,w,x para el owner) sino no fona.
Mas cosas, hay que habilitar la autenticacion por RSA en el servidor ssh:
RSAAuthentication yes
PubkeyAuthentication yes
Para indicar donde buscara el servidor sshd las claves publicas de los clientes que se vayan conectando se puede poner
AuthorizedKeysFile /path/to/authorized_keys
si lo queremos centralizado en un mismo sitio o sino
AuthorizedKeysFile .ssh/authorized_keys
que hace referencia a un path relativo, que varia segun el usuario que se conecte
Reinicar el demonio
/etc/nit.d/sshd restart
y listo.
Podemos hacer una prueba de conectividad: en el cliente hacemos
su rsnapshot
ssh IP_WEB
y vemos que no nos pide clave
Si la cosa no ha funcionado y nos sigue pidiendo clave se pueden sacar los mensajes de debug del cliente ssh con
ssh-vvv IP_WEB
y mirar en el fichero
tail -f /var/log/secure
del servidor ssh para ver lo que esta pasando por sus tripas.
Una vez hecha la prueba hacemos desde el servidor de copias
su rsnapshot
rsnapshot daily
Con lo que se ejecutara y dejara los resultados en la carpeta que hayamos configurado. Si hay errores quedaran marcados en consola y en el fichero indicado en la directiva de configuracion logfile del fichero de configuracion rsnapshot.conf
Aqui viene el otro tinglado, y es que como el rsnapshot se ejecuta con permisos un poco cutres es posible que no pueda ni leer algunas paginas web o ficheros. Yo lo que recomendaria es configurar el apache para que se ejecute bajo un usuario y grupo determinado, hacer un
chown -R usuarioapache:grupoapache /www
de todo el arbol de paginas web y meter al rsnapshot en el grupo grupoapache, teniendo cuidado de ejecutar antes algo como
chmod -R 640 /www
para dar permisos de r,w a usuarioapache, de r a grupoapache (es decir, a rsnapshot) y nada para el resto al arbol de directorios web.
Despues de todo este tingladillo, que no es poco, vienen las copias del mysql. Esto es facil, nos bajamos automysqlbackup.sh de aqui, lo ponemos en el cron para que se ejecute antes del rsnapshot y a correr. Yo lo tengo como root asi
0 1 * * * /usr/local/bin/automysqlbackup.sh.2.5
Este script vuelca todas las bases de datos a texto a la carpeta q le indiquemos. De alli la podremos transferir de la misma forma que transferimos ficheros o paginas con el rsnapshot.
Los parametros mas importantes del automysqlbackup son los que siguen:
USERNAME= "usuario para conectarse a la bd"
PASSWORD= "password para conectarse a la bd"
DBNAMES="all" #bases de datos a grabar
BACKUPDIR="/path" #path donde se dejan
MAILADDR="user@mail.com"
MDBNAMES="mysql $DBNAMES"
Y yo creo q esto es todo, que no es precisamente poco. Un exito mas para el software libre un tanto descafeinado.