Demonizando Latch para proteger archivos con dos llaves

Antes de nada querría dar las gracias a Helloween por tomarle prestada un trozo de su portada del magnífico álbum "Keeper of seven keys" para ilustrar esta entrada....

Imaginemos que tenemos un servidor dispuesto para nuestros usuarios. Tenemos cierto archivo o carpeta que tiene que estar disponible para dos usuarios en concreto; el cual no puede ser leído o modificado sin el permiso de ambos.

Sería genial que ambos usuarios pudiesen tener el control sobre este hecho, como si se tratase de un cofre el cual necesita dos llaves (podrían ser más) para ser abierto, sin ni siquiera tener un acceso físico a la máquina, es decir,  que puedan decidirlo por control remoto desde su smartphone y así tener el control total sobre el acceso a dicho archivo o carpeta...

Esta situación es posible si miramos las posibilidades que nos brinda LATCH (de paso les agradezco a 11paths el juguetico que me hace pasar unas horas muy entretenido) y hacemos un apañejo, o chapucilla a la espera de que implementen algo parecido (que seguro que lo han pensado).

Pues bueno vamos a ver como lo hacemos y al tiempo aprenderemos a hacer nuestros propios demonios en Linux.

Lo primero sería dar dos usuarios de alta en Latch, para así disponer de "las llaves" para nuestro cofre (una para cada uno). Lo haremos en latch.elevenpaths.com.

No me entretendré en este proceso por no alargar la entrada, si queréis verlo detenidamente echar un ojo a esta otro post crear cuenta latch.

Una vez hecho ésto pasaremos a registrar ambas cuentas en el sistema con el siguiente script , tambien tenemos descrito el proceso en la entrada anterior en la parte de emparejar nuestra cuenta. Como es obvio, lo haremos una vez por cada id de aplicación y su correspondiente secreto y en distintos archivos (latch-llave1.account y latch-llave2.account). Con ésto ya tenemos nuestras "2 llaves":


Liberando nuestro demonio

"Un demonio, daemon o dæmon (de sus siglas en inglés Disk And Execution MONitor), es un tipo especial de proceso informático no interactivo, es decir, que se ejecuta en segundo plano en vez de ser controlado directamente por el usuario. Este tipo de programas se ejecutan de forma continua (infinita), vale decir, que aunque se intente cerrar o matar el proceso, este continuará en ejecución o se reiniciará automáticamente. Todo esto sin intervención de terceros y sin dependencia de consola alguna.” (Wikipedia)

En este caso vamos a utilizar un demonio sencillo en System V, pero no olvidemos que lo podemos complicar tanto como queramos...
#NUESTRO DEMONIO
#!/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/bin/daemonkeeper #Ruta a nuestro fichero a ejecutar
DAEMON_OPTS=''
NAME=daemonlatch            #nombre de nuestro demonio
DESC=keeper_of_seven_keys
PIDFILE="/var/run/${NAME}.pid" #Donde se guarda el pid del proceso
QUIET="--quiet"
START_OPTS="--start ${QUIET} --background --make-pidfile --pidfile ${PIDFILE} --exec ${DAEMON} ${DAEMON_OPTS}"
STOP_OPTS="--stop --pidfile ${PIDFILE}"
OWNER=root                              #el dueño del proceso
LOGDIR=/var/log/${NAME}          #donde guardaremos nuestros logs

test -x $DAEMON || exit 0

# SI NO EXISTE EL DIRECTORIO LOG, LO CREAMOS
if [ ! -d "$LOGDIR" ]; then
    mkdir -m 750 $LOGDIR
    chown $OWNER:$OWNER $LOGDIR
fi

set -e

case "$1" in
  start)
 echo -n "Starting $DESC: "
 start-stop-daemon $START_OPTS
 echo "$NAME."
 ;;
  stop)
 echo -n "Stopping $DESC: "
 start-stop-daemon $STOP_OPTS
 echo "$NAME."
        rm $PIDFILE
 ;;
  restart|force-reload)
 echo -n "Restarting $DESC: "
 start-stop-daemon $STOP_OPTS
 sleep 1
 start-stop-daemon $START_OPTS
 echo "$NAME."
 ;;
  *)
 N=/etc/init.d/$NAME
 echo "Usage: $N {start|stop|restart|force-reload}" >&2
 exit 1
 ;;
esac

