Hardening de un servidor ssh. Parte 2.

En la entrada anterior, vimos cómo reducir la información expuesta del servicio ssh. En esta entrada, vamos a continuar fortificando nuestro servicio de manera que sea más seguro de cara a exponerlo al exterior.

Ya hemos visto que la configuración de nuestro servicio ssh se hace a través de una serie de parámetros que vienen en el archivo /etc/ssh/sshd_config. En nuestro caso, que lo estábamos haciendo a través de docker, vamos a editar el fichero que habíamos recuperado del contenedor y que teníamos en nuestra carpeta config.

Por supuesto, todas estas modificaciones que estamos haciendo son igual de válidas si lo hacemos tanto sobre un servidor normal como en un servidor virtualizado, salvo que las modificaciones las haremos directamente sobre el fichero /etc/ssh/sshd_config y no tendremos que modificar ningún Dockerfile 😉

Por defecto, el servicio ssh se levanta en el puerto 22. Una de las cosas que podemos hacer para evitar ataques automáticos a este puerto, es cambiarlo para que nuestro servicio se levante en un puerto distinto.

Por defecto viene comentado el puerto, como vemos en la imagen anterior, pero nosotros podemos descomentar esta línea y poner el puerto que deseemos.

Y para exponer el puerto en nuestro contenedor Docker, también debemos cambiar el fichero Dockerfile.

EXPOSE 8022

A la hora de levantar nuestro contenedor, ahora debemos hacerlo mapeando el puerto 8022, que es donde hemos configurado el puerto ssh.

$ docker run -d --name ssh-server -p 8022:8022 ssh-server

Y por tanto, para conectarnos a él, debemos indicar el puerto, ya que no estamos usando el puerto 22 por defecto.

$ ssh -i my_key root@localhost -p8022

Otro parámetro muy interesante es el parámetro PermitRootLogin. Por defecto, el valor de este parámetro si no indicamos nada es “without-password” (o “prohibit-password” en versiones más modernas, y en el caso de Docker, este valor venía a yes, ya que es el único usuario). Este valor impide que se alguien se pueda conectar como usuario root haciendo uso de una contraseña, lo cual evita que se haga un ataque por fuerza bruta hacia ese usuario. Pero sí que permite el acceso mediante claves RSA (tal y como lo hemos estado haciendo hasta ahora, aunque también podríamos haber cambiado la contraseña de root y acceder de esa manera).

De cara a mejorar la seguridad, la mejor opción es no permitir que nadie se pueda conectar mediante el usuario root. Lo que haríamos en tal caso sería conectarnos con cualquier otro usuario con permisos restringidos y las tareas administrativas las podríamos hacer o bien cambiando al usuario root o bien haciendo uso de sudo (para la imagen Docker, tendríamos que añadir «RUN yum install -y sudo», pero no tiene mucho sentido dentro de un contenedor, ya que lo ideal es crear la imagen con la configuración que queramos).

Para impedir que nos conectemos como usuario root tendremos que poner este parámetro a no.

Pero claro, hasta ahora, el único usuario que teníamos en nuestro contenedor Docker era el usuario root, por lo que si intentamos acceder ahora por ssh, nos va a resultar imposible.

Bueno, de momento hemos conseguido lo que buscábamos, que no podamos conectarnos por ssh mediante el usuario root.

Lo que vamos a hacer ahora es crear un nuevo usuario en nuestra imagen Docker para poder después conectarnos al contenedor vía ssh con dicho usuario.

Vamos a realizar una serie de cambios en el fichero Dockerfile. Lo primero será crear un nuevo usuario.

RUN adduser myuser

También modificaremos las líneas donde se añade la clave pública para, en lugar de añadírsela al usuario root, se la añadamos al usuario myuser.

RUN mkdir /home/myuser/.ssh

COPY my_key.pub /home/myuser/.ssh/authorized_keys

RUN chmod -R 700 /home/myuser/.ssh \
&& chown -R myuser:myuser /home/myuser/.ssh

Una vez que hemos realizado estos cambios, volvemos a generar la imagen Docker y levantamos el contenedor. Y ahora ya podremos conectarnos mediante el usuario myuser.

$ ssh -i my_key myuser@localhost -p8022

Perfecto, ya tenemos nuestro contenedor algo más seguro de manera que solo nos podemos conectar con nuestro usuario.

Otras dos directivas que nos pueden ayudar a fortificar nuestro servicio son AllowUsers y DenyUsers. Por defecto, estos parámetros permiten a todos los usuarios y no deniegan el acceso a ninguno. En primer lugar, se comprueba la directiva de DenyUsers y en segundo lugar la de AllowUsers. Aquí también se puede indicar el host desde el que se pueden conectar o los host que se pueden denegar. Aunque no lo vamos a necesitar para nuestro contenedor Docker, es interesante saber cómo funciona por si tuviéramos más de un usuario y solo quisiéramos permitir acceso a un servicio ssh a un determinado usuario. Por ejemplo, si quisiéramos únicamente permitir el acceso por ssh al usuario myuser, añadiríamos la siguiente línea al fichero sshd_config.

AllowUsers myuser

Otro parámetro también interesante de conocer es MaxAuthTries. Este permite especificar el número máximo de intentos de autenticación permitidos. Aunque a nuestro usuario Docker no le hemos añadido ninguna contraseña, si fuera este el caso y no tuviéramos limitado el número de intentos fallidos, podría ser un vector de ataque, ya que se podría intentar acceder por fuerza bruta. Si por ejemplo quisiéramos limitar a 2 intentos de acceso, añadiríamos la siguiente línea.

MaxAuthTries 2

Cuando un usuario alcanza la mitad del número máximo de intentos, empieza a registrarse en el log los intentos fallidos, lo cual, si tuviéramos en nuestro servidor configurado un HIDS, nos podrían llegar alertas sobre esto.

Otro parámetro muy interesante que vamos a configurar en un servicio ssh es LoginGraceTime. Este parámetro, que por defecto está a 2 minutos, indica el tiempo que tardará el servidor en cerrar una conexión abierta si no se ha autenticado. Reducir este valor resulta muy interesante a la hora de evitar ataques de denegación de servicio, ya que si una serie de atacantes intentan hacer login y dejan la conexión abierta durante un tiempo largo pueden llegar a colapsar el servidor. Es por eso que lo aconsejable es tener un valor bajo para este parámetro, en torno a 30 o 45 segundo.

Siguiendo con la configuración, otro parámetro es MaxStartups. Este parámetro indica el número máximo de conexiones no autenticadas que el servidor tendrá abiertas al mismo tiempo. El resto de conexiones serán descartadas hasta que se realice una conexión o pase el tiempo de la directiva anterior debido a que cortará la conexión dejando un “hueco” libre.

Este parámetro puede tener el formato 10:30:60, lo cual indica que cuando alcancemos las 10 conexiones rechazará el resto con una probabilidad de 30/100, que irá aumentando hasta llegar a 60, donde rechazará todas.

Puesto que en esta configuración solo estamos permitiendo la conexión a un único usuario no tiene mucho sentido permitir más de un intento conexión a la vez, por lo que pondremos este valor a 1.

MaxStartups 1

Y puesto que solamente tenemos un usuario, tampoco tiene mucho sentido permitir más de una sesión a la vez, así que pondremos otro parámetro, MaxSessions, a 1.

Como vemos, existen una serie de parámetros que nos permitirían tener un servidor ssh más seguro.

En el siguiente enlace, se puede descargar el proyecto con las modificaciones que se han realizado https://github.com/secdevoops/ssh-server-hardened

Categorías