03 febrero 2013

Asegurando el SSH en la RaspberryPI (o cualquier Linux)

Primero me quiero disculpar por no haber publicado ninguna entrada la semana anterior, me he encontrado muy ocupado trabajando en el proyecto de un amigo.

Si son curiosos les recomiendo visitar http://www.aciseaprende.com/ este es un nuevo centro de entrenamiento enfocado a la enseñanza de tecnologías web. Fué desarrollado en aproximadamente 2 semanas usando CakePHP, aún faltan algunos detalles pero el esqueleto básico está listo ya. Otro día les escribo un poquito más sobre CakePHP y el desarrollo de aplicaciones con frameworks y patrones de diseño.

El día de hoy vamos a hablar de como utilizar autenticación de pares de llaves publicas/privadas con SSH y deshabilitar la autenticación vía password. Esta entrada la escribo en base a la sugerencia que me hizo Gonzalo en la entrada del "Muro de la Vergüenza" acerca de como tengo "asegurada" mi Raspberry PI.

¿Por qué SSH?


Para los que no están familiarizados con el término SSH, este es el acrónimo del protocolo "Secure SHell" o "Consola Segura", este es el protocolo más usado y extendido en el mundo "Unix" que se utiliza para conectarse y administrar sistemas vía consola de comandos.

La consola de comandos es una de las maneras más eficientes para monitorear sistemas remotamente, hace algunos años el protocolo más extendido era "telnet", su utilidad era prácticamente la misma de SSH, pero tenía un grandísimo problema y era que todos los comandos se envíaban en "texto plano".

Esto era un problema porque cualquiera podía monitorear la red buscando conexiones telnet y averiguar cosas como los passwords de nuestras cuentas, obviamente telnet nació en los tiempos que la red no era tan peligrosa y no era necesario asegurar tanto nuestras conexiones.

¿Cómo funciona SSH?


A diferencia de telnet, SSH establece una conexión criptográficamente segura, esto es, que todos los datos que se transmiten a través de esta conexión van cifrados de tal manera que un tercero aunque logre monitorear los datos que se envían no podrá descifrarlos a menos que conozca la llave utilizada para cifrar la conexión.

Antes de iniciar la conexión SSH autentifica el usuario a conetarse, si el proceso de autenticación es positivo, entonces establece la conexión segura donde se pueden enviar y recibir comandos.

SSH soporta dos modos de autenticación, el password de toda la vida y la autenticación por pares de llaves publica/privada.

El problema de un password es que resulta siempre muy difícil el generar passwords seguros y que a su vez sean sencillos de recordar, la gente termina dejandolos accesibles de una manera u otra.

Autenticación con llave publica/privada


Para no complicarles mucho las cosas, digamos que este tipo de autenticación requiere de dos llaves. Si yo por ejemplo te comparto mi llave pública tu podrás entonces cifrar un mensaje que solo yo podré descifrar con mi llave privada. De igual manera si yo cifro un mensaje con mi llave privada, tu podrás descifrar el mensaje con la llave pública con lo que efectivamente podrás garantizar que el mensaje proviene de mi.

Obviamente para que este esquema de cifrado funcione de manera efectiva, la llave privada debe mantenerse privada y esta es justa mente la primera regla de los sistemas de autenticación con pares de llaves.

La forma en que SSH "autentica" la conexión es un poco complicada y no pienso explicarla acá, pero vale la pena decir que es muy buena práctica deshabilitar la autenticación por password y manejar nuestras consolas SSH a través de nuestros pares de llaves.

Luego de haber completado esta larga introducción, comencemos a trabajar la configuración de nuestra Raspberry PI.

Habilitando el servicio SSH


Nota: Esta entrada asume que están utilizando Raspbian y el usuario por defecto "pi" con el password "raspberry".

En la Raspberry PI habilitar el servicio SSH es tan fácil como ejecutar los siguientes comandos:

