¿Cómo funciona la autentificación mediante clave privada?

  • Time to read 6 minutes
Autentificación SSH clave privada

Probablemente tú, avezado ingeniero de sistemas, tengas este tema dominado. Probablemente este artículo no sea para ti. Probablemente, si pasas de este punto, me tires los ratones y los teclados a la cabeza en señal de protesta por las lagunas y las inexactitudes técnicas.

Este artículo es para todas esas personas que se enfrentan a las sistemas de autentificación por clave pública/privada por primera (o segunda, o tercera) vez. Que están hartos de buscar información sobre claves y certificados, y únicamente se encuentran con artículos incomprensibles que se centran en las maravillas y virguerías que se pueden conseguir con las miles de combinaciones y configuraciones posibles.

¿Qué es la autentificación mediante clave privada?

Dicho de una forma muy genérica y poco técnica, se trata un sistema que permite la autentificación de usuarios mediante la aplicación de determinados cálculos matemáticos sobre pares de claves públicas y privadas. No se ha entendido nada, ¿verdad? Veamos de forma un poco más detenida de qué va esto:

Yo, como usuario que se pretende autentificar en un sistema remoto, deberé generar mi par de clave pública/privada. Esto se lleva a cabo mediante herramientas especiales que más tarde veremos. Cada clave se guarda en un fichero:

  • Clave privada: se almacena por lo general en un fichero llamado id_rsa. Esta clave, sirve para codificar y, lo más importante, decodificar la información. Esta clave nunca se deberá compartir con nadie, puesto que es la clave que verifica que efectivamente somos quien decimos
  • Clave pública: se almacena por lo general en un fichero llamado id_rsa.pub. Esta clave sirve únicamente para codificar información. Esta clave es la que deberemos compartir con los sistemas con los que nos queramos conectar

Pero... espera un momento... ¿la clave que decodifica es la que yo me quedo? ¿No tendría más sentido que les dé a ellos la clave que decodifica, y yo les mande un mensaje codificado con mi clave, para que ellos lo decodifiquen también con mi clave? Pues... no. Y lo vas a entender en seguida.

¿Cómo funciona la autentificación mediante intercambio de claves?

El sistema de intercambio de claves funciona como un sistema de desafío y respuesta. Quizás lo veas más claro con este esquema:

Y si te lo explico, lo verás más claro aún probablemente. Bien, partamos de una situación en la que yo, como usuario Ramon, me quiero conectar al servidor ramon_server desde mi ordenador ramon_local:

  • En ramon_local, y más concretamente en el almacén de claves dentro de mi cuenta de usuario Ramon, tengo generado un par de claves:
    • La clave pública es la que empieza por r9lve....
    • La clave privada es la que empieza por dOJPde...
  • En ramon_server, tengo también una cuenta de usuario llamada Ramon, en cuyo almacén de claves hay una sección de claves autorizadas. Entre ellas, figura la clave pública que yo tengo en mi almacén local (que recordemos, empieza por r9lve....). En este listado de claves autorizadas puede estar sólo esta clave, o puede haber más claves. Es decir, se pueden añadir varias claves, que me permitan conectarme desde varios equipos.
  • Cuando yo desde mi ordenador ramon_local quiero acceder a ramon_server, ocurre una conversación similar a la siguiente:
    1. Me presento: ¡Hola, ramon_server! Soy el usuario Ramon, y me quiero conectar contigo. En mi perfil de usuario tengo la clave pública (r9lve...)
    2. Te desafío: ¡Hola, Ramon! Perfecto. Tu clave pública está en mi lista de claves autorizadas para mi usuario Ramon, así que eres alguien de confianza. Voy a usar esa clave para codificar un mensaje y mandártelo. Si quieres acceder, tendrás que devolvérmelo descifrado.
    3. Mi respuesta: aquí es donde está el meollo de la cuestión. La clave pública únicamente sirve para codificar; la clave privada sirve para codificar, pero también para decodificar mensajes. Puesto que yo soy el único que posee la clave privada, yo seré el único que puede decodificar el mensaje que ramon_server me ha puesto como reto. Una vez decodificado el mensaje con la clave privada, se lo devuelvo al servidor: Toma el mensaje decodificado.
    4. Puedes acceder: tras comprobar que efectivamente ramon_local ha podido decodificar el mensaje de forma correcta, se da la autentificación como correcta: Perfecto, puedes acceder.

... Y esa es la magia. Ahora, ¿qué?