exit 0
Guardaremos esta parte del demonio en /etc/init.d/ y le cambiaremos los permisos a 700. De manera que solo sea root quien pueda leer, escribir y ejecutar el archivo.

También crearemos el archivo pid en /var/run:
#chmod 700 daemonlatch 
#touch /var/run/daemonlatch.pid

Esta parte será la encargada del control; con la cual podremos parar, arrancar o re arrancar el demonio:
/etc/init.d/nombre del demonio /start/stop/restart

Ahora pasaremos a la segunda parte del demonio que llamaremos thekeeper que será la que se encargará de ver el estado de cada llave en el servidor de latch, de manera que si las dos llaves están activadas el archivo o carpeta se podrá leer, modificar,etc. según convengamos, o de lo contrario no se podrá:
#!/bin/bash
cofre=/home/manuel/importante.gpg
applicationId2="571a1Wfq8jnspoxk66pm"
secretkey2="rX2eZoqoBu6P1xWWwHVJNW15ErrlVgRcEqbtARF3"
LATCH2="/home/LATCH/latch-llave2.account"
account2=`grep "^$USER:" $LATCH2 |cut -d: -f2`
logs="/var/log/daemonlatch/daemonlatch.log"
##COMPROBAMOS LLAVE2
if [ -z `echo "$account2"|cut -d: -f2`  ]; then exit 0; fi
URL="/api/0.6/status/$account2"
requestSIgnature+="GET\n"
date2=`date -u '+%Y-%m-%d %H:%M:%S'`
requestSIgnature+="$date2\n\n$URL"
signed=`echo -en "$requestSIgnature" | openssl dgst -sha1 -hmac "$secretkey2" -binary|sed -e 's|.*= \(.*\)|\1|g'`
b64signed=`echo -n "$signed"|base64`
auth_header="Authorization: 11PATHS $applicationId2 $b64signed"
date_header="X-11Paths-Date: $date2"
JSON=`wget -q --no-check-certificate -O - --header "$auth_header" --header "$date_header" "https://latch.elevenpaths.com$URL"`
status2=`echo -e "$JSON" | sed -e 's|.*status":"\(.*\)","name.*|\1|g'`
echo $status2

##COMPROBAMOS LLAVE1

applicationId="JXM2krpxLzNxi41Ru0oe"
secretkey="SeTQQo4OzyJ02T2SB9q6qPAA8lNyWkUcA4NZdNiI"
LATCH="/home/LATCH/latch-llave1.account"
account=`grep "^$USER:" $LATCH |cut -d: -f2`
if [ -z `echo "$account"|cut -d: -f2`  ]; then exit 0; fi
URL="/api/0.6/status/$account"
requestSignature+="GET\n"
date=`date -u '+%Y-%m-%d %H:%M:%S'`
requestSignature+="$date\n\n$URL"
signed=`echo -en "$requestSignature" | openssl dgst -sha1 -hmac "$secretkey" -binary|sed -e 's|.*= \(.*\)|\1|g'`
b64signed=`echo -n "$signed"|base64`
auth_header="Authorization: 11PATHS $applicationId $b64signed"
date_header="X-11Paths-Date: $date"
JSON=`wget -q --no-check-certificate -O - --header "$auth_header" --header "$date_header" "https://latch.elevenpaths.com$URL"`
status=`echo -e "$JSON" | sed -e 's|.*status":"\(.*\)","name.*|\1|g'`
echo $status
if [ "$status" == "on" ] && [ "$status2" == "on" ]; then
date >>$logs
echo -e "cofre abierto " >> $logs
chmod 777 $cofre
elif [ "$status" == "off" ] && [ "$status2" == "off" ]; then
echo -e "cofre cerrado" >> $logs
chmod 000 $cofre
elif [ "$status" == "off" ] && [ "$status2" == "on" ]; then
echo -e "cofre cerrado" >> $logs
chmod 000 $cofre
elif [ "$status" == "on" ] && [ "$status2" == "off" ]; then
echo -e "cofre cerrado" >> $logs
echo 000 $cofre
else 
echo -e "Error de LATCH. Intenta de nuevo\n" >>$logs
echo 000 $cofre
fi

Por último haremos la tercera parte de nuestro demonio que llamaremos daemonkeeper, la colocaremos en el directorio /bin y le daremos permisos 700.