pi@raspberrypi ~ $ sudo update-rc.d ssh enable
update-rc.d: using dependency based boot sequencing

Y luego ejecutar:
pi@raspberrypi ~ $ sudo service ssh start
[ ok ] Starting OpenBSD Secure Shell server: sshd.

Un pequeño mensaje nos indicará que el servidor ha sido iniciado de manera exitosa.

Para conectarnos a nuestra Raspberry PI desde otro equipo solo ejecutamos el comando:

$ ssh pi@<direccion de nuestra RasPI>

Si es primera vez que nos conectamos nos aparecerá un mensaje como el siguiente:

The authenticity of host 'raspi.teubi.co (190.87.32.10)' can't be established.
ECDSA key fingerprint is 75:a2:ef:5e:19:b4:0f:44:4e:fe:f8:f3:be:18:8c:25.
Are you sure you want to continue connecting (yes/no)?

Cada vez que nos conectemos a un servidor nuevo nos aparecerá un mensaje como este, es buena práctica siempre verificar con un tercero la autenticidad del servidor destino la "huella digital" del servidor. Sin embargo asumo para este ejemplo que tenemos acceso físico a la RaspberryPI y sabemos que la IP a la que nos estamos conectando es la de nuestra RasPI. Por ello simplemente respondemos "yes".

Ingresamos nuestro password y nos mostrará una consola como si estuvieramos conectados localmente.

Generando el par de llaves


Lo primero es generar nuestro par de llaves desde la maquina por la cual nos vamos a conectar a nuestra Raspberry.

Importante: No generen esta llave desde la propia Raspberry ya que se supone que el servidor destino al cual nos conectaremos no conoce nada más de nosotros que nuestra llave pública.

Para generar nuestras llaves ejecutamos el siguiente comando:
test@v131:~$ ssh-keygen -t rsa

Este comando genera un par de llaves de tipo "RSA", lo primero que hará este comando es preguntarnos la ubicación de la llave. En mi caso mi computadora se llama "v131" y el usuario "test", la llave por defecto se guarda en ~/.ssh/id_rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/test/.ssh/id_rsa):

Si es la primera llave que creamos es seguro que simplemente escribamos [Entrar], si ya habíamos creado una llave anteriormente, lo más seguro es hacer una copia de respaldo del directorio ~/.ssh por si algo llegara a salir mal. Nos preguntará por una "frase clave". Pueden dejarla en blanco pero no lo recomiendo.
Created directory '/home/test/.ssh'.
Enter passphrase (empty for no passphrase):

Una frase clave es un conjunto de palabras que en teoría debería ser "fácil de recordar" y que solo nosotros conozcamos. Pueden tomar su libro favorito y elegir una frase que les guste, pueden tomar varias palabras que recuerden facil y formar una frase, la frase clave es como password pero debería de ser muchísimo más fácil de recordar que un monton de letras y números aleatorios.

Nos preguntará la frase clave por segunda vez luego y nos mostrará un mensaje confirmando la creación de la llave.
Enter same passphrase again: 
Your identification has been saved in /home/test/.ssh/id_rsa.
Your public key has been saved in /home/test/.ssh/id_rsa.pub.
The key fingerprint is:
77:e4:ec:c2:08:1f:57:f6:bb:14:f4:7a:a1:ec:99:23 test@v131
The key's randomart image is:
+--[ RSA 2048]----+
|                 |
|                 |
|            + .  |
|           * o . |
|      . S o + o..|
|       o * o. .+.|
|        o o .o+ .|
|           E.ooo |
|            .+o  |
+-----------------+

De este mensaje lo que más nos interesa es lo siguiente:
Your identification has been saved in /home/test/.ssh/id_rsa

Esta es la ubicación de la llave privada, procuren mantener seguro este archivo, la frase clave es solo un "nivel extra" de seguridad en caso de que alguien tenga acceso físico a su cuenta y copie su llave privada. Nunca pero nunca coloquen su llave privada en algun lugar de acceso público.