Tradicionalmente, la única forma de autentificación en la conexión a sistemas remotos o al propio sistema local, ha sido un desafío mediante usuario y contraseña. Esto tiene infinidad de inconvenientes bien conocidos por todos: si la contraseña es fácil, también es fácil de reventar; si es difícil, eso también dificulta recordarla y obliga a muchos usuarios a apuntársela en un papel, haciéndola también difícil de reventar; políticas de renovación, complejidad mínima ("necesita una mayúscula, una minúscula, un carácter especial y 3 mechones de pelo de caballo salvaje"; etc, etc.

Un par de claves pública y privada dispone de la suficiente complejidad como para evitar que un atacante pueda explotar la clave. Reventar por fuerza bruta una clave generada mediante algoritmo RSA-2048 llevaría varios años con la tecnología actual. Como además estas claves se pueden preconfigurar en los sistemas origen y destino, se vuelven muy eficaces para la autentificación entre servidores y procesos sin intervención del usuario.

¿Cómo configurar un sistema de intercambio de claves para conectarme con un servidor remoto mediante ssh?

Los pasos que voy a indicar a continuación, permiten el conexionado de un ordenador Windows con un servidor Linux mediante ssh. En este caso, las versiones son Windows 10 y Linux Debian, aunque los pasos son extrapolables a un ordenador local con Linux.

El primer paso para configurar una conexión mediante intercambio de claves, es la creación local de un par de claves pública/privada mediante el comando ssh-keygen.

Esto inicia un breve asistente que nos pedirá los siguientes datos:

  • Enter file in which to save the key: indica el nombre del fichero que contendrá nuestra clave privada. Por defecto se almacenará en el fichero id_rsa, dentro de la carpeta .ssh de nuestro perfil de usuario. En Windows será c:\users\{nombre_usuario}\.ssh. En Linux será ~/.ssh.
  • Enter passphrase: se puede proteger la clave privada mediante una contraseña, lo cual aporta un grado extra de seguridad. De esta forma, cuando se vaya a utilizar la clave, nos pedirá esta contraseña. Si se indica este dato, pedirá confirmación. Si se deja el dato vacío, se generará la clave privada sin protección.

El proceso depositará el par de claves en la ubicación que le hayamos indicado, o en la ruta por defecto. Si no hemos tocado nada, dentro de nuestra carpeta de usuario nos encontraremos la carpeta .ssh que contendrá 2 ficheros: id_rsa e id_rsa.pub.

El siguiente paso, es el copiado del fichero de clave pública al servidor remoto. Imaginemos que el servidor remoto es 192.168.100.100. Existen varios métodos para realizar este copiado. Aquí voy a indicar el más universal, que puede ser utilizado en sistemas Windows y Linux. La sintaxis del comando a utilizar es:

scp <fichero> <usuario>@<servidor_remoto>:<carpeta>

En el ejemplo de más abajo, copiamos el fichero .\id_rsa.pub en la carpeta home (es el valor por defecto) del usuario ramon del servidor 192.168.100.100.

Posteriormente, conectaremos con el servidor remoto mediante el comando con sintaxis:

ssh <usuario>@<servidor_remoto>

Esto nos conectará a la carpeta home de servidor_remoto para usuario. En el caso del ejemplo de más abajo, conectará con el servidor 192.168.100.100 mediante el usuario ramon, y aterrizará en la carpeta home del mismo. Si hacemos un ls, veremos que el fichero id_rsa.pub se ha copiado correctamente.

Los siguientes comandos, crean la carpeta .ssh, asigna los permisos correctos, y añade la clave contenida en el fichero id_rsa.pub al fichero authorized_keys. Todos estos comandos se pueden montar en una única línea:

mkdir -p ~/.ssh && touch ~/.ssh/authorized_keys && chmod -R go= ~/.ssh && cat id_rsa.pub >> ~/.ssh/authorized_keys

Bien. Hasta este momento hemos creado nuestro par de claves y hemos subido la clave pública al servidor remoto. Posteriormente, hemos añadido la clave al fichero de claves autorizadas. Por lo tanto, nuestro servidor ya nos conoce.

Si nos volvemos a conectar al servidor, únicamente nos pedirá la contraseña de desbloqueo de la clave privada. En caso de que no hayamos configurado una contraseña para dicha clave, el acceso será inmediato. Pero, a pesar de lo que pueda parecer por esa inmediatez, el acceso es completamente seguro, puesto que todo el mecanismo de autentificación se hace fuera de nuestra vista.

Y un último detalle de seguridad

Si queremos proteger completamente nuestro servidor remoto, lo ideal sería desactivar el uso de contraseñas para el usuario que tenemos protegido mediante clave privada. Como hemos comprobado, la protección que nos proporciona el intercambio de claves es prácticamente invulnerable, hasta el punto de que mantener el uso de contraseñas para el usuario puede considerarse un problema de seguridad en ciertos entornos.

Si queremos evitar que los usuarios puedan iniciar sesión remota mediante una contraseña estándar, deberemos seguir los pasos que indico a continuación:

  • Editar el fichero de configuración global de ssh, mediante el siguiente comando:
sudo nano /etc/ssh/sshd_config
  • Modificamos la línea PasswordAuthentication y le indicamos no
...
PasswordAuthentication no
...
  • Guardamos el fichero y reiniciamos el servicio ssh mediante el comando:
sudo systemctl restart ssh

Conclusión

Cuando trabajamos con servidores remotos, como por ejemplo cuando contratamos un VPS, debemos intentar implementar un nivel de seguridad que cumpla unos requisitos mínimos, que eviten que usuarios malintencionados puedan acceder a nuestro sistema y por ende a la información que hay en él, o que puedan introducir código malicioso. La autentificación mediante clave privada es una buena barrera que aleja las posibilidades de un ataque que intente averiguar nuestras credenciales por fuerza bruta.