Abr 292016
 
Artículo Administración de Servidores

La comunicación a través de internet entre una máquina cliente y un servidor supone un problema de seguridad. Normalmente, para ofrecer un determinado servicio, el servidor abre un puerto TCP en su dirección IP pública, y queda a la espera de solicitudes de conexión del cliente. Esto deja al servidor expuesto a ataques procedentes de cualquier otra máquina conectada a internet.

En este artículo se explica una de las posibles soluciones a este problema, mediante la creación de túneles de comunicación SSH.

Utilizando un túnel SSH, se puede configurar el servidor para que sólo abra en su dirección local (localhost, 127.0.0.1) el puerto TCP correspondiente al servicio que ofrece. El cliente se conectará a su vez a un puerto local (el número de puerto puede ser distinto del número de puerto en el que escucha el servidor). El túnel se encarga de encriptar toda la información enviada por el cliente, y enviarla al puerto local del servidor. De la misma forma, el túnel lee toda la la información que escribe el servidor en su puerto local, la encripta y la envía al puerto local en el que lee el cliente.

Vamos a tomar como ejemplo una máquina cliente “cliente” que necesita conectarse a una base de datos MySQL que reside en un servidor “ejemplo.com”. Si no se usa un túnel, el servidor debe permitir el establecimiento de conexiones en su dirección pública ejemplo.com:3306.

Redirección de puerto local (local port forwarding)

En primer lugar, configuramos el servidor para que sólo permita conexiones locales a la dirección localhost:3306.

A continuación, iniciamos una sesión ssh desde el cliente al servidor, en la que solicitamos la creación de un túnel entre el puerto 5000 del cliente al puerto 3306 del servidor, con el siguiente comando:

$ ssh -L 5000:localhost:3306 usuario@ejemplo.com

Una vez establecida la sesión, desde otro terminal del cliente podemos conectarnos a la base de datos del servidor con el comando:

$ mysql -h 127.0.0.1 -P 5000

Los datos que escribe el cliente en el puerto 5000 de su dirección local, son encriptados y enviados por el túnel al puerto 3306 del servidor, y los datos que devuelve el servidor son también encriptados, y enviados al cliente a través del túnel.

Como vemos en este ejemplo, para crear el túnel hemos tenido que establecer primero una sesión interactiva ssh, y después conectarnos desde otro terminal a la base de datos. Para evitar esto se pueden utilizar los flags “-nNT”, de manera que el comando ssh no establezca la sesión interactiva, y simplemente realice la redirección de puertos:

$ ssh -nNT -L 5000:localhost:3306 usuario@ejemplo.com

Creación de túneles persistentes

El túnel ssh creado en el apartado anterior sólo permanece mientras está establecida la sesión ssh en la que se estableció.

Para poder crear un túnel persistente, que no dependa de una sesión interactiva, podemos utilizar el comando “autossh”. autossh se encarga de establecer una sesión ssh en background, y comprueba periódicamente que la sesión permanezca activa. Si por cualquier razon (problema de red o de otro tipo) la sesión ssh finaliza, autossh se encarga de establecer una nueva sesión.

Para crear el túnel con autossh, utilizamos el comando:

$ /usr/lib/autossh/autossh -f -N -L 5000:localhost:3306 usuario@ejemplo.com

Script de creación de túneles ssh en el reinicio

Para que se creen los túneles ssh durante el renicio del servidor, debemos crear un script “/etc/init.d/autossh”, como el script de ejemplo que se puede descargar pulsando aqui.

Este script puede crear múltiples túneles a distintos servidores. La configuración de túneles para cada uno de los servidores se guarda en un fichero “/etc/autossh/<server>”. Por ejemplo:

# cat /etc/autossh/server1 
# Comprueba la conexión cada 10 segundos.
# Tras 3 intentos fallidos, cierra la conexión y la vuelve a establecer
ServerAliveInterval="10"
ServerAliveCountMax="3"
StrictHostKeyChecking="no"
 
LocalUser="root"
IdentityFile="~/.ssh/id_rsa"
 
RemoteUser="usuario"
RemoteHost="server1"
RemotePort="22"
 
# Lista de túneles locales y remotos a establecer
# 
# En este ejemplo:
#    - conecta el puerto remoto 10550 con el puerto local 10050
#    - conecta el puerto local 10051 con el puerto remoto 10051
ForwardPort=(
    "R 127.0.0.1:10550:localhost:10050"
    "L 127.0.0.1:10051:localhost:10051"
)

Redirección de puerto remoto (Remote port forwarding)

Un caso similar que también se puede solucionar mediante un túnel ssh se da cuando desde un máquina cliente conectada a internet queremos acceder a un servicio ofrecido por un servidor “server1” que no tiene conexión directa a internet.

En este caso, podemos utilizar un segundo servidor “server2.com” que sí está conectado a internet, para establecer la comunicación:

  • Desde el servidor “server1”, extablecemos una sesión ssh en la que creamos un túnel remoto:
    ssh -R 5000:localhost:3306 usuario@server2.com

    Como se puede ver, en este caso utilizamos la opción “-R” para establecer un túnel remoto, en lugar de la opción “-L” que establecer un túnel local. Con este comando, el servidor “server2.com” queda a la espera de conexiones en el puerto 9000, y transmite la información que reciba al puerto 3306 del servidor “server1”.

  • Una vez establecido el túnel, desde el cliente podemos establecer una sesión interactiva al servidor “server2.com”, y desde allí conectarnos a la base de datos MySQL del servidor “server1”:
    cliente$ ssh usuario@server2.com
      ...
    server2$ mysql -h 127.0.0.1 -P 5000

Referencias:

SSH Tunnel – Local and Remote Port Forwarding Explained With Examples

 Publicado por en 7:11 am

 Deja un comentario

(requerido)

(requerido)