La siguiente línea interesante es la siguiente:
Your public key has been saved in /home/test/.ssh/id_rsa.pub.

Esta es nuestra llave pública, esta llave es la que copiaremos a nuestra Raspberry PI para poder conectarnos.

El resto de información como el "fingerprint" de la llave y el "randomart" solo son formas fáciles de identificar nuestra llave si quisieramos que un tercero validara su origen, por ejemplo si tuvieramos que llamarle a alguien por telefono y decirle: La huella digital de mi llave es "77:e4:ec:c2:08:1f:57:f6...".

Copiando la llave pública a nuestra Raspberry PI


Asumiendo que ya iniciaron el servicio SSH esta parte rfesulta muy sencilla, para copiar la llave podemos utilizar otro comando llamado scp o "Secure CoPy". Podemos ejecutar lo siguiente para copiar nuestra llave pública a nuestra Raspberry PI.

test@v131:~$ scp .ssh/id_rsa.pub pi@<dirección de su RasPI>:/home/pi

Ingresamos nuestro password "raspberry" y un mensaje nos confirmará que la llave ha sido copiada exitosamente:
id_rsa.pub                                                                                          100%  391     0.4KB/s   00:00 

Ahora podemos iniciar sesión vía SSH en nuestra Raspberry usando el comando "ssh":
test@v131:~$ ssh pi@<dirección de nuestra RasPI>

Primero verificamos que exista un directorio llamado .ssh haciendo uso del comando "ls". Si no existiera nos aparecerá el siguiente mensaje:
pi@raspberrypi ~ $ ls .ssa
ls: cannot access .ssa: No such file or directory

Si este es el caso creamos nuestro directorio con el comando "mkdir":
pi@raspberrypi ~ $ mkdir .ssh

Luego copiamos nuestra llave pública al archivo de llaves autorizadas:
pi@raspberrypi ~ $cat id_rsa.pub >> .ssh/authorized_keys

Utilizamos la redirección ">>" para copiar nuestra llave al final del archivo authorized_keys, si la cuenta fuera compartida con alguien más por ejemplo no quisieramos eliminar el acceso de esta otra persona sobreescribiendo el archivo de llaves autorizadas.

Y listo, ahora podemos conectarnos a nuestra raspberry PI usando nuestro par de llaves pública/privada. 

Sin embargo hasta este punto aún se puede acceder a la RasPI por medio de un password.

Una forma abreviada...


Alternativamente, José nos regala un pequeño comando para agregar nuestra llave publica a las llaves autorizadas directamente con las herramientas de SSH. Para copiar la llave pública ejecutamos el siguiente comando:

$ ssh-copy-id -i .ssh/id_rsa.pub pi@<Direccion de su RasPI>


Deshabilitado los logins con password


Siempre desde nuestra sesión ssh vamos a editar el archivo /etc/ssh/sshd_config como root:
pi@raspberrypi ~ $ sudo nano /etc/ssh/sshd_config

Dentro de ese archivo verificamos que las siguientes lineas aparescan como "yes":
RSAAuthentication yes
PubkeyAuthentication yes

Y para deshabilitar los inicios de sesion con password, buscamos la siguiente línea y cambiamos "PasswordAuthentication" a no:
# Change to no to disable tunnelled clear text passwords
PasswordAuthentication no

En nano apretamos Ctrl+X para salir y luego seleccionamos guardar los cambios.

Nota: El siguiente comando reiniciara nuestra sesión SSH, antes de ejecutarlo verifiquen que hayan copiado su llave pública al directorio ssh en el archivo "authorized_keys". Luego de esto no podrán acceder vía ssh con el password "raspberry" por lo que si no han seguido bien las instrucciones tendrán que conectarse físicamente a la raspberry para repetir el procedimiento.

Reiniciamos el servicio SSH con el siguiente comando:

