32 – Acceso automático con certificados SSH

Te doy la bienvenida al episodio 32 de deployandome, el podcast de tecnología para sysadmins y devops. Soy Rodolfo Pilas y estoy grabando el 28 de agosto de 2018.

El otro día estaba revisando viejos archivos y me encuentro una carpeta con material de un taller que dicté en un evento que se hacía anualmente llamado TechMeetup y que se realizó en el complejo de conferencias de la Torre de las Comunicaciones aquí en Montevideo, en el año 2014.

El taller se llamó Administración de llaves SSH para aplicaciones y ese material está compartido en mi blog pilas.guru

En el taller presentaba el problema que nace cuando empezamos a utilizar aplicaciones y a automatizar los accesos con certificados SSH, ya que quitamos la passphrase al certificado, precisamente para que las conexiones se puedan establecer automáticamente y muchas veces para acceder como root en los servidores de destino.

Supongo que por la insistencia que le pongo a OpenSSH en distintas ediciones de este podcast te habrás dado cuenta que lo considero algo tan fundamental para gestionar una infraestructura como lo es el servicio DNS para el funcionamiento de Internet.

Y por eso, en esta edición de deployando.me, te voy a contar cómo hago mis configuraciones para tener certificados SSH sin pasphrase, que habilitan a mis aplicaciones a conectarse como root, sin que ello signifique un riesgo de seguridad.


Sabemos que el par de certificados SSH tiene su llave privada y su llave pública.

Sobre la llave pública podemos tener un nivel de seguridad cero, nada. Podemos copiar la llave publica a cualquier servidor, publicarla en un web, ponerla en nuestro perfil de twitter, es decir nada, la llave pública que la tenga cualquiera, no hay problema con ello.

Pero la llave privada es otra cosa, por eso su nombre; se tiene que proteger ya que es la que permite colocar mi firma digital, es decir, la llave que me representa, que me abrirá las puertas. Sobre la llave privada tengo dos niveles de seguridad, un primer nivel es el propio archivo, lo que en seguridad se llama "lo que tengo", sobre el archivo trato de tenerlo solo yo y pondré cuidado en que esto se mantenga así. Un segundo nivel de seguridad es la passphrase que me permite utilizar la llave pública, lo que en seguridad se llama "lo que sé" y esta passphrase solo la se yo y si por algun motivo tuve que compartirla o escribirla en un ambiente poco seguro, siempre puedo cambiarla en cualquier momento.

Ahora fíjate que cuando esto lo llevo a una aplicación automatizada, que digamos corre en el crontab, y debe acceder como root a un servidor lo que tengo que hacer es quitarle la passphrase a la llave privada que le dará el acceso, ya que no estaré para escribirla, pues obviamente es automatizada.

¿Qué pasó ahi con la seguridad? Ya no tengo el nivel de seguridad de "lo que se", es decir la passphrase, sino que solo queda la seguridad de "lo que tengo", en este caso el archivo de la llave privada. Pero, fíjate que la aplicación automatizada no va a estar corriendo en mi notebook, donde digamos yo podría cuidar que nadie haga una copia del archivo de la llave privada, no!, esa llave privada sin passphrase va a estar alojada en donde corre la aplicación que estoy automatizando, que será el servidor de respaldo, el servidor de sincronización, el servidor del agente de monitoreo o lo que sea que estoy automatizando.

Entonces en resumen estoy dejando un archivo en algún lugar de mi infraestructura que permite a quién lo tenga conectarse a un conjunto de mis servidores y, si esa conexión se hace como root, no te tengo que explicar el "poder" de ese archivo.

Pero ahí es que debemos utilizar lo que en la página man del SSHD aparece cuando se describe el formato del archivo authorized_keys como las "opciones" que se pueden configurar en los certificados públicos que tenemos inscriptos. Estas opciones limitarán el alcance o los servicios que OpenSSH dará a las conexiones.

Mediante estas opciones podemos configurar para que, aunque alguien mal intencionado tenga el certificado privado sin passphrase de la aplicación, no le sirva para nada, o por lo menos, no pueda hacer nada más que lo que hace la aplicación automatizada que lo usa. Es decir, si la aplicación respalda la base de datos, a este mal intencionado no le servirá, por ejemplo, para crear usuarios y solo podrá respaldar la base de datos. Y esto, como te digo, si es que el certificado público le sirve para algo.

--

La idea es que dentro del authorized_keys copiamos el certificado público, uno por renglón, pero delante en el mismo renglón podemos ponerle estas opciones que limitan cosas.

Por ejemplo, podemos ponerle from= y la IP del servidor desde donde aceptamos la conexión, tendrá que llegar con esa IP o jamás el servidor OpenSSH le otorgará el acceso.

Otra opción bastante útil es no-pty que evitará otorgarle una terminal interactiva a quién se conecta. Si es una aplicación no necesita una terminal, sino que va a estar ejecutando un grupo de comandos. O si por ejemplo, solo queremos habilitar acceso sFTP, esta sería la opción que le configura el acceso al cliente sftp pero no de shell al cliente ssh.

Asi que sumando estas dos opciones en un certificado público haremos que solo sirva si te conectas de una determinada IP y solo puedas ejecutar comandos y no obtener un shell. ¿Entender cómo funciona?

Y hay más..

Con la opción no-port-forwarding evitaremos que utilice la conexión como puente para acceder a un servicio de otra.

Con no-x11-forwarding evitaremos que ejecute aplicaciones gráficas eventualmente instaladas en mi máquina que se despliegan gráficamente en la de este muchacho mal intencionado que les vengo diciendo que se copió el certificado sin passphrase.

Y fíjate que justamente para estas dos funcionalidades de ssh no necesita tener un shell, o sea que deberíamos sumarlas a las opciones no-pty y from que te decía antes.

Hay otras opciones que te sugiero consultar en el man de sshd pero podemos simplemente utilizar la opción restrict que es un comodín que engloba todas las opciones restrictivas, presentes y futuras que se le puedan poner a un certificado, así podrás asegurarte que el acceso está limitado aunque actualices OpenSSH.

Pero hay una opción más que la llamo la 'última' opción, y es la opción command= donde puedes poner el comando que se ejecutará al usar el certificado y será ese comando si o si para lo que servirá el certificado.

Fíjate que command=/usr/bin/uptime en un certificado público, cuando alguien acceda por ssh ejecutará uptime y saldrá. No importa si del otro lado quieren ejecutar otro comando, conectando por ejemplo con ssh whoami, lo que verá su terminal es la ejecución de uptime.

Por eso, con las opciones from restrict y command en los certificados que tenemos los archivos authorized_keys podemos empezar a dejar certificados privados sin passphrase en manos de nuestras aplicaciones con un muy razonable nivel de seguridad.


Soy Rodolfo Pilas, en twitter me puedes seguir por @pilasguru y te dejo un saludo. Confío que este podcast te haya aportado para mejorar y, como siempre, espero tus inquietudes y sugerencias comentando en deployando.me

Hasta la próxima edición.