Con esta parte lo que se controlará es el tiempo que pasará entre chequear el estado de las llaves, en este caso será 30 seg..
#!/bin/bash
date >>/var/log/daemonlatch/daemonlatch.log
echo "demonio arrancado" >> /var/log/daemonlatch/daemonlatch.log
while true
do
sleep 30
/bin/thekeeper
done
Una vez creado nuestro demonio vamos a asignarle los niveles de ejecución o Runlevels.

Tenemos varios niveles de ejecución, y cada uno de ellos nos proporciona unas funcionalidades diferentes, y un entorno de trabajo distinto. 

La definición de cada runlevel la encontramos en el fichero /etc/inittab. En mi caso son los siguientes DEBIAN WHEEZY:

# Runlevel 0 is halt.
# Runlevel 1 is single-user.
# Runlevels 2-5 are multi-user.
# Runlevel 6 is reboot.

Para saber en qué nivel de ejecución estamos actualmente podemos utilizar el comando runlevel. Para iniciar o parar un demonio al entrar en un runlevel simplemente tenemos que crear un enlace simbólico en el directorio correspondiente al runlevel en el que queremos iniciar/parar el demonio. Los directorios con los enlaces a los scripts de los demonios son los de /etc/rcX.d/ donde X se corresponde con el número de runlevel. Así, por ejemplo, en el directorio /etc/rc5.d/ tenemos los enlaces a los scripts de los demonios que se iniciarán/pararán al entrar en el runlevel 5. Ahora que ya sabemos dónde hemos de colocar nuestros enlaces ya podemos crearlos. 

Es muy importante el nombre que le damos a los enlaces ya que de él depende si el demonio se inicia o se para y el orden en que se inicia/para. La sintaxis que se sigue en el nombre del enlace es la siguiente: S (para iniciar el demonio apuntado por el enlace) K (para parar el demonio apuntado por el enlace) y luego el orden en que se ejecutará; que puede ir desde 00 hasta 99 (siendo 00 la máxima prioridad). Además puede haber varios con la misma prioridad. 

Bueno al tajo!! Ahora para crear los enlaces simbólicos debemos hacerlo en los runlevels adecuados. Para iniciar en el runlevel 5 (multiusuario gráfico) y 3 (multiusuario) y para pararlo en el runlevel 6 (reinicio) y 0 (apagado). Lo hacemos con el comando ln de la siguiente manera:

ln -s /etc/init.d/daemonlatch /etc/rc5.d/S30daemonlatch
ln -s /etc/init.d/daemonlatch /etc/rc3.d/S30daemonlatch
ln -s /etc/init.d/daemonlatch /etc/rc6.d/K05daemonlatch
ln -s /etc/init.d/daemonlatch /etc/rc0.d/K05daemonlatch


Ya tenemos listo nuestro demonio!!!

Tan solo nos queda probarlo. Para ello simularemos que uno de los usuarios crea un archivo cifrado que se llamará 'importante' en su /home (igual lo podemos hacer con una carpeta)
$touch /home/manuel/importante
$gpg -c /home/manuel/importante


$rm /home/importante

Esto creará importante.gpg del cual ambos usuarios tendrán la clave.

Arrancamos el demonio:

#/etc/ini.d/daemonlatch start

Cada cierto tiempo (el que hayamos estimado en el archivo daemonkeeper) nuestro demonio conectará con el servidor de LATCH consultando el estado de las llaves...

En cuanto uno de los dos usuarios que tienen las llaves en su poder bloquee su llave en LATCH, el archivo deja de estar disponible para nadie... y no estará accesible hasta que ambos lo decidan...

Con esto hemos conseguido que estos usuarios tengan un archivo mancomunado y pleno control en el acceso, les hemos dado una capa nueva de protección...

Podríamos hacer esto más complejo y elegante, como por ejemplo llevar un sistema de log mas pensado, hacer un fichero de configuración para el demonio y que recoja las variables de él, etc, etc....

Un saludo y sed buenos...

2 comentarios :

  1. otra entrada genial Manuel! eso sí, pronto va a tocar abrazar systemd :P

    ResponderEliminar
  2. XD sip, a lo visto a saltao escarcha en la decisión...creo que funciona bastante bien Fedora lo implementó hace tiempo.....a Canonical no le ha hecho puta la gracia......esperemos que sea para bien.....

    ResponderEliminar