pi@raspberrypi ~ $ sudo service ssh restart
Connection to raspi.teubi.co closed. 

Ahora nos conectamos a nuestra Raspberry PI desde la maquina remota con ssh utilizando el mismo comando, nos preguntará la "frase clave" del inicio, la escribimos ahora:

test@v131:~$ ssh pi@raspi.teubi.co
Enter passphrase for key '/home/test/.ssh/id_rsa':

Y... ¡¡Listo!! Si todo sale bien nos mostrará la consola de comandos de nuestra RaspberryPI:
Linux raspberrypi 3.2.27+ #250 PREEMPT Thu Oct 18 19:03:02 BST 2012 armv6l

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sun Feb  3 18:36:10 2013 from 192.168.0.1
pi@raspberrypi ~ $  

¿Que pasa ahora si trato de entrar con otro usuario que no posee mi llave privada? Pues simple, el servidor SSH deniega inmediatemente la conexión sin siquiera preguntar por un password o algo similar, por ejemplo si intento acceder como el usuario "root" desde la misma máquina remota:
root@v131:~# ssh pi@raspi.teubi.co
Warning: Permanently added the ECDSA host key for IP address '190.87.32.10' to the list of known hosts.
Permission denied (publickey).

Les cuento también que pueden usar la llave pública que hemos creado en esta ocasión para identificarse en otros servicios como Amazon Web Services o GitHub.

Algo más...


Si van a utilizar este modo de autenticación, cuiden celosamente sus llaves privadas. 

Si borran su llave privada o la pierden no hay forma de recuperarla. Hagan una copia de respaldo de su llave en una USB o CDROM y guárdenla en un lugar seguro al que solo ustedes tengan acceso.

OK si ustedes no manejan información confidencial o crítica tal vez no sea necesario ser tan paranóicos y meter la copia de respaldo en una caja fuerte. Pero si es recomendable que tengan un backup en algun lugar donde puedan rescatar las llaves de autenticación en caso su computadora falle o borren por accidente el directorio ".ssh" (Esto último ha pasado hasta en las mejores familias). 

Concluyendo


En Internet van a encontrar muchísimos artículos que hablan de "autenticación sin password" utilizando pares de llaves públicas/privadas. Si bien la autenticación con pares de llaves es "mas segura" vender esto como algo que podemos hacer "sin password" es fomentar "malas prácticas".

Una práctica tan mala, que hace unos días unos usuarios de github terminaron colocando en línea sus llaves privadas de autenticación al agregarlas erróneamente a un repositorio público.

La idea de utilizar una "frase clave" es que aunque alguna persona tenga acceso físico a la computadora donde tenemos la llave privada, esta no pueda ser utilizada. Como el ejemplo que puse antes, "root" puede copiar mi llave privada de la computadora donde me conecto, pero mientras yo no le proporcione mi frase clave el no tendrá manera de conectarse a la RasPI.

En el muro de la vergüenza pueden ver una serie de intentos fallidos de acceder a la RasPI. Recuerden que Internet es un lugar peligroso, ni las humildes RasPI se salvan de los intentos de acceso por personas maliciosas. Así que el uso de pares de llaves publicas/privadas nos da un poquito de confianza extra de que al menos "al que quiera entrar... le va a costar".

No habiendo nada más que decir por ahora... ¡¡¡Hasta la próxima!!!


Fuentes y referencias:

2 comentarios:

Jose David Calderon Serrano dijo...

Que chevere está el post :)

En la seción de "Copiando la llave pública a nuestra Raspberry PI" se puede agilizar desde el cliente con el comando:

ssh-copy-id -i .ssh/id_rsa.pub pi@

así se crea automáticamente el authorized_keys con la entrada respectiva.

Jesús Alberto Pinedo dijo...

Muchas gracias por tu entrada y por la anterior. Yo tengo desde hace poco la pi conectada al router y es increible la cantidad de gente que se intenta conectar a ella!!!

Saludos,